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