scan.l revision 203531
1202719Sgabor%{
2202719Sgabor/*      $OpenBSD: scan.l,v 1.23 2009/10/27 23:59:36 deraadt Exp $	*/
3202719Sgabor
4202719Sgabor/*
5202719Sgabor * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6202719Sgabor *
7202719Sgabor * Permission to use, copy, modify, and distribute this software for any
8202719Sgabor * purpose with or without fee is hereby granted, provided that the above
9202719Sgabor * copyright notice and this permission notice appear in all copies.
10202719Sgabor *
11202719Sgabor * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12202719Sgabor * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13202719Sgabor * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14202719Sgabor * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15202719Sgabor * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16202719Sgabor * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17202719Sgabor * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18202719Sgabor */
19202719Sgabor
20202719Sgabor#include <sys/cdefs.h>
21202719Sgabor__FBSDID("$FreeBSD: head/usr.bin/bc/scan.l 203531 2010-02-05 18:17:17Z delphij $");
22202719Sgabor
23202719Sgabor#include <err.h>
24202719Sgabor#include <errno.h>
25203498Sdelphij#include <histedit.h>
26202719Sgabor#include <signal.h>
27202719Sgabor#include <stdbool.h>
28202719Sgabor#include <string.h>
29202719Sgabor#include <unistd.h>
30202719Sgabor
31202719Sgabor#include "extern.h"
32202719Sgabor#include "bc.h"
33202719Sgabor#include "pathnames.h"
34202719Sgabor
35202719Sgaborint		 lineno;
36202719Sgabor
37203498Sdelphijbool		 interactive;
38203498SdelphijHistEvent	 he;
39203498SdelphijEditLine	*el;
40203498SdelphijHistory		*hist;
41203498Sdelphij
42202719Sgaborstatic char	*strbuf = NULL;
43202719Sgaborstatic size_t	 strbuf_sz = 1;
44202719Sgaborstatic bool	 dot_seen;
45202719Sgabor
46202719Sgaborstatic void	 init_strbuf(void);
47202719Sgaborstatic void	 add_str(const char *);
48203498Sdelphijstatic int	 bc_yyinput(char *, int);
49202719Sgabor
50203498Sdelphij#undef YY_INPUT
51203498Sdelphij#define YY_INPUT(buf,retval,max) \
52203498Sdelphij	(retval = bc_yyinput(buf, max))
53202719Sgabor%}
54202719Sgabor
55202719Sgabor%option always-interactive
56202719Sgabor
57202719SgaborDIGIT		[0-9A-F]
58202719SgaborALPHA		[a-z_]
59202719SgaborALPHANUM	[a-z_0-9]
60202719Sgabor
61202719Sgabor%x		comment string number
62202719Sgabor
63202719Sgabor%%
64202719Sgabor
65202719Sgabor"/*"		BEGIN(comment);
66202719Sgabor<comment>{
67202719Sgabor	"*/"	BEGIN(INITIAL);
68202719Sgabor	\n	lineno++;
69202719Sgabor	\*	;
70202719Sgabor	[^*\n]+	;
71202719Sgabor	<<EOF>>	fatal("end of file in comment");
72202719Sgabor}
73202719Sgabor
74202719Sgabor\"		BEGIN(string); init_strbuf();
75202719Sgabor<string>{
76202719Sgabor	[^"\n\\\[\]]+	add_str(yytext);
77202719Sgabor	\[	add_str("\\[");
78202719Sgabor	\]	add_str("\\]");
79202719Sgabor	\\	add_str("\\\\");
80202719Sgabor	\n	add_str("\n"); lineno++;
81202719Sgabor	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
82202719Sgabor	<<EOF>>	fatal("end of file in string");
83202719Sgabor}
84202719Sgabor
85202719Sgabor{DIGIT}+	{
86202719Sgabor			BEGIN(number);
87202719Sgabor			dot_seen = false;
88202719Sgabor			init_strbuf();
89202719Sgabor			add_str(yytext);
90202719Sgabor		}
91202719Sgabor\.		{
92202719Sgabor			BEGIN(number);
93202719Sgabor			dot_seen = true;
94202719Sgabor			init_strbuf();
95202719Sgabor			add_str(".");
96202719Sgabor		}
97202719Sgabor<number>{
98202719Sgabor	{DIGIT}+	add_str(yytext);
99202719Sgabor	\.	{
100202719Sgabor			if (dot_seen) {
101202719Sgabor				BEGIN(INITIAL);
102202719Sgabor				yylval.str = strbuf;
103202719Sgabor				unput('.');
104202719Sgabor				return (NUMBER);
105202719Sgabor			} else {
106202719Sgabor				dot_seen = true;
107202719Sgabor				add_str(".");
108202719Sgabor			}
109202719Sgabor		}
110202719Sgabor	\\\n[ \t]*	lineno++;
111202719Sgabor	[^0-9A-F\.]	{
112202719Sgabor			BEGIN(INITIAL);
113202719Sgabor			unput(yytext[0]);
114202719Sgabor			if (strcmp(strbuf, ".") == 0)
115202719Sgabor				return (DOT);
116202719Sgabor			else {
117202719Sgabor				yylval.str = strbuf;
118202719Sgabor				return (NUMBER);
119202719Sgabor			}
120202719Sgabor		}
121202719Sgabor}
122202719Sgabor
123202719Sgabor"auto"		return (AUTO);
124202719Sgabor"break"		return (BREAK);
125202719Sgabor"continue"	return (CONTINUE);
126202719Sgabor"define"	return (DEFINE);
127202719Sgabor"else"		return (ELSE);
128202719Sgabor"ibase"		return (IBASE);
129202719Sgabor"if"		return (IF);
130202719Sgabor"last"		return (DOT);
131202719Sgabor"for"		return (FOR);
132202719Sgabor"length"	return (LENGTH);
133202719Sgabor"obase"		return (OBASE);
134202719Sgabor"print"		return (PRINT);
135202719Sgabor"quit"		return (QUIT);
136202719Sgabor"return"	return (RETURN);
137202719Sgabor"scale"		return (SCALE);
138202719Sgabor"sqrt"		return (SQRT);
139202719Sgabor"while"		return (WHILE);
140202719Sgabor
141202719Sgabor"^"		return (EXPONENT);
142202719Sgabor"*"		return (MULTIPLY);
143202719Sgabor"/"		return (DIVIDE);
144202719Sgabor"%"		return (REMAINDER);
145202719Sgabor
146202719Sgabor"!"		return (BOOL_NOT);
147202719Sgabor"&&"		return (BOOL_AND);
148202719Sgabor"||"		return (BOOL_OR);
149202719Sgabor
150202719Sgabor"+"		return (PLUS);
151202719Sgabor"-"		return (MINUS);
152202719Sgabor
153202719Sgabor"++"		return (INCR);
154202719Sgabor"--"		return (DECR);
155202719Sgabor
156202719Sgabor"="		yylval.str = ""; return (ASSIGN_OP);
157202719Sgabor"+="		yylval.str = "+"; return (ASSIGN_OP);
158202719Sgabor"-="		yylval.str = "-"; return (ASSIGN_OP);
159202719Sgabor"*="		yylval.str = "*"; return (ASSIGN_OP);
160202719Sgabor"/="		yylval.str = "/"; return (ASSIGN_OP);
161202719Sgabor"%="		yylval.str = "%"; return (ASSIGN_OP);
162202719Sgabor"^="		yylval.str = "^"; return (ASSIGN_OP);
163202719Sgabor
164202719Sgabor"=="		return (EQUALS);
165202719Sgabor"<="		return (LESS_EQ);
166202719Sgabor">="		return (GREATER_EQ);
167202719Sgabor"!="		return (UNEQUALS);
168202719Sgabor"<"		return (LESS);
169202719Sgabor">"		return (GREATER);
170202719Sgabor
171202719Sgabor","		return (COMMA);
172202719Sgabor";"		return (SEMICOLON);
173202719Sgabor
174202719Sgabor"("		return (LPAR);
175202719Sgabor")"		return (RPAR);
176202719Sgabor
177202719Sgabor"["		return (LBRACKET);
178202719Sgabor"]"		return (RBRACKET);
179202719Sgabor
180202719Sgabor"{"		return (LBRACE);
181202719Sgabor"}"		return (RBRACE);
182202719Sgabor
183202719Sgabor{ALPHA}{ALPHANUM}* {
184202719Sgabor			/* alloc an extra byte for the type marker */
185202719Sgabor			char *p = malloc(yyleng + 2);
186202719Sgabor			if (p == NULL)
187202719Sgabor				err(1, NULL);
188202719Sgabor			strlcpy(p, yytext, yyleng + 1);
189202719Sgabor			yylval.astr = p;
190202719Sgabor			return (LETTER);
191202719Sgabor		}
192202719Sgabor
193202719Sgabor\\\n		lineno++;
194202719Sgabor\n		lineno++; return (NEWLINE);
195202719Sgabor
196202719Sgabor#[^\n]*		;
197202719Sgabor[ \t]		;
198202719Sgabor<<EOF>>		return (QUIT);
199202719Sgabor.		yyerror("illegal character");
200202719Sgabor
201202719Sgabor%%
202202719Sgabor
203202719Sgaborstatic void
204202719Sgaborinit_strbuf(void)
205202719Sgabor{
206203443Sgabor
207202719Sgabor	if (strbuf == NULL) {
208202719Sgabor		strbuf = malloc(strbuf_sz);
209202719Sgabor		if (strbuf == NULL)
210202719Sgabor			err(1, NULL);
211202719Sgabor	}
212202719Sgabor	strbuf[0] = '\0';
213202719Sgabor}
214202719Sgabor
215202719Sgaborstatic void
216202719Sgaboradd_str(const char *str)
217202719Sgabor{
218203443Sgabor	size_t arglen;
219202719Sgabor
220202719Sgabor	arglen = strlen(str);
221202719Sgabor
222202719Sgabor	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
223202719Sgabor		size_t	 newsize;
224202719Sgabor		char	*p;
225202719Sgabor
226202719Sgabor		newsize = strbuf_sz + arglen + 1;
227202719Sgabor		p = realloc(strbuf, newsize);
228202719Sgabor		if (p == NULL) {
229202719Sgabor			free(strbuf);
230202719Sgabor			err(1, NULL);
231202719Sgabor		}
232202719Sgabor		strbuf_sz = newsize;
233202719Sgabor		strbuf = p;
234202719Sgabor	}
235202719Sgabor	strlcat(strbuf, str, strbuf_sz);
236202719Sgabor}
237202719Sgabor
238202719Sgabor/* ARGSUSED */
239202719Sgaborvoid
240202719Sgaborabort_line(int sig)
241202719Sgabor{
242203443Sgabor	static const char str[] = "[\n]P\n";
243203443Sgabor	int save_errno;
244202719Sgabor
245202719Sgabor	switch (sig) {
246202719Sgabor	default:
247202719Sgabor		save_errno = errno;
248202719Sgabor		YY_FLUSH_BUFFER;	/* XXX signal race? */
249202719Sgabor		write(STDOUT_FILENO, str, sizeof(str) - 1);
250202719Sgabor		errno = save_errno;
251202719Sgabor	}
252202719Sgabor}
253202719Sgabor
254202719Sgaborint
255202719Sgaboryywrap(void)
256202719Sgabor{
257203443Sgabor	static YY_BUFFER_STATE buf;
258203443Sgabor	static int state;
259202719Sgabor
260202719Sgabor	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
261202719Sgabor		filename = sargv[fileindex++];
262202719Sgabor		yyin = fopen(filename, "r");
263202719Sgabor		lineno = 1;
264202719Sgabor		if (yyin == NULL)
265202719Sgabor			err(1, "cannot open %s", filename);
266202719Sgabor		return (0);
267202719Sgabor	}
268202719Sgabor	if (state == 0 && cmdexpr[0] != '\0') {
269202719Sgabor		buf = yy_scan_string(cmdexpr);
270202719Sgabor		state++;
271202719Sgabor		lineno = 1;
272202719Sgabor		filename = "command line";
273202719Sgabor		return (0);
274202719Sgabor	} else if (state == 1) {
275202719Sgabor		yy_delete_buffer(buf);
276202719Sgabor		free(cmdexpr);
277202719Sgabor		state++;
278202719Sgabor	}
279202719Sgabor	if (yyin != NULL && yyin != stdin)
280202719Sgabor		fclose(yyin);
281202719Sgabor	if (fileindex < sargc) {
282202719Sgabor		filename = sargv[fileindex++];
283202719Sgabor		yyin = fopen(filename, "r");
284202719Sgabor		lineno = 1;
285202719Sgabor		if (yyin == NULL)
286202719Sgabor			err(1, "cannot open %s", filename);
287202719Sgabor		return (0);
288202719Sgabor	} else if (fileindex == sargc) {
289202719Sgabor		fileindex++;
290202719Sgabor		yyin = stdin;
291202719Sgabor		if (interactive)
292202719Sgabor			signal(SIGINT, abort_line);
293202719Sgabor		lineno = 1;
294202719Sgabor		filename = "stdin";
295202719Sgabor		return (0);
296202719Sgabor	}
297202719Sgabor	return (1);
298202719Sgabor}
299203498Sdelphij
300203498Sdelphijstatic int
301203498Sdelphijbc_yyinput(char *buf, int maxlen)
302203498Sdelphij{
303203498Sdelphij	int num;
304203531Sdelphij	if (yyin == stdin && interactive) {
305203498Sdelphij		const char *bp;
306203498Sdelphij
307203498Sdelphij		if ((bp = el_gets(el, &num)) == NULL || num == 0)
308203498Sdelphij			return (0);
309203498Sdelphij		if (num > maxlen) {
310203498Sdelphij			el_push(el, (char *)(uintptr_t)(bp) + maxlen);
311203498Sdelphij			num = maxlen;
312203498Sdelphij		}
313203498Sdelphij		memcpy(buf, bp, num);
314203498Sdelphij		history(hist, &he, H_ENTER, bp);
315203498Sdelphij	} else {
316203498Sdelphij		int c = '*';
317203498Sdelphij		for (num = 0; num < maxlen &&
318203498Sdelphij		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
319203498Sdelphij			buf[num] = (char) c;
320203498Sdelphij		if (c == '\n')
321203498Sdelphij			buf[num++] = (char) c;
322203498Sdelphij		if (c == EOF && ferror(yyin))
323203498Sdelphij			YY_FATAL_ERROR( "input in flex scanner failed" );
324203498Sdelphij	}
325203498Sdelphij	return (num);
326203498Sdelphij}
327203498Sdelphij
328