xref: /netbsd-src/external/bsd/bc/dist/scan.l (revision ed857e95db3fec367bb6764523110eb0ac99cb49)
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