c0af39acf7401d473a86610a7e38d615c26a7274
[scilab.git] / scilab / modules / ast / src / cpp / parse / parser.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2008-2008 - INRIA - Bruno JOFRET
4  *  Copyright (C) 2010-2010 - DIGITEO - Bruno JOFRET
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  * === LICENSE_END ===
15  *
16  */
17
18 #include <fstream>
19 #include <string>
20 #include <string.h>
21 #include "parser.hxx"
22 #include "parser_private.hxx"
23
24 #ifdef _MSC_VER
25 #include "windows.h"
26 #include "charEncoding.h"
27 #include "sci_malloc.h"
28 #endif
29
30 extern "C"
31 {
32 #include "sci_tmpdir.h"
33 #include "Scierror.h"
34 #include "localization.h"
35 #include "os_string.h"
36 #ifdef __APPLE__
37 #include "PATH_MAX.h"
38 #endif
39 #include "os_wfopen.h"
40 }
41
42 extern FILE*    yyin;
43 extern int      yyparse();
44 extern int      yydebug;
45 extern int      yylex_destroy();
46
47 void Parser::cleanup()
48 {
49     yylex_destroy();
50 }
51
52 void Parser::parseFile(const std::wstring& fileName, const std::wstring& progName)
53 {
54     // Calling Parse state machine in C with global values
55     // Must be locked to avoid concurrent access
56     // FIXME : LOCK
57     if (getParseTrace() == true)
58     {
59         ParserSingleInstance::enableParseTrace();
60     }
61     else
62     {
63         ParserSingleInstance::disableParseTrace();
64     }
65
66     try
67     {
68         ParserSingleInstance::parseFile(fileName, progName);
69     }
70     catch (const ast::InternalError& ie)
71     {
72         ParserSingleInstance::setTree(nullptr);
73         ParserSingleInstance::setExitStatus(Parser::Failed);
74     }
75
76     this->setExitStatus(ParserSingleInstance::getExitStatus());
77     this->setControlStatus(ParserSingleInstance::getControlStatus());
78     if (getExitStatus() == Parser::Succeded)
79     {
80         this->setTree(ParserSingleInstance::getTree());
81     }
82     else
83     {
84         this->setErrorMessage(ParserSingleInstance::getErrorMessage());
85     }
86
87     if (getExitStatus() != Parser::Succeded)
88     {
89         delete ParserSingleInstance::getTree();
90         ParserSingleInstance::setTree(nullptr);
91     }
92
93     // FIXME : UNLOCK
94 }
95
96
97 /** \brief parse the given file name */
98 void ParserSingleInstance::parseFile(const std::wstring& fileName, const std::wstring& progName)
99 {
100     yylloc.first_line = yylloc.last_line = 1;
101     yylloc.first_column = yylloc.last_column = 1;
102 #ifdef _MSC_VER
103     yyin = os_wfopen(fileName.c_str(), L"r");
104 #else
105     char* pstTemp = wide_string_to_UTF8(fileName.c_str());
106     yyin = fopen(pstTemp, "r");
107     FREE(pstTemp);
108 #endif
109
110     if (!yyin)
111     {
112         wchar_t szError[bsiz];
113         os_swprintf(szError, bsiz, _W("%ls: Cannot open file %ls.\n").c_str(), L"parser", fileName.c_str());
114         throw ast::InternalError(szError);
115     }
116
117
118     ParserSingleInstance::disableStrictMode();
119     //  Parser::getInstance()->enableStrictMode();
120     ParserSingleInstance::setFileName(fileName);
121     ParserSingleInstance::setProgName(progName);
122
123     ParserSingleInstance::setTree(nullptr);
124     ParserSingleInstance::setExitStatus(Parser::Succeded);
125     ParserSingleInstance::resetControlStatus();
126     ParserSingleInstance::resetErrorMessage();
127     yyparse();
128     fclose(yyin);
129 }
130
131 void Parser::parse(const char *command)
132 {
133     // Calling Parse state machine in C with global values
134     // Must be locked to avoid concurrent access
135     // FIXME : LOCK
136     if (getParseTrace() == true)
137     {
138         ParserSingleInstance::enableParseTrace();
139     }
140     else
141     {
142         ParserSingleInstance::disableParseTrace();
143     }
144
145     ParserSingleInstance::parse(command);
146     this->setExitStatus(ParserSingleInstance::getExitStatus());
147     this->setControlStatus(ParserSingleInstance::getControlStatus());
148     if (getExitStatus() == Parser::Succeded)
149     {
150         this->setTree(ParserSingleInstance::getTree());
151     }
152     else
153     {
154         this->setErrorMessage(ParserSingleInstance::getErrorMessage());
155     }
156
157     if (getControlStatus() == AllControlClosed && get_last_token() != YYEOF)
158     {
159         //set parser last token to EOF
160         scan_throw(YYEOF);
161     }
162
163     if (getExitStatus() != Parser::Succeded)
164     {
165         delete ParserSingleInstance::getTree();
166         ParserSingleInstance::setTree(nullptr);
167     }
168
169     // FIXME : UNLOCK
170 }
171
172 void Parser::parse(const wchar_t *command)
173 {
174     char* pstCommand = wide_string_to_UTF8(command);
175     parse(pstCommand);
176     FREE(pstCommand);
177 }
178
179 /** \brief parse the given file command */
180 void ParserSingleInstance::parse(const char *command)
181 {
182     size_t len = strlen(command);
183
184     yylloc.first_line = yylloc.last_line = 1;
185     yylloc.first_column = yylloc.last_column = 1;
186 #ifdef _MSC_VER
187     char szFile[MAX_PATH];
188     char* pstTmpDIr = getTMPDIR();
189     os_sprintf(szFile, "%s\\%s", pstTmpDIr, "command.temp");
190     FREE(pstTmpDIr);
191     if (fileLocker)
192     {
193         fclose(fileLocker);
194         fileLocker = nullptr;
195     }
196
197     errno_t err;
198     err = fopen_s(&yyin, szFile, "w");
199     if (err)
200     {
201         ParserSingleInstance::setExitStatus(Parser::Failed);
202         ParserSingleInstance::resetErrorMessage();
203         wchar_t szError[bsiz];
204         wchar_t* wszFile = to_wide_string(szFile);
205         os_swprintf(szError, bsiz, _W("%ls: Cannot open file %ls.\n").c_str(), L"parser", wszFile);
206         FREE(wszFile);
207         appendErrorMessage(szError);
208         return;
209     }
210
211     fwrite(command, sizeof(char), len, yyin);
212     fclose(yyin);
213     fopen_s(&yyin, szFile, "r");
214 #endif
215
216 #ifdef __APPLE__
217     char szFile[PATH_MAX];
218     char* pstTmpDIr = "/tmp";
219     sprintf(szFile, "%s/%s", getTMPDIR(), "command.temp");
220     //FREE(pstTmpDIr);
221     if (fileLocker)
222     {
223         fclose(fileLocker);
224         fileLocker = nullptr;
225     }
226     yyin = fopen(szFile, "w");
227     fwrite(command, 1, len, yyin);
228     fclose(yyin);
229     yyin = fopen(szFile, "r");
230 #endif
231
232
233 #ifndef _MSC_VER
234 #ifndef __APPLE__
235     yyin = fmemopen((void*)command, len, "r");
236 #endif
237 #endif
238
239     ParserSingleInstance::disableStrictMode();
240     ParserSingleInstance::setFileName(L"prompt");
241     ParserSingleInstance::setTree(nullptr);
242     ParserSingleInstance::setExitStatus(Parser::Succeded);
243     ParserSingleInstance::resetControlStatus();
244     ParserSingleInstance::resetErrorMessage();
245
246     yyparse();
247
248     fclose(yyin);
249 #ifdef _MSC_VER
250     DeleteFileA(szFile);
251 #endif
252
253 #ifdef _MSC_VER
254     //reopen a file to prevents max file opened.
255     fopen_s(&fileLocker, szFile, "w");
256 #endif
257 #ifdef __APPLE__
258     fileLocker = fopen(szFile, "w");
259 #endif
260 }
261
262 /** \brief put the asked line in codeLine */
263 char *ParserSingleInstance::getCodeLine(int line, char **codeLine)
264 {
265     int i = 0;
266
267     rewind(yyin);
268     /*
269     ** WARNING : *codeLine will be allocated by getline
270     ** so it must be manually freed !
271     */
272     for (i = 1 ; i <= line ; ++i)
273     {
274         fgets(*codeLine, 4096, yyin);
275     }
276     return *codeLine;
277 }
278
279 std::wstring& ParserSingleInstance::getErrorMessage(void)
280 {
281     return _error_message;
282 }
283
284 void ParserSingleInstance::appendErrorMessage(const std::wstring& message)
285 {
286     _error_message += message;
287 }
288
289 /** \brief enable Bison trace mode */
290 void ParserSingleInstance::enableParseTrace(void)
291 {
292     yydebug = 1;
293 }
294
295 /** \brief disable Bison trace mode */
296 void ParserSingleInstance::disableParseTrace(void)
297 {
298     yydebug = 0;
299 }
300
301 void Parser::releaseTmpFile()
302 {
303     ParserSingleInstance::releaseTmpFile();
304 }
305
306 void ParserSingleInstance::releaseTmpFile()
307 {
308     if (fileLocker)
309     {
310         //fclose(fileLocker);
311         //fileLocker = nullptr;
312     }
313 }
314
315 std::wstring ParserSingleInstance::_file_name;
316 std::wstring ParserSingleInstance::_prog_name;
317 std::wstring ParserSingleInstance::_error_message;
318 bool ParserSingleInstance::_strict_mode = false;
319 bool ParserSingleInstance::_stop_on_first_error = false;
320 ast::Exp* ParserSingleInstance::_the_program = nullptr;
321 Parser::ParserStatus ParserSingleInstance::_exit_status = Parser::Succeded;
322 std::list<Parser::ControlStatus> ParserSingleInstance::_control_status;
323 FILE* ParserSingleInstance::fileLocker = nullptr;
324