Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / bc / bc / scan.l
1 %{
2 /* $FreeBSD: src/contrib/bc/bc/scan.l,v 1.4.2.1 2001/03/04 09:34:54 kris Exp $ */
3 /* scan.l: the (f)lex description file for the scanner. */
4
5 /*  This file is part of GNU bc.
6     Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
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; see the file COPYING.  If not, write to
20       The Free Software Foundation, Inc.
21       59 Temple Place, Suite 330
22       Boston, MA 02111 USA
23
24     You may contact the author by:
25        e-mail:  philnelson@acm.org
26       us-mail:  Philip A. Nelson
27                 Computer Science Department, 9062
28                 Western Washington University
29                 Bellingham, WA 98226-9062
30        
31 *************************************************************************/
32
33 #include "bcdefs.h"
34 #include "bc.h"
35 #include "global.h"
36 #include "proto.h"
37 #include <errno.h>
38
39 /* Using flex, we can ask for a smaller input buffer.  With lex, this
40    does nothing! */
41
42 #ifdef SMALL_BUF
43 #undef YY_READ_BUF_SIZE
44 #define YY_READ_BUF_SIZE 512
45 #endif
46
47 /* Force . as last for now. */
48 #define DOT_IS_LAST
49
50 /* We want to define our own yywrap. */
51 #undef yywrap
52 _PROTOTYPE(int yywrap, (void));
53
54 #if defined(LIBEDIT)
55 /* Support for the BSD libedit with history for
56    nicer input on the interactive part of input. */
57
58 #include <histedit.h>
59
60 /* Have input call the following function. */
61 #undef  YY_INPUT
62 #define YY_INPUT(buf,result,max_size) \
63                 bcel_input((char *)buf, &result, max_size)
64
65 /* Variables to help interface editline with bc. */
66 static const char *bcel_line = (char *)NULL;
67 static int   bcel_len = 0;
68
69
70 /* Required to get rid of that ugly ? default prompt! */
71 char *
72 null_prompt (EditLine *el)
73 {
74   return "";
75 }
76
77
78 /* bcel_input puts upto MAX characters into BUF with the number put in
79    BUF placed in *RESULT.  If the yy input file is the same as
80    stdin, use editline.  Otherwise, just read it.
81 */
82
83 static void
84 bcel_input (buf, result, max)
85         char *buf;
86         int  *result;
87         int   max;
88 {
89   if (!edit || yyin != stdin)
90     {
91       while ( (*result = read( fileno(yyin), buf, max )) < 0 )
92         if (errno != EINTR)
93           {
94             yyerror( "read() in flex scanner failed" );
95             exit (1);
96           }
97       return;
98     }
99
100   /* Do we need a new string? */
101   if (bcel_len == 0)
102     {
103       bcel_line = el_gets(edit, &bcel_len);
104       if (bcel_line == NULL) {
105         /* end of file */
106         *result = 0;
107         bcel_len = 0;
108         return;
109       }
110       if (bcel_len != 0)
111         history (hist, &histev, H_ENTER, bcel_line); 
112       fflush (stdout);
113     }
114
115   if (bcel_len <= max)
116     {
117       strncpy (buf, bcel_line, bcel_len);
118       *result = bcel_len;
119       bcel_len = 0;
120     }
121   else
122     {
123       strncpy (buf, bcel_line, max);
124       *result = max;
125       bcel_line += max;
126       bcel_len -= max;
127     }
128 }
129 #endif
130
131 #ifdef READLINE
132 /* Support for the readline and history libraries.  This allows
133    nicer input on the interactive part of input. */
134
135 /* Have input call the following function. */
136 #undef  YY_INPUT
137 #define YY_INPUT(buf,result,max_size) \
138                 rl_input((char *)buf, &result, max_size)
139
140 /* Variables to help interface readline with bc. */
141 static char *rl_line = (char *)NULL;
142 static char *rl_start = (char *)NULL;
143 static int   rl_len = 0;
144
145 /* Definitions for readline access. */
146 extern FILE *rl_instream;
147 _PROTOTYPE(char *readline, (char *));
148
149 /* rl_input puts upto MAX characters into BUF with the number put in
150    BUF placed in *RESULT.  If the yy input file is the same as
151    rl_instream (stdin), use readline.  Otherwise, just read it.
152 */
153
154 static void
155 rl_input (buf, result, max)
156         char *buf;
157         int  *result;
158         int   max;
159 {
160   if (yyin != rl_instream)
161     {
162       while ( (*result = read( fileno(yyin), buf, max )) < 0 )
163         if (errno != EINTR)
164           {
165             yyerror( "read() in flex scanner failed" );
166             exit (1);
167           }
168       return;
169     }
170
171   /* Do we need a new string? */
172   if (rl_len == 0)
173     {
174       if (rl_start)
175         free(rl_start);
176       rl_start = readline ("");
177       if (rl_start == NULL) {
178         /* end of file */
179         *result = 0;
180         rl_len = 0;
181         return;
182       }
183       rl_line = rl_start;
184       rl_len = strlen (rl_line)+1;
185       if (rl_len != 1)
186         add_history (rl_line); 
187       rl_line[rl_len-1] = '\n';
188       fflush (stdout);
189     }
190
191   if (rl_len <= max)
192     {
193       strncpy (buf, rl_line, rl_len);
194       *result = rl_len;
195       rl_len = 0;
196     }
197   else
198     {
199       strncpy (buf, rl_line, max);
200       *result = max;
201       rl_line += max;
202       rl_len -= max;
203     }
204 }
205 #endif
206
207 #if !defined(READLINE) && !defined(LIBEDIT)
208
209 /* MINIX returns from read with < 0 if SIGINT is  encountered.
210    In flex, we can redefine YY_INPUT to the following.  In lex, this
211    does nothing! */
212 #undef  YY_INPUT
213 #define YY_INPUT(buf,result,max_size) \
214         while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
215             if (errno != EINTR) \
216                 YY_FATAL_ERROR( "read() in flex scanner failed" );
217 #endif
218
219 %}
220 DIGIT [0-9A-F]
221 LETTER [a-z]
222 %s slcomment
223 %%
224 "#"             {
225                   if (!std_only)
226                     BEGIN(slcomment);
227                   else
228                     yyerror ("illegal character: #");
229                 }
230 <slcomment>[^\n]* { BEGIN(INITIAL); }
231 <slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
232 define return(Define);
233 break  return(Break);
234 quit   return(Quit);
235 length return(Length);
236 return return(Return);
237 for    return(For);
238 if     return(If);
239 while  return(While);
240 sqrt   return(Sqrt);
241 scale  return(Scale);
242 ibase  return(Ibase);
243 obase  return(Obase);
244 auto   return(Auto);
245 else   return(Else);
246 read   return(Read);
247 halt   return(Halt);
248 last   return(Last);
249 history {
250 #if defined(READLINE) || defined(LIBEDIT)
251           return(HistoryVar);
252 #else
253           yylval.s_value = strcopyof(yytext); return(NAME);
254 #endif
255         }
256
257 warranty return(Warranty);
258 continue return(Continue);
259 print  return(Print);
260 limits return(Limits);
261 "." {
262 #ifdef DOT_IS_LAST
263        return(Last);
264 #else
265        yyerror ("illegal character: %s",yytext);
266 #endif
267     }
268 "+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; 
269                                               return((int)yytext[0]); }
270 && { return(AND); }
271 \|\| { return(OR); }
272 "!" { return(NOT); }
273 "*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
274 "="|\+=|-=|\*=|\/=|%=|\^=  { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
275 =\+|=-|=\*|=\/|=%|=\^  { 
276 #ifdef OLD_EQ_OP
277                          char warn_save;
278                          warn_save = warn_not_std;
279                          warn_not_std = TRUE;
280                          warn ("Old fashioned =<op>");
281                          warn_not_std = warn_save;
282                          yylval.c_value = yytext[1];
283 #else
284                          yylval.c_value = '=';
285                          yyless (1);
286 #endif
287                          return(ASSIGN_OP);
288                        }
289 ==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
290 \+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
291 "\n" { line_no++; return(ENDOFLINE); }
292 \\\n {  line_no++;  /* ignore a "quoted" newline */ }
293 [ \t]+  { /* ignore spaces and tabs */ }
294 "/*"  {
295         int c;
296
297         for (;;)
298           {
299             while ( ((c=input()) != '*') && (c != EOF)) 
300               /* eat it */
301               if (c == '\n') line_no++;
302             if (c == '*')
303               {
304                 while ( (c=input()) == '*') /* eat it*/;
305                 if (c == '/') break; /* at end of comment */
306                 if (c == '\n') line_no++;
307               }
308             if (c == EOF)
309               {
310                 fprintf (stderr,"EOF encountered in a comment.\n");
311                 break;
312               }
313           }
314       }
315 [a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
316 \"[^\"]*\"  {
317               unsigned char *look;
318               int count = 0;
319               yylval.s_value = strcopyof(yytext);
320               for (look = yytext; *look != 0; look++)
321                 {
322                   if (*look == '\n') line_no++;
323                   if (*look == '"')  count++;
324                 }
325               if (count != 2) yyerror ("NUL character in string.");
326               return(STRING);
327             }
328 {DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
329               unsigned char *src, *dst;
330               int len;
331               /* remove a trailing decimal point. */
332               len = strlen(yytext);
333               if (yytext[len-1] == '.')
334                 yytext[len-1] = 0;
335               /* remove leading zeros. */
336               src = yytext;
337               dst = yytext;
338               while (*src == '0') src++;
339               if (*src == 0) src--;
340               /* Copy strings removing the newlines. */
341               while (*src != 0)
342                 {
343                   if (*src == '\\')
344                     {
345                       src++; src++;
346                       line_no++;
347                     }
348                   else
349                     *dst++ = *src++;
350                 }
351               *dst = 0;
352               yylval.s_value = strcopyof(yytext); 
353               return(NUMBER);
354             }
355 .       {
356           if (yytext[0] < ' ')
357             yyerror ("illegal character: ^%c",yytext[0] + '@');
358           else
359             if (yytext[0] > '~')
360               yyerror ("illegal character: \\%03o", (int) yytext[0]);
361             else
362               yyerror ("illegal character: %s",yytext);
363         }
364 %%
365
366
367
368 /* This is the way to get multiple files input into lex. */
369
370 int
371 yywrap()
372 {
373   if (!open_new_file ()) return (1);    /* EOF on standard in. */
374   return (0);                           /* We have more input. */
375 }