]> www.ginac.de Git - ginac.git/blob - ginsh/ginsh_lexer.lpp
[BUGFIX] Fix crash in parser.
[ginac.git] / ginsh / ginsh_lexer.lpp
1 /** @file ginsh_lexer.lpp
2  *
3  *  Lexical analyzer definition for ginsh.
4  *  This file must be processed with flex. */
5
6 /*
7  *  GiNaC Copyright (C) 1999-2020 Johannes Gutenberg University Mainz, Germany
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23
24
25 /*
26  *  Definitions
27  */
28
29 %option nounput
30
31 %pointer
32
33 %{
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "ginsh.h"
39 #include "ginsh_parser.hpp"
40
41 using namespace std;
42 using namespace GiNaC;
43
44 #define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size))
45
46 // Table of all used symbols
47 sym_tab syms;
48
49 // Type of symbols to generate (real or complex)
50 unsigned symboltype = domain::complex;
51
52 // lex input function
53 static int ginsh_input(char *buf, int max_size);
54 %}
55
56         /* Abbreviations */
57 D       [0-9]
58 E       [elEL][-+]?{D}+
59 A       [a-zA-Z_]
60 AN      [0-9a-zA-Z_]
61
62
63 /*
64  *  Lexical rules
65  */
66
67 %%
68 [ \t\n]+                /* skip whitespace */
69 \\$                     /* skip line continuations */
70 "//".*                  /* skip comments starting with "//" */
71 ^"#".*                  /* skip lines starting with "#" */
72 ^"!".*                  system(yytext + 1);     /* execute shell command */
73
74                         /* special values */
75 Pi                      yylval = Pi; return T_LITERAL;
76 Euler                   yylval = Euler; return T_LITERAL;
77 Catalan                 yylval = Catalan; return T_LITERAL;
78 FAIL                    yylval = *new fail(); return T_LITERAL;
79 I                       yylval = I; return T_NUMBER;
80 Digits                  yylval = (long)Digits; return T_DIGITS;
81
82                         /* keywords */
83 quit|exit               return T_QUIT;
84 warranty                return T_WARRANTY;
85 print                   return T_PRINT;
86 iprint                  return T_IPRINT;
87 print_latex             return T_PRINTLATEX;
88 print_csrc              return T_PRINTCSRC;
89 time                    return T_TIME;
90 xyzzy                   return T_XYZZY;
91 inventory               return T_INVENTORY;
92 look                    return T_LOOK;
93 score                   return T_SCORE;
94 complex_symbols return T_COMPLEX_SYMBOLS;
95 real_symbols    return T_REAL_SYMBOLS;
96
97                         /* comparison */
98 "=="                    return T_EQUAL;
99 "!="                    return T_NOTEQ;
100 "<="                    return T_LESSEQ;
101 ">="                    return T_GREATEREQ;
102
103                         /* last 1..3 expressions */
104 \%                      return T_QUOTE;
105 \%\%                    return T_QUOTE2;
106 \%\%\%                  return T_QUOTE3;
107
108                         /* numbers */
109 {D}+                    |
110 "#"{D}+"R"{AN}+         |
111 "#b"([01])+             |
112 "#o"[0-7]+              |
113 "#x"[0-9a-fA-F]+        |
114 {D}+"."{D}*({E})?       |
115 {D}*"."{D}+({E})?       |
116 {D}+{E}                 yylval = numeric(yytext); return T_NUMBER;
117
118                         /* symbols */
119 {A}{AN}*                {
120                                 sym_tab::const_iterator i = syms.find(yytext);
121                                 if (i == syms.end()) {
122                                         if (symboltype == domain::complex) {
123                                                 symbol tmp(yytext);
124                                                 syms[yytext] = tmp;
125                                                 yylval = tmp;
126                                         } else {
127                                                 realsymbol tmp(yytext);
128                                                 syms[yytext] = tmp;
129                                                 yylval = tmp;
130                                         }
131                                 } else
132                                         yylval = i->second;
133                                 return T_SYMBOL;
134                         }
135
136                         /* wildcards */
137 \${D}+                  yylval = wild(atoi(yytext + 1)); return T_LITERAL;
138
139                         /* everything else */
140 .                       return *yytext;
141
142 %%
143
144
145 /*
146  *  Routines
147  */
148
149 static int line_length = 0;
150 static char *line_read = nullptr;
151 static char *line_ptr;
152
153 // Input function that uses libreadline for interactive input
154 static int ginsh_input(char *buf, int max_size)
155 {
156         int result;
157 #if defined(YY_CURRENT_BUFFER)
158         if (YY_CURRENT_BUFFER->yy_is_interactive) {
159 #else
160         if (yy_current_buffer->yy_is_interactive) {
161 #endif
162 #ifdef HAVE_LIBREADLINE
163                 // Do we need to read a new line?
164                 int actual;
165                 if (line_length == 0) {
166
167                         // Free old line
168                         if (line_read)
169                                 free(line_read);
170
171                         // Read new line, prompt "> "
172                         line_read = line_ptr = readline("> ");
173
174                         // EOF?
175                         if (!line_read) {
176                                 line_length = 0;
177                                 return YY_NULL;
178                         }
179
180                         // Add non-empty lines to history
181                         line_length = strlen(line_read) + 1;
182                         if (line_length > 1)
183                                 add_history(line_read);
184
185                         // Reappend trailing '\n' which is stripped by readline()
186                         line_read[line_length - 1] = '\n';
187                 }
188
189                 // Copy data to lex buffer
190                 actual = line_length > max_size ? max_size : line_length;
191                 memcpy(buf, line_ptr, actual);
192                 line_length -= actual;
193                 line_ptr += actual;
194                 result = actual;
195 #else
196                 printf("> "); fflush(stdout);
197                 int c = '*', n;
198                 for (n = 0; n < max_size && (c = getc(yyin)) != EOF && c != '\n'; ++n)
199                         buf[n] = (char)c;
200                 if (c == '\n')
201                         buf[n++] = (char)c;
202                 if (c == EOF && ferror(yyin))
203                         YY_FATAL_ERROR("input in flex scanner failed");
204                 result = n;
205 #endif
206         } else if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin))
207                 YY_FATAL_ERROR("input in flex scanner failed");
208
209         return result;
210 }
211
212 // List of input files to be processed
213 int num_files = 0;
214 char **file_list = nullptr;
215
216 // EOF encountered, connect to next file. If this was the last file,
217 // connect to stdin. If this was stdin, terminate the scanner.
218 int yywrap()
219 {
220         if (yyin == stdin)
221                 return 1;
222
223         fclose(yyin);
224         if (num_files) {
225                 yyin = fopen(*file_list, "r");
226                 if (yyin == nullptr) {
227                         cerr << "Can't open " << *file_list << endl;
228                         return 1;
229                 }
230                 num_files--;
231                 file_list++;
232         } else
233                 yyin = stdin;
234         return 0;
235 }