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