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