Merge branch 'vendor/GCC50'
[dragonfly.git] / usr.bin / bc / scan.l
1 %{
2 /*
3  * $OpenBSD: scan.l,v 1.21 2006/03/18 20:44:43 otto Exp $
4  */
5
6 /*
7  * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21
22 #include <err.h>
23 #include <errno.h>
24 #include <histedit.h>
25 #include <signal.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "extern.h"
31 #include "pathnames.h"
32 #include "y.tab.h"
33
34 int             lineno;
35 bool            interactive;
36
37 HistEvent        he;
38 EditLine        *el;
39 History         *hist;
40
41 static char     *strbuf = NULL;
42 static size_t   strbuf_sz = 1;
43 static bool     dot_seen;
44 static int      use_el;
45 static volatile sig_atomic_t skipchars;
46
47 static void     init_strbuf(void);
48 static void     add_str(const char *);
49 static int      bc_yyinput(char *, int);
50
51 #undef YY_INPUT
52 #define YY_INPUT(buf,retval,max) \
53         (retval = bc_yyinput(buf, max))
54
55 %}
56
57 %option always-interactive
58 %option noinput
59
60 DIGIT           [0-9A-F]
61 ALPHA           [a-z_]
62 ALPHANUM        [a-z_0-9]
63
64 %x              comment string number
65
66 %%
67
68 "/*"            BEGIN(comment);
69 <comment>{
70         "*/"    BEGIN(INITIAL);
71         \n      lineno++;
72         \*      ;
73         [^*\n]+ ;
74         <<EOF>> fatal("end of file in comment");
75 }
76
77 \"              BEGIN(string); init_strbuf();
78 <string>{
79         [^"\n\\\[\]]+   add_str(yytext);
80         \[      add_str("\\[");
81         \]      add_str("\\]");
82         \\      add_str("\\\\");
83         \n      add_str("\n"); lineno++;
84         \"      BEGIN(INITIAL); yylval.str = strbuf; return STRING;
85         <<EOF>> fatal("end of file in string");
86 }
87
88 {DIGIT}+        {
89                         BEGIN(number);
90                         dot_seen = false;
91                         init_strbuf();
92                         add_str(yytext);
93                 }
94 \.              {
95                         BEGIN(number);
96                         dot_seen = true;
97                         init_strbuf();
98                         add_str(".");
99                 }
100 <number>{
101         {DIGIT}+        add_str(yytext);
102         \.      {
103                         if (dot_seen) {
104                                 BEGIN(INITIAL);
105                                 yylval.str = strbuf;
106                                 unput('.');
107                                 return NUMBER;
108                         } else {
109                                 dot_seen = true;
110                                 add_str(".");
111                         }
112                 }
113         \\\n[ \t]*      lineno++;
114         [^0-9A-F\.]     {
115                         BEGIN(INITIAL);
116                         unput(yytext[0]);
117                         if (strcmp(strbuf, ".") == 0)
118                                 return DOT;
119                         else {
120                                 yylval.str = strbuf;
121                                 return NUMBER;
122                         }
123                 }
124 }
125
126 "auto"          return AUTO;
127 "break"         return BREAK;
128 "continue"      return CONTINUE;
129 "define"        return DEFINE;
130 "else"          return ELSE;
131 "ibase"         return IBASE;
132 "if"            return IF;
133 "last"          return DOT;
134 "for"           return FOR;
135 "length"        return LENGTH;
136 "obase"         return OBASE;
137 "print"         return PRINT;
138 "quit"          return QUIT;
139 "return"        return RETURN;
140 "scale"         return SCALE;
141 "sqrt"          return SQRT;
142 "while"         return WHILE;
143
144 "^"             return EXPONENT;
145 "*"             return MULTIPLY;
146 "/"             return DIVIDE;
147 "%"             return REMAINDER;
148
149 "!"             return BOOL_NOT;
150 "&&"            return BOOL_AND;
151 "||"            return BOOL_OR;
152
153 "+"             return PLUS;
154 "-"             return MINUS;
155
156 "++"            return INCR;
157 "--"            return DECR;
158
159 "="             yylval.str = ""; return ASSIGN_OP;
160 "+="            yylval.str = "+"; return ASSIGN_OP;
161 "-="            yylval.str = "-"; return ASSIGN_OP;
162 "*="            yylval.str = "*"; return ASSIGN_OP;
163 "/="            yylval.str = "/"; return ASSIGN_OP;
164 "%="            yylval.str = "%"; return ASSIGN_OP;
165 "^="            yylval.str = "^"; return ASSIGN_OP;
166
167 "=="            return EQUALS;
168 "<="            return LESS_EQ;
169 ">="            return GREATER_EQ;
170 "!="            return UNEQUALS;
171 "<"             return LESS;
172 ">"             return GREATER;
173
174 ","             return COMMA;
175 ";"             return SEMICOLON;
176
177 "("             return LPAR;
178 ")"             return RPAR;
179
180 "["             return LBRACKET;
181 "]"             return RBRACKET;
182
183 "{"             return LBRACE;
184 "}"             return RBRACE;
185
186 {ALPHA}{ALPHANUM}* {
187                         /* alloc an extra byte for the type marker */
188                         char *p = malloc(yyleng + 2);
189                         if (p == NULL)
190                                 err(1, NULL);
191                         strlcpy(p, yytext, yyleng + 1);
192                         yylval.astr = p;
193                         return LETTER;
194                 }
195
196 \\\n            lineno++;
197 \n              lineno++; return NEWLINE;
198
199 #[^\n]*         ;
200 [ \t]           ;
201 <<EOF>>         return QUIT;
202 .               yyerror("illegal character");
203
204 %%
205
206 static void
207 init_strbuf(void)
208 {
209         if (strbuf == NULL) {
210                 strbuf = malloc(strbuf_sz);
211                 if (strbuf == NULL)
212                         err(1, NULL);
213         }
214         strbuf[0] = '\0';
215 }
216
217 static void
218 add_str(const char *str)
219 {
220         size_t arglen;
221
222         arglen = strlen(str);
223
224         if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
225                 size_t newsize;
226                 char *p;
227
228                 newsize = strbuf_sz + arglen + 1;
229                 p = realloc(strbuf, newsize);
230                 if (p == NULL) {
231                         free(strbuf);
232                         err(1, NULL);
233                 }
234                 strbuf_sz = newsize;
235                 strbuf = p;
236         }
237         strlcat(strbuf, str, strbuf_sz);
238 }
239
240 /* ARGSUSED */
241 void
242 abort_line(int sig)
243 {
244         const char str1[] = "[\n]P\n";
245         const char str2[] = "[^C\n]P\n";
246         int save_errno;
247         const LineInfo *info;
248
249         save_errno = errno;
250         if (use_el) {
251                 write(STDOUT_FILENO, str2, sizeof(str2) - 1);
252                 info = el_line(el);
253                 skipchars = info->lastchar - info->buffer;
254         } else
255                 write(STDOUT_FILENO, str1, sizeof(str1) - 1);
256         errno = save_errno;
257 }
258
259 /*
260  * Avoid the echo of ^D by the default code of editline and take
261  * into account skipchars to make ^D work when the cursor is at start of
262  * line after a ^C.
263  */
264 unsigned char
265 bc_eof(EditLine *e, int ch)
266 {
267         const struct lineinfo *info = el_line(e);
268
269         if (info->buffer + skipchars == info->cursor &&
270             info->cursor == info->lastchar)
271                 return (CC_EOF);
272         else
273                 return (CC_ERROR);
274 }
275
276 int
277 yywrap(void)
278 {
279         static int state;
280         static YY_BUFFER_STATE buf;
281
282         if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
283                 filename = sargv[fileindex++];
284                 yyin = fopen(filename, "r");
285                 lineno = 1;
286                 if (yyin == NULL)
287                         err(1, "cannot open %s", filename);
288                 return (0);
289         }
290         if (state == 0 && cmdexpr[0] != '\0') {
291                 buf = yy_scan_string(cmdexpr);
292                 state++;
293                 lineno = 1;
294                 filename = "command line";
295                 return (0);
296         } else if (state == 1) {
297                 yy_delete_buffer(buf);
298                 free(cmdexpr);
299                 state++;
300         }
301         if (yyin != NULL && yyin != stdin)
302                 fclose(yyin);
303         if (fileindex < sargc) {
304                 filename = sargv[fileindex++];
305                 yyin = fopen(filename, "r");
306                 lineno = 1;
307                 if (yyin == NULL)
308                         err(1, "cannot open %s", filename);
309                 return (0);
310         } else if (fileindex == sargc) {
311                 fileindex++;
312                 yyin = stdin;
313                 if (interactive) {
314                         signal(SIGINT, abort_line);
315                         signal(SIGTSTP, tstpcont);
316                 }
317                 lineno = 1;
318                 filename = "stdin";
319                 return (0);
320         }
321         return (1);
322 }
323
324 static int
325 bc_yyinput(char *buf, int maxlen)
326 {
327         int num;
328
329         if (el != NULL)
330                 el_get(el, EL_EDITMODE, &use_el);
331
332         if (yyin == stdin && interactive && use_el) {
333                 const char *bp;
334                 sigset_t oset, nset;
335
336                 if ((bp = el_gets(el, &num)) == NULL || num == 0)
337                         return (0);
338                 sigemptyset(&nset);
339                 sigaddset(&nset, SIGINT);
340                 sigprocmask(SIG_BLOCK, &nset, &oset);
341                 if (skipchars < num) {
342                         bp += skipchars;
343                         num -= skipchars;
344                 }
345                 skipchars = 0;
346                 sigprocmask(SIG_SETMASK, &oset, NULL);
347                 if (num > maxlen) {
348                         el_push(el, (char *)(uintptr_t)(bp) + maxlen);
349                         num = maxlen;
350                 }
351                 memcpy(buf, bp, num);
352                 history(hist, &he, H_ENTER, bp);
353                 el_get(el, EL_EDITMODE, &use_el);
354         } else {
355                 int c = '*';
356                 for (num = 0; num < maxlen &&
357                     (c = getc(yyin)) != EOF && c != '\n'; ++num)
358                         buf[num] = (char) c;
359                 if (c == '\n')
360                         buf[num++] = (char) c;
361                 if (c == EOF && ferror(yyin))
362                         YY_FATAL_ERROR( "input in flex scanner failed" );
363         }
364         return (num);
365 }