9be6c35401fa6189ea5badabcd546dc7f8bfb736
[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 bool Parser::stopOnFirstError(void)
180 {
181     return ParserSingleInstance::stopOnFirstError();
182 }
183 void Parser::enableStopOnFirstError(void)
184 {
185     ParserSingleInstance::enableStopOnFirstError();
186 }
187 void Parser::disableStopOnFirstError(void)
188 {
189     ParserSingleInstance::disableStopOnFirstError();
190 }
191
192 /** \brief parse the given file command */
193 void ParserSingleInstance::parse(const char *command)
194 {
195     size_t len = strlen(command);
196
197     yylloc.first_line = yylloc.last_line = 1;
198     yylloc.first_column = yylloc.last_column = 1;
199 #ifdef _MSC_VER
200     char szFile[MAX_PATH];
201     char* pstTmpDIr = getTMPDIR();
202     os_sprintf(szFile, "%s\\%s", pstTmpDIr, "command.temp");
203     FREE(pstTmpDIr);
204     if (fileLocker)
205     {
206         fclose(fileLocker);
207         fileLocker = nullptr;
208     }
209
210     errno_t err;
211     err = fopen_s(&yyin, szFile, "w");
212     if (err)
213     {
214         ParserSingleInstance::setExitStatus(Parser::Failed);
215         ParserSingleInstance::resetErrorMessage();
216         wchar_t szError[bsiz];
217         wchar_t* wszFile = to_wide_string(szFile);
218         os_swprintf(szError, bsiz, _W("%ls: Cannot open file %ls.\n").c_str(), L"parser", wszFile);
219         FREE(wszFile);
220         appendErrorMessage(szError);
221         return;
222     }
223
224     fwrite(command, sizeof(char), len, yyin);
225     fclose(yyin);
226     fopen_s(&yyin, szFile, "r");
227 #endif
228
229 #ifdef __APPLE__
230     char szFile[PATH_MAX];
231     char* pstTmpDIr = "/tmp";
232     sprintf(szFile, "%s/%s", getTMPDIR(), "command.temp");
233     //FREE(pstTmpDIr);
234     if (fileLocker)
235     {
236         fclose(fileLocker);
237         fileLocker = nullptr;
238     }
239     yyin = fopen(szFile, "w");
240     fwrite(command, 1, len, yyin);
241     fclose(yyin);
242     yyin = fopen(szFile, "r");
243 #endif
244
245
246 #ifndef _MSC_VER
247 #ifndef __APPLE__
248     yyin = fmemopen((void*)command, len, "r");
249 #endif
250 #endif
251
252     ParserSingleInstance::disableStrictMode();
253     ParserSingleInstance::setFileName(L"prompt");
254     ParserSingleInstance::setTree(nullptr);
255     ParserSingleInstance::setExitStatus(Parser::Succeded);
256     ParserSingleInstance::resetControlStatus();
257     ParserSingleInstance::resetErrorMessage();
258
259     yyparse();
260
261     fclose(yyin);
262 #ifdef _MSC_VER
263     DeleteFileA(szFile);
264 #endif
265
266 #ifdef _MSC_VER
267     //reopen a file to prevents max file opened.
268     fopen_s(&fileLocker, szFile, "w");
269 #endif
270 #ifdef __APPLE__
271     fileLocker = fopen(szFile, "w");
272 #endif
273 }
274
275 /** \brief put the asked line in codeLine */
276 char *ParserSingleInstance::getCodeLine(int line, char **codeLine)
277 {
278     int i = 0;
279
280     rewind(yyin);
281     /*
282     ** WARNING : *codeLine will be allocated by getline
283     ** so it must be manually freed !
284     */
285     for (i = 1 ; i <= line ; ++i)
286     {
287         fgets(*codeLine, 4096, yyin);
288     }
289     return *codeLine;
290 }
291
292 std::wstring& ParserSingleInstance::getErrorMessage(void)
293 {
294     return _error_message;
295 }
296
297 void ParserSingleInstance::appendErrorMessage(const std::wstring& message)
298 {
299     if (ParserSingleInstance::stopOnFirstError() && _error_message.empty() == false)
300     {
301         return;
302     }
303
304     _error_message += message;
305 }
306
307 /** \brief enable Bison trace mode */
308 void ParserSingleInstance::enableParseTrace(void)
309 {
310     yydebug = 1;
311 }
312
313 /** \brief disable Bison trace mode */
314 void ParserSingleInstance::disableParseTrace(void)
315 {
316     yydebug = 0;
317 }
318
319 void Parser::releaseTmpFile()
320 {
321     ParserSingleInstance::releaseTmpFile();
322 }
323
324 void ParserSingleInstance::releaseTmpFile()
325 {
326     if (fileLocker)
327     {
328         //fclose(fileLocker);
329         //fileLocker = nullptr;
330     }
331 }
332
333 std::wstring ParserSingleInstance::_file_name;
334 std::wstring ParserSingleInstance::_prog_name;
335 std::wstring ParserSingleInstance::_error_message;
336 bool ParserSingleInstance::_strict_mode = false;
337 bool ParserSingleInstance::_stop_on_first_error = true;
338 ast::Exp* ParserSingleInstance::_the_program = nullptr;
339 Parser::ParserStatus ParserSingleInstance::_exit_status = Parser::Succeded;
340 std::list<Parser::ControlStatus> ParserSingleInstance::_control_status;
341 FILE* ParserSingleInstance::fileLocker = nullptr;
342