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