scan.l revision 202719
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 202719 2010-01-20 21:30:52Z gabor $");
22202719Sgabor
23202719Sgabor#include <err.h>
24202719Sgabor#include <errno.h>
25202719Sgabor#include <signal.h>
26202719Sgabor#include <stdbool.h>
27202719Sgabor#include <string.h>
28202719Sgabor#include <unistd.h>
29202719Sgabor
30202719Sgabor#include "extern.h"
31202719Sgabor#include "bc.h"
32202719Sgabor#include "pathnames.h"
33202719Sgabor
34202719Sgaborint		 lineno;
35202719Sgabor
36202719Sgaborstatic char	*strbuf = NULL;
37202719Sgaborstatic size_t	 strbuf_sz = 1;
38202719Sgaborstatic bool	 dot_seen;
39202719Sgabor
40202719Sgaborstatic void	 init_strbuf(void);
41202719Sgaborstatic void	 add_str(const char *);
42202719Sgabor
43202719Sgabor%}
44202719Sgabor
45202719Sgabor%option always-interactive
46202719Sgabor
47202719SgaborDIGIT		[0-9A-F]
48202719SgaborALPHA		[a-z_]
49202719SgaborALPHANUM	[a-z_0-9]
50202719Sgabor
51202719Sgabor%x		comment string number
52202719Sgabor
53202719Sgabor%%
54202719Sgabor
55202719Sgabor"/*"		BEGIN(comment);
56202719Sgabor<comment>{
57202719Sgabor	"*/"	BEGIN(INITIAL);
58202719Sgabor	\n	lineno++;
59202719Sgabor	\*	;
60202719Sgabor	[^*\n]+	;
61202719Sgabor	<<EOF>>	fatal("end of file in comment");
62202719Sgabor}
63202719Sgabor
64202719Sgabor\"		BEGIN(string); init_strbuf();
65202719Sgabor<string>{
66202719Sgabor	[^"\n\\\[\]]+	add_str(yytext);
67202719Sgabor	\[	add_str("\\[");
68202719Sgabor	\]	add_str("\\]");
69202719Sgabor	\\	add_str("\\\\");
70202719Sgabor	\n	add_str("\n"); lineno++;
71202719Sgabor	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
72202719Sgabor	<<EOF>>	fatal("end of file in string");
73202719Sgabor}
74202719Sgabor
75202719Sgabor{DIGIT}+	{
76202719Sgabor			BEGIN(number);
77202719Sgabor			dot_seen = false;
78202719Sgabor			init_strbuf();
79202719Sgabor			add_str(yytext);
80202719Sgabor		}
81202719Sgabor\.		{
82202719Sgabor			BEGIN(number);
83202719Sgabor			dot_seen = true;
84202719Sgabor			init_strbuf();
85202719Sgabor			add_str(".");
86202719Sgabor		}
87202719Sgabor<number>{
88202719Sgabor	{DIGIT}+	add_str(yytext);
89202719Sgabor	\.	{
90202719Sgabor			if (dot_seen) {
91202719Sgabor				BEGIN(INITIAL);
92202719Sgabor				yylval.str = strbuf;
93202719Sgabor				unput('.');
94202719Sgabor				return (NUMBER);
95202719Sgabor			} else {
96202719Sgabor				dot_seen = true;
97202719Sgabor				add_str(".");
98202719Sgabor			}
99202719Sgabor		}
100202719Sgabor	\\\n[ \t]*	lineno++;
101202719Sgabor	[^0-9A-F\.]	{
102202719Sgabor			BEGIN(INITIAL);
103202719Sgabor			unput(yytext[0]);
104202719Sgabor			if (strcmp(strbuf, ".") == 0)
105202719Sgabor				return (DOT);
106202719Sgabor			else {
107202719Sgabor				yylval.str = strbuf;
108202719Sgabor				return (NUMBER);
109202719Sgabor			}
110202719Sgabor		}
111202719Sgabor}
112202719Sgabor
113202719Sgabor"auto"		return (AUTO);
114202719Sgabor"break"		return (BREAK);
115202719Sgabor"continue"	return (CONTINUE);
116202719Sgabor"define"	return (DEFINE);
117202719Sgabor"else"		return (ELSE);
118202719Sgabor"ibase"		return (IBASE);
119202719Sgabor"if"		return (IF);
120202719Sgabor"last"		return (DOT);
121202719Sgabor"for"		return (FOR);
122202719Sgabor"length"	return (LENGTH);
123202719Sgabor"obase"		return (OBASE);
124202719Sgabor"print"		return (PRINT);
125202719Sgabor"quit"		return (QUIT);
126202719Sgabor"return"	return (RETURN);
127202719Sgabor"scale"		return (SCALE);
128202719Sgabor"sqrt"		return (SQRT);
129202719Sgabor"while"		return (WHILE);
130202719Sgabor
131202719Sgabor"^"		return (EXPONENT);
132202719Sgabor"*"		return (MULTIPLY);
133202719Sgabor"/"		return (DIVIDE);
134202719Sgabor"%"		return (REMAINDER);
135202719Sgabor
136202719Sgabor"!"		return (BOOL_NOT);
137202719Sgabor"&&"		return (BOOL_AND);
138202719Sgabor"||"		return (BOOL_OR);
139202719Sgabor
140202719Sgabor"+"		return (PLUS);
141202719Sgabor"-"		return (MINUS);
142202719Sgabor
143202719Sgabor"++"		return (INCR);
144202719Sgabor"--"		return (DECR);
145202719Sgabor
146202719Sgabor"="		yylval.str = ""; return (ASSIGN_OP);
147202719Sgabor"+="		yylval.str = "+"; return (ASSIGN_OP);
148202719Sgabor"-="		yylval.str = "-"; return (ASSIGN_OP);
149202719Sgabor"*="		yylval.str = "*"; return (ASSIGN_OP);
150202719Sgabor"/="		yylval.str = "/"; return (ASSIGN_OP);
151202719Sgabor"%="		yylval.str = "%"; return (ASSIGN_OP);
152202719Sgabor"^="		yylval.str = "^"; return (ASSIGN_OP);
153202719Sgabor
154202719Sgabor"=="		return (EQUALS);
155202719Sgabor"<="		return (LESS_EQ);
156202719Sgabor">="		return (GREATER_EQ);
157202719Sgabor"!="		return (UNEQUALS);
158202719Sgabor"<"		return (LESS);
159202719Sgabor">"		return (GREATER);
160202719Sgabor
161202719Sgabor","		return (COMMA);
162202719Sgabor";"		return (SEMICOLON);
163202719Sgabor
164202719Sgabor"("		return (LPAR);
165202719Sgabor")"		return (RPAR);
166202719Sgabor
167202719Sgabor"["		return (LBRACKET);
168202719Sgabor"]"		return (RBRACKET);
169202719Sgabor
170202719Sgabor"{"		return (LBRACE);
171202719Sgabor"}"		return (RBRACE);
172202719Sgabor
173202719Sgabor{ALPHA}{ALPHANUM}* {
174202719Sgabor			/* alloc an extra byte for the type marker */
175202719Sgabor			char *p = malloc(yyleng + 2);
176202719Sgabor			if (p == NULL)
177202719Sgabor				err(1, NULL);
178202719Sgabor			strlcpy(p, yytext, yyleng + 1);
179202719Sgabor			yylval.astr = p;
180202719Sgabor			return (LETTER);
181202719Sgabor		}
182202719Sgabor
183202719Sgabor\\\n		lineno++;
184202719Sgabor\n		lineno++; return (NEWLINE);
185202719Sgabor
186202719Sgabor#[^\n]*		;
187202719Sgabor[ \t]		;
188202719Sgabor<<EOF>>		return (QUIT);
189202719Sgabor.		yyerror("illegal character");
190202719Sgabor
191202719Sgabor%%
192202719Sgabor
193202719Sgaborstatic void
194202719Sgaborinit_strbuf(void)
195202719Sgabor{
196202719Sgabor	if (strbuf == NULL) {
197202719Sgabor		strbuf = malloc(strbuf_sz);
198202719Sgabor		if (strbuf == NULL)
199202719Sgabor			err(1, NULL);
200202719Sgabor	}
201202719Sgabor	strbuf[0] = '\0';
202202719Sgabor}
203202719Sgabor
204202719Sgaborstatic void
205202719Sgaboradd_str(const char *str)
206202719Sgabor{
207202719Sgabor	size_t	 arglen;
208202719Sgabor
209202719Sgabor	arglen = strlen(str);
210202719Sgabor
211202719Sgabor	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
212202719Sgabor		size_t	 newsize;
213202719Sgabor		char	*p;
214202719Sgabor
215202719Sgabor		newsize = strbuf_sz + arglen + 1;
216202719Sgabor		p = realloc(strbuf, newsize);
217202719Sgabor		if (p == NULL) {
218202719Sgabor			free(strbuf);
219202719Sgabor			err(1, NULL);
220202719Sgabor		}
221202719Sgabor		strbuf_sz = newsize;
222202719Sgabor		strbuf = p;
223202719Sgabor	}
224202719Sgabor	strlcat(strbuf, str, strbuf_sz);
225202719Sgabor}
226202719Sgabor
227202719Sgabor/* ARGSUSED */
228202719Sgaborvoid
229202719Sgaborabort_line(int sig)
230202719Sgabor{
231202719Sgabor	static const char	 str[] = "[\n]P\n";
232202719Sgabor	int			 save_errno;
233202719Sgabor
234202719Sgabor	switch (sig) {
235202719Sgabor	default:
236202719Sgabor		save_errno = errno;
237202719Sgabor		YY_FLUSH_BUFFER;	/* XXX signal race? */
238202719Sgabor		write(STDOUT_FILENO, str, sizeof(str) - 1);
239202719Sgabor		errno = save_errno;
240202719Sgabor	}
241202719Sgabor}
242202719Sgabor
243202719Sgaborint
244202719Sgaboryywrap(void)
245202719Sgabor{
246202719Sgabor	static int		 state;
247202719Sgabor	static YY_BUFFER_STATE	 buf;
248202719Sgabor
249202719Sgabor	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
250202719Sgabor		filename = sargv[fileindex++];
251202719Sgabor		yyin = fopen(filename, "r");
252202719Sgabor		lineno = 1;
253202719Sgabor		if (yyin == NULL)
254202719Sgabor			err(1, "cannot open %s", filename);
255202719Sgabor		return (0);
256202719Sgabor	}
257202719Sgabor	if (state == 0 && cmdexpr[0] != '\0') {
258202719Sgabor		buf = yy_scan_string(cmdexpr);
259202719Sgabor		state++;
260202719Sgabor		lineno = 1;
261202719Sgabor		filename = "command line";
262202719Sgabor		return (0);
263202719Sgabor	} else if (state == 1) {
264202719Sgabor		yy_delete_buffer(buf);
265202719Sgabor		free(cmdexpr);
266202719Sgabor		state++;
267202719Sgabor	}
268202719Sgabor	if (yyin != NULL && yyin != stdin)
269202719Sgabor		fclose(yyin);
270202719Sgabor	if (fileindex < sargc) {
271202719Sgabor		filename = sargv[fileindex++];
272202719Sgabor		yyin = fopen(filename, "r");
273202719Sgabor		lineno = 1;
274202719Sgabor		if (yyin == NULL)
275202719Sgabor			err(1, "cannot open %s", filename);
276202719Sgabor		return (0);
277202719Sgabor	} else if (fileindex == sargc) {
278202719Sgabor		fileindex++;
279202719Sgabor		yyin = stdin;
280202719Sgabor		if (interactive)
281202719Sgabor			signal(SIGINT, abort_line);
282202719Sgabor		lineno = 1;
283202719Sgabor		filename = "stdin";
284202719Sgabor		return (0);
285202719Sgabor	}
286202719Sgabor	return (1);
287202719Sgabor}
288202719Sgabor
289