- ginsh can handle multiple input files which are specified on the command line
[ginac.git] / ginsh / ginsh_lexer.ll
1 /** @file ginsh_lexer.ll
2  *
3  *  Lexical analyzer definition for ginsh.
4  *  This file must be processed with flex.
5  *
6  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23
24 /*
25  *  Definitions
26  */
27
28 %{
29 #include "config.h"
30
31 #include <stdio.h>
32 extern "C" {
33 #include <readline/readline.h>
34 #include <readline/history.h>
35 }
36 #include <map>
37
38 #include <ginac/ginac.h>
39 #include "ginsh.h"
40
41 #include "ginsh_parser.h"
42
43 #define YY_INPUT(buf, result, max_size) (result = ginsh_input(buf, max_size))
44
45 // Table of all used symbols
46 sym_tab syms;
47
48 // lex input function
49 static int ginsh_input(char *buf, int max_size);
50 %}
51
52         /* Abbreviations */
53 D       [0-9]
54 E       [elEL][-+]?{D}+
55 A       [a-zA-Z_]
56 AN      [0-9a-zA-Z_]
57
58
59 /*
60  *  Lexical rules
61  */
62
63 %%
64 [ \t\n]+                /* skip whitespace */
65 \\$                     /* skip line continuations */
66 "#".*                   /* skip comments starting with "#" */
67 ^"!".*                  system(yytext + 1);     /* execute shell command */
68
69                         /* special values */
70 Pi                      yylval = Pi; return T_LITERAL;
71 EulerGamma              yylval = EulerGamma; return T_LITERAL;
72 Catalan                 yylval = Catalan; return T_LITERAL;
73 FAIL                    yylval = *new fail(); return T_LITERAL;
74 I                       yylval = I; return T_NUMBER;
75 Digits                  yylval = (long)Digits; return T_DIGITS;
76
77                         /* keywords */
78 quit|exit               return T_QUIT;
79 print                   return T_PRINT;
80 time                    return T_TIME;
81 xyzzy                   return T_XYZZY;
82 inventory               return T_INVENTORY;
83 look                    return T_LOOK;
84 score                   return T_SCORE;
85
86                         /* comparison */
87 "=="                    return T_EQUAL;
88 "!="                    return T_NOTEQ;
89 "<="                    return T_LESSEQ;
90 ">="                    return T_GREATEREQ;
91
92                         /* last 1..3 expressions */
93 \"                      return T_QUOTE;
94 \"\"                    return T_QUOTE2;
95 \"\"\"                  return T_QUOTE3;
96
97                         /* matrix delimiters */
98 \[\[                    return T_MATRIX_BEGIN;
99 \]\]                    return T_MATRIX_END;
100
101                         /* numbers */
102 {D}+                    |
103 {D}+"."{D}*({E})?       |
104 {D}*"."{D}+({E})?       |
105 {D}+{E}                 yylval = numeric(yytext); return T_NUMBER;
106
107                         /* symbols */
108 {A}{AN}*                {
109                                 if (syms.find(yytext) == syms.end())
110                                         syms[yytext] = *(new symbol(yytext));
111                                 yylval = syms[yytext];
112                                 return T_SYMBOL;
113                         }
114
115                         /* everything else */
116 .                       return *yytext;
117
118 %%
119
120
121 /*
122  *  Routines
123  */
124
125 static int line_length = 0;
126 static char *line_read = NULL;
127 static char *line_ptr;
128
129 // Input function that uses libreadline for interactive input
130 static int ginsh_input(char *buf, int max_size)
131 {
132         int result;
133         if (yy_current_buffer->yy_is_interactive) {
134                 int actual;
135
136                 // Do we need to read a new line?
137                 if (line_length == 0) {
138
139                         // Free old line
140                         if (line_read)
141                                 free(line_read);
142
143                         // Read new line, prompt "> "
144                         line_read = line_ptr = readline("> ");
145
146                         // EOF?
147                         if (!line_read) {
148                                 line_length = 0;
149                                 return YY_NULL;
150                         }
151
152                         // Add non-empty lines to history
153                         line_length = strlen(line_read) + 1;
154                         if (line_length > 1)
155                                 add_history(line_read);
156
157                         // Reappend trailing '\n' which is stripped by readline()
158                         line_read[line_length - 1] = '\n';
159                 }
160
161                 // Copy data to lex buffer
162                 actual = line_length > max_size ? max_size : line_length;
163                 memcpy(buf, line_ptr, actual);
164                 line_length -= actual;
165                 line_ptr += actual;
166                 result = actual;
167
168         } else if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin))
169                 YY_FATAL_ERROR("input in flex scanner failed");
170
171         return result;
172 }
173
174 // List of input files to be processed
175 int num_files = 0;
176 char **file_list = NULL;
177
178 // EOF encountered, connect to next file. If this was the last file,
179 // connect to stdin. If this was stdin, terminate the scanner.
180 int yywrap()
181 {
182         if (yyin == stdin)
183                 return 1;
184
185         fclose(yyin);
186         if (num_files) {
187                 yyin = fopen(*file_list, "r");
188                 if (yyin == NULL) {
189                         cerr << "Can't open " << *file_list << endl;
190                         return 1;
191                 }
192                 num_files--;
193                 file_list++;
194         } else
195                 yyin = stdin;
196         return 0;
197 }