xref: /dragonfly/usr.bin/bc/scan.l (revision ec21d9fb)
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 }
366