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