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