xref: /dragonfly/usr.bin/bc/scan.l (revision 20c2db9a)
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 #pragma GCC diagnostic ignored "-Wsign-compare"
23 #include <err.h>
24 #include <errno.h>
25 #include <histedit.h>
26 #include <signal.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "extern.h"
32 #include "pathnames.h"
33 #include "y.tab.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 
46 static void	init_strbuf(void);
47 static void	add_str(const char *);
48 static int	bc_yyinput(char *, int);
49 
50 #undef YY_INPUT
51 #define YY_INPUT(buf,retval,max) \
52 	(retval = bc_yyinput(buf, max))
53 
54 %}
55 
56 %option always-interactive
57 %option noinput
58 
59 DIGIT		[0-9A-F]
60 ALPHA		[a-z_]
61 ALPHANUM	[a-z_0-9]
62 
63 %x		comment string number
64 
65 %%
66 
67 "/*"		BEGIN(comment);
68 <comment>{
69 	"*/"	BEGIN(INITIAL);
70 	\n	lineno++;
71 	\*	;
72 	[^*\n]+	;
73 	<<EOF>>	fatal("end of file in comment");
74 }
75 
76 \"		BEGIN(string); init_strbuf();
77 <string>{
78 	[^"\n\\\[\]]+	add_str(yytext);
79 	\[	add_str("\\[");
80 	\]	add_str("\\]");
81 	\\	add_str("\\\\");
82 	\n	add_str("\n"); lineno++;
83 	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
84 	<<EOF>>	fatal("end of file in string");
85 }
86 
87 {DIGIT}+	{
88 			BEGIN(number);
89 			dot_seen = false;
90 			init_strbuf();
91 			add_str(yytext);
92 		}
93 \.		{
94 			BEGIN(number);
95 			dot_seen = true;
96 			init_strbuf();
97 			add_str(".");
98 		}
99 <number>{
100 	{DIGIT}+	add_str(yytext);
101 	\.	{
102 			if (dot_seen) {
103 				BEGIN(INITIAL);
104 				yylval.str = strbuf;
105 				unput('.');
106 				return NUMBER;
107 			} else {
108 				dot_seen = true;
109 				add_str(".");
110 			}
111 		}
112 	\\\n[ \t]*	lineno++;
113 	[^0-9A-F\.]	{
114 			BEGIN(INITIAL);
115 			unput(yytext[0]);
116 			if (strcmp(strbuf, ".") == 0)
117 				return DOT;
118 			else {
119 				yylval.str = strbuf;
120 				return NUMBER;
121 			}
122 		}
123 }
124 
125 "auto"		return AUTO;
126 "break"		return BREAK;
127 "continue"	return CONTINUE;
128 "define"	return DEFINE;
129 "else"		return ELSE;
130 "ibase"		return IBASE;
131 "if"		return IF;
132 "last"		return DOT;
133 "for"		return FOR;
134 "length"	return LENGTH;
135 "obase"		return OBASE;
136 "print"		return PRINT;
137 "quit"		return QUIT;
138 "return"	return RETURN;
139 "scale"		return SCALE;
140 "sqrt"		return SQRT;
141 "while"		return WHILE;
142 
143 "^"		return EXPONENT;
144 "*"		return MULTIPLY;
145 "/"		return DIVIDE;
146 "%"		return REMAINDER;
147 
148 "!"		return BOOL_NOT;
149 "&&"		return BOOL_AND;
150 "||"		return BOOL_OR;
151 
152 "+"		return PLUS;
153 "-"		return MINUS;
154 
155 "++"		return INCR;
156 "--"		return DECR;
157 
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 "/="		yylval.str = "/"; return ASSIGN_OP;
163 "%="		yylval.str = "%"; return ASSIGN_OP;
164 "^="		yylval.str = "^"; return ASSIGN_OP;
165 
166 "=="		return EQUALS;
167 "<="		return LESS_EQ;
168 ">="		return GREATER_EQ;
169 "!="		return UNEQUALS;
170 "<"		return LESS;
171 ">"		return GREATER;
172 
173 ","		return COMMA;
174 ";"		return SEMICOLON;
175 
176 "("		return LPAR;
177 ")"		return RPAR;
178 
179 "["		return LBRACKET;
180 "]"		return RBRACKET;
181 
182 "{"		return LBRACE;
183 "}"		return RBRACE;
184 
185 {ALPHA}{ALPHANUM}* {
186 			/* alloc an extra byte for the type marker */
187 			char *p = malloc(yyleng + 2);
188 			if (p == NULL)
189 				err(1, NULL);
190 			strlcpy(p, yytext, yyleng + 1);
191 			yylval.astr = p;
192 			return LETTER;
193 		}
194 
195 \\\n		lineno++;
196 \n		lineno++; return NEWLINE;
197 
198 #[^\n]*		;
199 [ \t]		;
200 <<EOF>>		return QUIT;
201 .		yyerror("illegal character");
202 
203 %%
204 
205 static void
206 init_strbuf(void)
207 {
208 	if (strbuf == NULL) {
209 		strbuf = malloc(strbuf_sz);
210 		if (strbuf == NULL)
211 			err(1, NULL);
212 	}
213 	strbuf[0] = '\0';
214 }
215 
216 static void
217 add_str(const char *str)
218 {
219 	size_t arglen;
220 
221 	arglen = strlen(str);
222 
223 	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
224 		size_t newsize;
225 		char *p;
226 
227 		newsize = strbuf_sz + arglen + 1;
228 		p = realloc(strbuf, newsize);
229 		if (p == NULL) {
230 			free(strbuf);
231 			err(1, NULL);
232 		}
233 		strbuf_sz = newsize;
234 		strbuf = p;
235 	}
236 	strlcat(strbuf, str, strbuf_sz);
237 }
238 
239 /* ARGSUSED */
240 void
241 abort_line(int sig)
242 {
243 	const char str[] = "[\n]P\n";
244 	int save_errno;
245 
246 	save_errno = errno;
247 	YY_FLUSH_BUFFER;	/* XXX signal race? */
248 	write(STDOUT_FILENO, str, sizeof(str) - 1);
249 	errno = save_errno;
250 }
251 
252 int
253 yywrap(void)
254 {
255 	static int state;
256 	static YY_BUFFER_STATE buf;
257 
258 	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
259 		filename = sargv[fileindex++];
260 		yyin = fopen(filename, "r");
261 		lineno = 1;
262 		if (yyin == NULL)
263 			err(1, "cannot open %s", filename);
264 		return (0);
265 	}
266 	if (state == 0 && cmdexpr[0] != '\0') {
267 		buf = yy_scan_string(cmdexpr);
268 		state++;
269 		lineno = 1;
270 		filename = "command line";
271 		return (0);
272 	} else if (state == 1) {
273 		yy_delete_buffer(buf);
274 		free(cmdexpr);
275 		state++;
276 	}
277 	if (yyin != NULL && yyin != stdin)
278 		fclose(yyin);
279 	if (fileindex < sargc) {
280 		filename = sargv[fileindex++];
281 		yyin = fopen(filename, "r");
282 		lineno = 1;
283 		if (yyin == NULL)
284 			err(1, "cannot open %s", filename);
285 		return (0);
286 	} else if (fileindex == sargc) {
287 		fileindex++;
288 		yyin = stdin;
289 		if (interactive)
290 			signal(SIGINT, abort_line);
291 		lineno = 1;
292 		filename = "stdin";
293 		return (0);
294 	}
295 	return (1);
296 }
297 
298 static int
299 bc_yyinput(char *buf, int maxlen)
300 {
301 	int num;
302 	if (yyin == stdin && interactive) {
303 		const char *bp;
304 
305 		if ((bp = el_gets(el, &num)) == NULL || num == 0)
306 			return (0);
307 		if (num > maxlen) {
308 			el_push(el, (char *)(uintptr_t)(bp) + maxlen);
309 			num = maxlen;
310 		}
311 		memcpy(buf, bp, num);
312 		history(hist, &he, H_ENTER, bp);
313 	} else {
314 		int c = '*';
315 		for (num = 0; num < maxlen &&
316 		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
317 			buf[num] = (char) c;
318 		if (c == '\n')
319 			buf[num++] = (char) c;
320 		if (c == EOF && ferror(yyin))
321 			YY_FATAL_ERROR( "input in flex scanner failed" );
322 	}
323 	return (num);
324 }
325