scan.l revision 252181
1163976Sdougb%{
2135446Strhodes/*      $OpenBSD: scan.l,v 1.23 2009/10/27 23:59:36 deraadt Exp $	*/
3135446Strhodes
4135446Strhodes/*
5135446Strhodes * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6135446Strhodes *
7135446Strhodes * Permission to use, copy, modify, and distribute this software for any
8135446Strhodes * purpose with or without fee is hereby granted, provided that the above
9135446Strhodes * copyright notice and this permission notice appear in all copies.
10135446Strhodes *
11135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12135446Strhodes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13135446Strhodes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14135446Strhodes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15135446Strhodes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16135446Strhodes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17135446Strhodes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18135446Strhodes */
19135446Strhodes
20135446Strhodes#include <sys/cdefs.h>
21163976Sdougb__FBSDID("$FreeBSD: stable/9/usr.bin/bc/scan.l 252181 2013-06-24 21:33:19Z marius $");
22135446Strhodes
23135446Strhodes#include <err.h>
24135446Strhodes#include <errno.h>
25135446Strhodes#include <histedit.h>
26135446Strhodes#include <stdbool.h>
27135446Strhodes#include <string.h>
28135446Strhodes#include <unistd.h>
29135446Strhodes
30135446Strhodes#include "extern.h"
31135446Strhodes#include "bc.h"
32135446Strhodes#include "pathnames.h"
33135446Strhodes
34135446Strhodesint		 lineno;
35135446Strhodes
36135446Strhodesbool		 interactive;
37135446StrhodesHistEvent	 he;
38135446StrhodesEditLine	*el;
39135446StrhodesHistory		*hist;
40135446Strhodes
41135446Strhodesstatic char	*strbuf = NULL;
42135446Strhodesstatic size_t	 strbuf_sz = 1;
43135446Strhodesstatic bool	 dot_seen;
44135446Strhodes
45135446Strhodesstatic void	 init_strbuf(void);
46135446Strhodesstatic void	 add_str(const char *);
47135446Strhodesstatic int	 bc_yyinput(char *, int);
48135446Strhodes
49135446Strhodes#define YY_DECL	int yylex(void)
50135446Strhodes#define YY_NO_INPUT
51135446Strhodes#undef YY_INPUT
52135446Strhodes#define YY_INPUT(buf,retval,max) \
53135446Strhodes	(retval = bc_yyinput(buf, max))
54135446Strhodes%}
55135446Strhodes
56135446Strhodes%option always-interactive
57135446Strhodes
58135446StrhodesDIGIT		[0-9A-F]
59135446StrhodesALPHA		[a-z_]
60135446StrhodesALPHANUM	[a-z_0-9]
61135446Strhodes
62135446Strhodes%x		comment string number
63135446Strhodes
64135446Strhodes%%
65135446Strhodes
66135446Strhodes"/*"		BEGIN(comment);
67135446Strhodes<comment>{
68135446Strhodes	"*/"	BEGIN(INITIAL);
69135446Strhodes	\n	lineno++;
70135446Strhodes	\*	;
71135446Strhodes	[^*\n]+	;
72135446Strhodes	<<EOF>>	fatal("end of file in comment");
73135446Strhodes}
74135446Strhodes
75135446Strhodes\"		BEGIN(string); init_strbuf();
76135446Strhodes<string>{
77135446Strhodes	[^"\n\\\[\]]+	add_str(yytext);
78135446Strhodes	\[	add_str("\\[");
79135446Strhodes	\]	add_str("\\]");
80135446Strhodes	\\	add_str("\\\\");
81135446Strhodes	\n	add_str("\n"); lineno++;
82135446Strhodes	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
83135446Strhodes	<<EOF>>	fatal("end of file in string");
84135446Strhodes}
85135446Strhodes
86135446Strhodes{DIGIT}+	{
87135446Strhodes			BEGIN(number);
88135446Strhodes			dot_seen = false;
89135446Strhodes			init_strbuf();
90135446Strhodes			add_str(yytext);
91135446Strhodes		}
92135446Strhodes\.		{
93135446Strhodes			BEGIN(number);
94135446Strhodes			dot_seen = true;
95135446Strhodes			init_strbuf();
96135446Strhodes			add_str(".");
97135446Strhodes		}
98135446Strhodes<number>{
99135446Strhodes	{DIGIT}+	add_str(yytext);
100135446Strhodes	\.	{
101135446Strhodes			if (dot_seen) {
102135446Strhodes				BEGIN(INITIAL);
103135446Strhodes				yylval.str = strbuf;
104135446Strhodes				unput('.');
105135446Strhodes				return (NUMBER);
106135446Strhodes			} else {
107135446Strhodes				dot_seen = true;
108135446Strhodes				add_str(".");
109135446Strhodes			}
110135446Strhodes		}
111135446Strhodes	\\\n[ \t]*	lineno++;
112135446Strhodes	[^0-9A-F\.]	{
113135446Strhodes			BEGIN(INITIAL);
114135446Strhodes			unput(yytext[0]);
115135446Strhodes			if (strcmp(strbuf, ".") == 0)
116135446Strhodes				return (DOT);
117135446Strhodes			else {
118135446Strhodes				yylval.str = strbuf;
119135446Strhodes				return (NUMBER);
120135446Strhodes			}
121135446Strhodes		}
122135446Strhodes}
123135446Strhodes
124135446Strhodes"auto"		return (AUTO);
125135446Strhodes"break"		return (BREAK);
126135446Strhodes"continue"	return (CONTINUE);
127135446Strhodes"define"	return (DEFINE);
128135446Strhodes"else"		return (ELSE);
129135446Strhodes"ibase"		return (IBASE);
130135446Strhodes"if"		return (IF);
131135446Strhodes"last"		return (DOT);
132135446Strhodes"for"		return (FOR);
133135446Strhodes"length"	return (LENGTH);
134135446Strhodes"obase"		return (OBASE);
135135446Strhodes"print"		return (PRINT);
136135446Strhodes"quit"		return (QUIT);
137135446Strhodes"return"	return (RETURN);
138135446Strhodes"scale"		return (SCALE);
139135446Strhodes"sqrt"		return (SQRT);
140135446Strhodes"while"		return (WHILE);
141135446Strhodes
142135446Strhodes"^"		return (EXPONENT);
143135446Strhodes"*"		return (MULTIPLY);
144135446Strhodes"/"		return (DIVIDE);
145135446Strhodes"%"		return (REMAINDER);
146135446Strhodes
147135446Strhodes"!"		return (BOOL_NOT);
148135446Strhodes"&&"		return (BOOL_AND);
149135446Strhodes"||"		return (BOOL_OR);
150135446Strhodes
151135446Strhodes"+"		return (PLUS);
152135446Strhodes"-"		return (MINUS);
153135446Strhodes
154135446Strhodes"++"		return (INCR);
155135446Strhodes"--"		return (DECR);
156135446Strhodes
157135446Strhodes"="		yylval.str = ""; return (ASSIGN_OP);
158135446Strhodes"+="		yylval.str = "+"; return (ASSIGN_OP);
159135446Strhodes"-="		yylval.str = "-"; return (ASSIGN_OP);
160135446Strhodes"*="		yylval.str = "*"; return (ASSIGN_OP);
161135446Strhodes"/="		yylval.str = "/"; return (ASSIGN_OP);
162135446Strhodes"%="		yylval.str = "%"; return (ASSIGN_OP);
163135446Strhodes"^="		yylval.str = "^"; return (ASSIGN_OP);
164135446Strhodes
165135446Strhodes"=="		return (EQUALS);
166135446Strhodes"<="		return (LESS_EQ);
167135446Strhodes">="		return (GREATER_EQ);
168135446Strhodes"!="		return (UNEQUALS);
169135446Strhodes"<"		return (LESS);
170135446Strhodes">"		return (GREATER);
171135446Strhodes
172135446Strhodes","		return (COMMA);
173135446Strhodes";"		return (SEMICOLON);
174135446Strhodes
175135446Strhodes"("		return (LPAR);
176135446Strhodes")"		return (RPAR);
177135446Strhodes
178135446Strhodes"["		return (LBRACKET);
179135446Strhodes"]"		return (RBRACKET);
180135446Strhodes
181135446Strhodes"{"		return (LBRACE);
182135446Strhodes"}"		return (RBRACE);
183135446Strhodes
184135446Strhodes{ALPHA}{ALPHANUM}* {
185135446Strhodes			/* alloc an extra byte for the type marker */
186135446Strhodes			char *p = malloc(yyleng + 2);
187135446Strhodes			if (p == NULL)
188135446Strhodes				err(1, NULL);
189135446Strhodes			strlcpy(p, yytext, yyleng + 1);
190135446Strhodes			yylval.astr = p;
191135446Strhodes			return (LETTER);
192135446Strhodes		}
193135446Strhodes
194135446Strhodes\\\n		lineno++;
195135446Strhodes\n		lineno++; return (NEWLINE);
196135446Strhodes
197135446Strhodes#[^\n]*		;
198135446Strhodes[ \t]		;
199135446Strhodes<<EOF>>		return (QUIT);
200135446Strhodes.		yyerror("illegal character");
201135446Strhodes
202135446Strhodes%%
203135446Strhodes
204135446Strhodesstatic void
205135446Strhodesinit_strbuf(void)
206135446Strhodes{
207135446Strhodes
208135446Strhodes	if (strbuf == NULL) {
209135446Strhodes		strbuf = malloc(strbuf_sz);
210135446Strhodes		if (strbuf == NULL)
211135446Strhodes			err(1, NULL);
212135446Strhodes	}
213135446Strhodes	strbuf[0] = '\0';
214135446Strhodes}
215135446Strhodes
216135446Strhodesstatic void
217135446Strhodesadd_str(const char *str)
218135446Strhodes{
219135446Strhodes	size_t arglen;
220135446Strhodes
221135446Strhodes	arglen = strlen(str);
222135446Strhodes
223135446Strhodes	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
224135446Strhodes		size_t	 newsize;
225135446Strhodes		char	*p;
226135446Strhodes
227135446Strhodes		newsize = strbuf_sz + arglen + 1;
228135446Strhodes		p = realloc(strbuf, newsize);
229135446Strhodes		if (p == NULL) {
230135446Strhodes			free(strbuf);
231135446Strhodes			err(1, NULL);
232135446Strhodes		}
233135446Strhodes		strbuf_sz = newsize;
234135446Strhodes		strbuf = p;
235135446Strhodes	}
236135446Strhodes	strlcat(strbuf, str, strbuf_sz);
237135446Strhodes}
238135446Strhodes
239135446Strhodesint
240135446Strhodesyywrap(void)
241135446Strhodes{
242135446Strhodes	static YY_BUFFER_STATE buf;
243135446Strhodes	static int state;
244135446Strhodes
245135446Strhodes	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
246135446Strhodes		filename = sargv[fileindex++];
247135446Strhodes		yyin = fopen(filename, "r");
248135446Strhodes		lineno = 1;
249135446Strhodes		if (yyin == NULL)
250135446Strhodes			err(1, "cannot open %s", filename);
251135446Strhodes		return (0);
252135446Strhodes	}
253135446Strhodes	if (state == 0 && cmdexpr[0] != '\0') {
254135446Strhodes		buf = yy_scan_string(cmdexpr);
255135446Strhodes		state++;
256135446Strhodes		lineno = 1;
257135446Strhodes		filename = "command line";
258135446Strhodes		return (0);
259135446Strhodes	} else if (state == 1) {
260135446Strhodes		yy_delete_buffer(buf);
261135446Strhodes		free(cmdexpr);
262135446Strhodes		state++;
263135446Strhodes	}
264153816Sdougb	if (yyin != NULL && yyin != stdin)
265143731Sdougb		fclose(yyin);
266143731Sdougb	if (fileindex < sargc) {
267143731Sdougb		filename = sargv[fileindex++];
268143731Sdougb		yyin = fopen(filename, "r");
269143731Sdougb		lineno = 1;
270143731Sdougb		if (yyin == NULL)
271143731Sdougb			err(1, "cannot open %s", filename);
272143731Sdougb		return (0);
273143731Sdougb	} else if (fileindex == sargc) {
274143731Sdougb		fileindex++;
275143731Sdougb		yyin = stdin;
276143731Sdougb		lineno = 1;
277143731Sdougb		filename = "stdin";
278143731Sdougb		return (0);
279143731Sdougb	}
280143731Sdougb	return (1);
281143731Sdougb}
282135446Strhodes
283135446Strhodesstatic int
284135446Strhodesbc_yyinput(char *buf, int maxlen)
285135446Strhodes{
286135446Strhodes	int num;
287135446Strhodes	if (yyin == stdin && interactive) {
288135446Strhodes		const char *bp;
289135446Strhodes
290135446Strhodes		if ((bp = el_gets(el, &num)) == NULL || num == 0)
291135446Strhodes			return (0);
292135446Strhodes		if (num > maxlen) {
293135446Strhodes			el_push(el, (char *)(uintptr_t)(bp) + maxlen);
294135446Strhodes			num = maxlen;
295135446Strhodes		}
296135446Strhodes		memcpy(buf, bp, num);
297135446Strhodes		history(hist, &he, H_ENTER, bp);
298135446Strhodes	} else {
299135446Strhodes		int c = '*';
300135446Strhodes		for (num = 0; num < maxlen &&
301135446Strhodes		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
302135446Strhodes			buf[num] = (char) c;
303135446Strhodes		if (c == '\n')
304135446Strhodes			buf[num++] = (char) c;
305135446Strhodes		if (c == EOF && ferror(yyin))
306135446Strhodes			YY_FATAL_ERROR( "input in flex scanner failed" );
307135446Strhodes	}
308135446Strhodes	return (num);
309135446Strhodes}
310135446Strhodes
311135446Strhodes