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