1 /* $NetBSD: scan.l,v 1.1 2017/04/10 02:28:23 phil Exp $ */
2
3 /*
4 * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
5 * Copyright (C) 2016-2017 Philip A. Nelson.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The names Philip A. Nelson and Free Software Foundation may not be
18 * used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /* scan.l: the (f)lex description file for the scanner. */
35
36 %{
37
38 #include "bcdefs.h"
39 #include "bc.h"
40 #include "global.h"
41 #include "proto.h"
42 #include <errno.h>
43
44 /* Using flex, we can ask for a smaller input buffer. With lex, this
45 does nothing! */
46
47 #ifdef SMALL_BUF
48 #undef YY_READ_BUF_SIZE
49 #define YY_READ_BUF_SIZE 512
50 #endif
51
52 /* Force . as last for now. */
53 #define DOT_IS_LAST
54
55 /* We want to define our own yywrap. */
56 #undef yywrap
57 int yywrap (void);
58
59 #if defined(LIBEDIT)
60 /* Support for the BSD libedit with history for
61 nicer input on the interactive part of input. */
62
63 #include <histedit.h>
64
65 /* Have input call the following function. */
66 #undef YY_INPUT
67 #define YY_INPUT(buf,result,max_size) \
68 bcel_input((char *)buf, (yy_size_t *)&result, max_size)
69
70 /* Variables to help interface editline with bc. */
71 static const char *bcel_line = (char *)NULL;
72 static int bcel_len = 0;
73
74 /* bcel_input puts upto MAX characters into BUF with the number put in
75 BUF placed in *RESULT. If the yy input file is the same as
76 stdin, use editline. Otherwise, just read it.
77 */
78
79 static void
bcel_input(char * buf,yy_size_t * result,int max)80 bcel_input (char *buf, yy_size_t *result, int max)
81 {
82 ssize_t rdsize;
83 if (!edit || yyin != stdin)
84 {
85 while ( (rdsize = read( fileno(yyin), buf, max )) < 0 )
86 if (errno != EINTR)
87 {
88 yyerror( "read() in flex scanner failed" );
89 bc_exit (1);
90 }
91 *result = (yy_size_t) rdsize;
92 return;
93 }
94
95 /* Do we need a new string? */
96 if (bcel_len == 0)
97 {
98 bcel_line = el_gets(edit, &bcel_len);
99 if (bcel_line == NULL) {
100 /* end of file */
101 *result = 0;
102 bcel_len = 0;
103 return;
104 }
105 if (bcel_len != 0)
106 history (hist, &histev, H_ENTER, bcel_line);
107 fflush (stdout);
108 }
109
110 if (bcel_len <= max)
111 {
112 strncpy (buf, bcel_line, bcel_len);
113 *result = bcel_len;
114 bcel_len = 0;
115 }
116 else
117 {
118 strncpy (buf, bcel_line, max);
119 *result = max;
120 bcel_line += max;
121 bcel_len -= max;
122 }
123 }
124 #endif
125
126 #ifdef READLINE
127 /* Support for the readline and history libraries. This allows
128 nicer input on the interactive part of input. */
129
130 /* Have input call the following function. */
131 #undef YY_INPUT
132 #define YY_INPUT(buf,result,max_size) \
133 rl_input((char *)buf, &result, max_size)
134
135 /* Variables to help interface readline with bc. */
136 static char *rl_line = (char *)NULL;
137 static char *rl_start = (char *)NULL;
138 static int rl_len = 0;
139
140 /* Definitions for readline access. */
141 extern FILE *rl_instream;
142
143 /* rl_input puts upto MAX characters into BUF with the number put in
144 BUF placed in *RESULT. If the yy input file is the same as
145 rl_instream (stdin), use readline. Otherwise, just read it.
146 */
147
148 static void
rl_input(char * buf,int * result,int max)149 rl_input (char *buf, int *result, int max)
150 {
151 if (yyin != rl_instream)
152 {
153 while ( (*result = read( fileno(yyin), buf, max )) < 0 )
154 if (errno != EINTR)
155 {
156 yyerror( "read() in flex scanner failed" );
157 bc_exit (1);
158 }
159 return;
160 }
161
162 /* Do we need a new string? */
163 if (rl_len == 0)
164 {
165 if (rl_start)
166 free(rl_start);
167 rl_start = readline ("");
168 if (rl_start == NULL) {
169 /* end of file */
170 *result = 0;
171 rl_len = 0;
172 return;
173 }
174 rl_line = rl_start;
175 rl_len = strlen (rl_line)+1;
176 if (rl_len != 1)
177 add_history (rl_line);
178 rl_line[rl_len-1] = '\n';
179 fflush (stdout);
180 }
181
182 if (rl_len <= max)
183 {
184 strncpy (buf, rl_line, rl_len);
185 *result = rl_len;
186 rl_len = 0;
187 }
188 else
189 {
190 strncpy (buf, rl_line, max);
191 *result = max;
192 rl_line += max;
193 rl_len -= max;
194 }
195 }
196 #endif
197
198 #if !defined(READLINE) && !defined(LIBEDIT)
199
200 /* MINIX returns from read with < 0 if SIGINT is encountered.
201 In flex, we can redefine YY_INPUT to the following. In lex, this
202 does nothing! */
203 #undef YY_INPUT
204 #define YY_INPUT(buf,result,max_size) \
205 while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
206 if (errno != EINTR) \
207 YY_FATAL_ERROR( "read() in flex scanner failed" );
208 #endif
209
210 %}
211 DIGIT [0-9A-Z]
212 LETTER [a-z]
213 %s slcomment
214 %%
215 "#" {
216 if (!std_only)
217 BEGIN(slcomment);
218 else
219 yyerror ("illegal character: #");
220 }
221 <slcomment>[^\n]* { BEGIN(INITIAL); }
222 <slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
223 define return(Define);
224 break return(Break);
225 quit return(Quit);
226 length return(Length);
227 return return(Return);
228 for return(For);
229 if return(If);
230 while return(While);
231 sqrt return(Sqrt);
232 scale return(Scale);
233 ibase return(Ibase);
234 obase return(Obase);
235 auto return(Auto);
236 else return(Else);
237 read return(Read);
238 random return(Random);
239 halt return(Halt);
240 last return(Last);
241 void return(Void);
242 history {
243 #if defined(READLINE) || defined(LIBEDIT)
244 return(HistoryVar);
245 #else
246 yylval.s_value = strcopyof(yytext); return(NAME);
247 #endif
248 }
249
250 warranty return(Warranty);
251 continue return(Continue);
252 print return(Print);
253 limits return(Limits);
254 "." {
255 #ifdef DOT_IS_LAST
256 return(Last);
257 #else
258 yyerror ("illegal character: %s",yytext);
259 #endif
260 }
261 "+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0];
262 return((int)yytext[0]); }
263 && { return(AND); }
264 \|\| { return(OR); }
265 "!" { return(NOT); }
266 "*"|"/"|"%"|"&" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
267 "="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
268 =\+|=-|=\*|=\/|=%|=\^ {
269 #ifdef OLD_EQ_OP
270 char warn_save;
271 warn_save = warn_not_std;
272 warn_not_std = TRUE;
273 ct_warn ("Old fashioned =<op>");
274 warn_not_std = warn_save;
275 yylval.c_value = yytext[1];
276 #else
277 yylval.c_value = '=';
278 yyless (1);
279 #endif
280 return(ASSIGN_OP);
281 }
282 ==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
283 \+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
284 "\n" { line_no++; return(ENDOFLINE); }
285 \\\n { line_no++; /* ignore a "quoted" newline */ }
286 [ \t]+ { /* ignore spaces and tabs */ }
287 "/*" {
288 int c;
289
290 for (;;)
291 {
292 while ( ((c=input()) != '*') && (c != EOF))
293 /* eat it */
294 if (c == '\n') line_no++;
295 if (c == '*')
296 {
297 while ( (c=input()) == '*') /* eat it*/;
298 if (c == '/') break; /* at end of comment */
299 if (c == '\n') line_no++;
300 }
301 if (c == EOF)
302 {
303 fprintf (stderr,"EOF encountered in a comment.\n");
304 break;
305 }
306 }
307 }
308 [a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
309 \"[^\"]*\" {
310 const char *look;
311 int count = 0;
312 yylval.s_value = strcopyof(yytext);
313 for (look = yytext; *look != 0; look++)
314 {
315 if (*look == '\n') line_no++;
316 if (*look == '"') count++;
317 }
318 if (count != 2) yyerror ("NUL character in string.");
319 return(STRING);
320 }
321 {DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
322 char *src, *dst;
323 int len;
324 /* remove a trailing decimal point. */
325 len = strlen(yytext);
326 if (yytext[len-1] == '.')
327 yytext[len-1] = 0;
328 /* remove leading zeros. */
329 src = yytext;
330 dst = yytext;
331 while (*src == '0') src++;
332 if (*src == 0) src--;
333 /* Copy strings removing the newlines. */
334 while (*src != 0)
335 {
336 if (*src == '\\')
337 {
338 src++; src++;
339 line_no++;
340 }
341 if (*src == ',')
342 {
343 src++;
344 ct_warn("Commas in numbers");
345 }
346 else
347 *dst++ = *src++;
348 }
349 *dst = 0;
350 yylval.s_value = strcopyof(yytext);
351 return(NUMBER);
352 }
353 . {
354 if (yytext[0] < ' ')
355 yyerror ("illegal character: ^%c",yytext[0] + '@');
356 else
357 if (yytext[0] > '~')
358 yyerror ("illegal character: \\%03o", (int) yytext[0]);
359 else
360 yyerror ("illegal character: %s",yytext);
361 }
362 %%
363
364
365
366 /* This is the way to get multiple files input into lex. */
367
368 int
369 yywrap(void)
370 {
371 if (!open_new_file ()) return (1); /* EOF on standard in. */
372 return (0); /* We have more input. */
373 yyunput(0,NULL); /* Make sure the compiler think yyunput is used. */
374 }
375