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