]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bc/bc/scan.l
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bc / bc / scan.l
1 %{
2 /* $FreeBSD$ */
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
148 /* rl_input puts upto MAX characters into BUF with the number put in
149    BUF placed in *RESULT.  If the yy input file is the same as
150    rl_instream (stdin), use readline.  Otherwise, just read it.
151 */
152
153 static void
154 rl_input (buf, result, max)
155         char *buf;
156         int  *result;
157         int   max;
158 {
159   if (yyin != rl_instream)
160     {
161       while ( (*result = read( fileno(yyin), buf, max )) < 0 )
162         if (errno != EINTR)
163           {
164             yyerror( "read() in flex scanner failed" );
165             exit (1);
166           }
167       return;
168     }
169
170   /* Do we need a new string? */
171   if (rl_len == 0)
172     {
173       if (rl_start)
174         free(rl_start);
175       rl_start = readline ("");
176       if (rl_start == NULL) {
177         /* end of file */
178         *result = 0;
179         rl_len = 0;
180         return;
181       }
182       rl_line = rl_start;
183       rl_len = strlen (rl_line)+1;
184       if (rl_len != 1)
185         add_history (rl_line); 
186       rl_line[rl_len-1] = '\n';
187       fflush (stdout);
188     }
189
190   if (rl_len <= max)
191     {
192       strncpy (buf, rl_line, rl_len);
193       *result = rl_len;
194       rl_len = 0;
195     }
196   else
197     {
198       strncpy (buf, rl_line, max);
199       *result = max;
200       rl_line += max;
201       rl_len -= max;
202     }
203 }
204 #endif
205
206 #if !defined(READLINE) && !defined(LIBEDIT)
207
208 /* MINIX returns from read with < 0 if SIGINT is  encountered.
209    In flex, we can redefine YY_INPUT to the following.  In lex, this
210    does nothing! */
211 #undef  YY_INPUT
212 #define YY_INPUT(buf,result,max_size) \
213         while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
214             if (errno != EINTR) \
215                 YY_FATAL_ERROR( "read() in flex scanner failed" );
216 #endif
217
218 %}
219 DIGIT [0-9A-F]
220 LETTER [a-z]
221 %s slcomment
222 %%
223 "#"             {
224                   if (!std_only)
225                     BEGIN(slcomment);
226                   else
227                     yyerror ("illegal character: #");
228                 }
229 <slcomment>[^\n]* { BEGIN(INITIAL); }
230 <slcomment>"\n" { line_no++; BEGIN(INITIAL); return(ENDOFLINE); }
231 define return(Define);
232 break  return(Break);
233 quit   return(Quit);
234 length return(Length);
235 return return(Return);
236 for    return(For);
237 if     return(If);
238 while  return(While);
239 sqrt   return(Sqrt);
240 scale  return(Scale);
241 ibase  return(Ibase);
242 obase  return(Obase);
243 auto   return(Auto);
244 else   return(Else);
245 read   return(Read);
246 halt   return(Halt);
247 last   return(Last);
248 history {
249 #if defined(READLINE) || defined(LIBEDIT)
250           return(HistoryVar);
251 #else
252           yylval.s_value = strcopyof(yytext); return(NAME);
253 #endif
254         }
255
256 warranty return(Warranty);
257 continue return(Continue);
258 print  return(Print);
259 limits return(Limits);
260 "." {
261 #ifdef DOT_IS_LAST
262        return(Last);
263 #else
264        yyerror ("illegal character: %s",yytext);
265 #endif
266     }
267 "+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; 
268                                               return((int)yytext[0]); }
269 && { return(AND); }
270 \|\| { return(OR); }
271 "!" { return(NOT); }
272 "*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); }
273 "="|\+=|-=|\*=|\/=|%=|\^=  { yylval.c_value = yytext[0]; return(ASSIGN_OP); }
274 =\+|=-|=\*|=\/|=%|=\^  { 
275 #ifdef OLD_EQ_OP
276                          char warn_save;
277                          warn_save = warn_not_std;
278                          warn_not_std = TRUE;
279                          warn ("Old fashioned =<op>");
280                          warn_not_std = warn_save;
281                          yylval.c_value = yytext[1];
282 #else
283                          yylval.c_value = '=';
284                          yyless (1);
285 #endif
286                          return(ASSIGN_OP);
287                        }
288 ==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); }
289 \+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); }
290 "\n" { line_no++; return(ENDOFLINE); }
291 \\\n {  line_no++;  /* ignore a "quoted" newline */ }
292 [ \t]+  { /* ignore spaces and tabs */ }
293 "/*"  {
294         int c;
295
296         for (;;)
297           {
298             while ( ((c=input()) != '*') && (c != EOF)) 
299               /* eat it */
300               if (c == '\n') line_no++;
301             if (c == '*')
302               {
303                 while ( (c=input()) == '*') /* eat it*/;
304                 if (c == '/') break; /* at end of comment */
305                 if (c == '\n') line_no++;
306               }
307             if (c == EOF)
308               {
309                 fprintf (stderr,"EOF encountered in a comment.\n");
310                 break;
311               }
312           }
313       }
314 [a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); }
315 \"[^\"]*\"  {
316               unsigned char *look;
317               int count = 0;
318               yylval.s_value = strcopyof(yytext);
319               for (look = yytext; *look != 0; look++)
320                 {
321                   if (*look == '\n') line_no++;
322                   if (*look == '"')  count++;
323                 }
324               if (count != 2) yyerror ("NUL character in string.");
325               return(STRING);
326             }
327 {DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* {
328               unsigned char *src, *dst;
329               int len;
330               /* remove a trailing decimal point. */
331               len = strlen(yytext);
332               if (yytext[len-1] == '.')
333                 yytext[len-1] = 0;
334               /* remove leading zeros. */
335               src = yytext;
336               dst = yytext;
337               while (*src == '0') src++;
338               if (*src == 0) src--;
339               /* Copy strings removing the newlines. */
340               while (*src != 0)
341                 {
342                   if (*src == '\\')
343                     {
344                       src++; src++;
345                       line_no++;
346                     }
347                   else
348                     *dst++ = *src++;
349                 }
350               *dst = 0;
351               yylval.s_value = strcopyof(yytext); 
352               return(NUMBER);
353             }
354 .       {
355           if (yytext[0] < ' ')
356             yyerror ("illegal character: ^%c",yytext[0] + '@');
357           else
358             if (yytext[0] > '~')
359               yyerror ("illegal character: \\%03o", (int) yytext[0]);
360             else
361               yyerror ("illegal character: %s",yytext);
362         }
363 %%
364
365
366
367 /* This is the way to get multiple files input into lex. */
368
369 int
370 yywrap()
371 {
372   if (!open_new_file ()) return (1);    /* EOF on standard in. */
373   return (0);                           /* We have more input. */
374 }