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