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$");
22202719Sgabor
23202719Sgabor#include <err.h>
24202719Sgabor#include <errno.h>
25203498Sdelphij#include <histedit.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
36203498Sdelphijbool		 interactive;
37203498SdelphijHistEvent	 he;
38203498SdelphijEditLine	*el;
39203498SdelphijHistory		*hist;
40203498Sdelphij
41202719Sgaborstatic char	*strbuf = NULL;
42202719Sgaborstatic size_t	 strbuf_sz = 1;
43202719Sgaborstatic bool	 dot_seen;
44202719Sgabor
45202719Sgaborstatic void	 init_strbuf(void);
46202719Sgaborstatic void	 add_str(const char *);
47203498Sdelphijstatic int	 bc_yyinput(char *, int);
48202719Sgabor
49252181Smarius#define YY_DECL	int yylex(void)
50215704Sbrucec#define YY_NO_INPUT
51203498Sdelphij#undef YY_INPUT
52203498Sdelphij#define YY_INPUT(buf,retval,max) \
53203498Sdelphij	(retval = bc_yyinput(buf, max))
54202719Sgabor%}
55202719Sgabor
56202719Sgabor%option always-interactive
57202719Sgabor
58202719SgaborDIGIT		[0-9A-F]
59202719SgaborALPHA		[a-z_]
60202719SgaborALPHANUM	[a-z_0-9]
61202719Sgabor
62202719Sgabor%x		comment string number
63202719Sgabor
64202719Sgabor%%
65202719Sgabor
66202719Sgabor"/*"		BEGIN(comment);
67202719Sgabor<comment>{
68202719Sgabor	"*/"	BEGIN(INITIAL);
69202719Sgabor	\n	lineno++;
70202719Sgabor	\*	;
71202719Sgabor	[^*\n]+	;
72202719Sgabor	<<EOF>>	fatal("end of file in comment");
73202719Sgabor}
74202719Sgabor
75202719Sgabor\"		BEGIN(string); init_strbuf();
76202719Sgabor<string>{
77202719Sgabor	[^"\n\\\[\]]+	add_str(yytext);
78202719Sgabor	\[	add_str("\\[");
79202719Sgabor	\]	add_str("\\]");
80202719Sgabor	\\	add_str("\\\\");
81202719Sgabor	\n	add_str("\n"); lineno++;
82202719Sgabor	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
83202719Sgabor	<<EOF>>	fatal("end of file in string");
84202719Sgabor}
85202719Sgabor
86202719Sgabor{DIGIT}+	{
87202719Sgabor			BEGIN(number);
88202719Sgabor			dot_seen = false;
89202719Sgabor			init_strbuf();
90202719Sgabor			add_str(yytext);
91202719Sgabor		}
92202719Sgabor\.		{
93202719Sgabor			BEGIN(number);
94202719Sgabor			dot_seen = true;
95202719Sgabor			init_strbuf();
96202719Sgabor			add_str(".");
97202719Sgabor		}
98202719Sgabor<number>{
99202719Sgabor	{DIGIT}+	add_str(yytext);
100202719Sgabor	\.	{
101202719Sgabor			if (dot_seen) {
102202719Sgabor				BEGIN(INITIAL);
103202719Sgabor				yylval.str = strbuf;
104202719Sgabor				unput('.');
105202719Sgabor				return (NUMBER);
106202719Sgabor			} else {
107202719Sgabor				dot_seen = true;
108202719Sgabor				add_str(".");
109202719Sgabor			}
110202719Sgabor		}
111202719Sgabor	\\\n[ \t]*	lineno++;
112202719Sgabor	[^0-9A-F\.]	{
113202719Sgabor			BEGIN(INITIAL);
114202719Sgabor			unput(yytext[0]);
115202719Sgabor			if (strcmp(strbuf, ".") == 0)
116202719Sgabor				return (DOT);
117202719Sgabor			else {
118202719Sgabor				yylval.str = strbuf;
119202719Sgabor				return (NUMBER);
120202719Sgabor			}
121202719Sgabor		}
122202719Sgabor}
123202719Sgabor
124202719Sgabor"auto"		return (AUTO);
125202719Sgabor"break"		return (BREAK);
126202719Sgabor"continue"	return (CONTINUE);
127202719Sgabor"define"	return (DEFINE);
128202719Sgabor"else"		return (ELSE);
129202719Sgabor"ibase"		return (IBASE);
130202719Sgabor"if"		return (IF);
131202719Sgabor"last"		return (DOT);
132202719Sgabor"for"		return (FOR);
133202719Sgabor"length"	return (LENGTH);
134202719Sgabor"obase"		return (OBASE);
135202719Sgabor"print"		return (PRINT);
136202719Sgabor"quit"		return (QUIT);
137202719Sgabor"return"	return (RETURN);
138202719Sgabor"scale"		return (SCALE);
139202719Sgabor"sqrt"		return (SQRT);
140202719Sgabor"while"		return (WHILE);
141202719Sgabor
142202719Sgabor"^"		return (EXPONENT);
143202719Sgabor"*"		return (MULTIPLY);
144202719Sgabor"/"		return (DIVIDE);
145202719Sgabor"%"		return (REMAINDER);
146202719Sgabor
147202719Sgabor"!"		return (BOOL_NOT);
148202719Sgabor"&&"		return (BOOL_AND);
149202719Sgabor"||"		return (BOOL_OR);
150202719Sgabor
151202719Sgabor"+"		return (PLUS);
152202719Sgabor"-"		return (MINUS);
153202719Sgabor
154202719Sgabor"++"		return (INCR);
155202719Sgabor"--"		return (DECR);
156202719Sgabor
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"^="		yylval.str = "^"; return (ASSIGN_OP);
164202719Sgabor
165202719Sgabor"=="		return (EQUALS);
166202719Sgabor"<="		return (LESS_EQ);
167202719Sgabor">="		return (GREATER_EQ);
168202719Sgabor"!="		return (UNEQUALS);
169202719Sgabor"<"		return (LESS);
170202719Sgabor">"		return (GREATER);
171202719Sgabor
172202719Sgabor","		return (COMMA);
173202719Sgabor";"		return (SEMICOLON);
174202719Sgabor
175202719Sgabor"("		return (LPAR);
176202719Sgabor")"		return (RPAR);
177202719Sgabor
178202719Sgabor"["		return (LBRACKET);
179202719Sgabor"]"		return (RBRACKET);
180202719Sgabor
181202719Sgabor"{"		return (LBRACE);
182202719Sgabor"}"		return (RBRACE);
183202719Sgabor
184202719Sgabor{ALPHA}{ALPHANUM}* {
185202719Sgabor			/* alloc an extra byte for the type marker */
186202719Sgabor			char *p = malloc(yyleng + 2);
187202719Sgabor			if (p == NULL)
188202719Sgabor				err(1, NULL);
189202719Sgabor			strlcpy(p, yytext, yyleng + 1);
190202719Sgabor			yylval.astr = p;
191202719Sgabor			return (LETTER);
192202719Sgabor		}
193202719Sgabor
194202719Sgabor\\\n		lineno++;
195202719Sgabor\n		lineno++; return (NEWLINE);
196202719Sgabor
197202719Sgabor#[^\n]*		;
198202719Sgabor[ \t]		;
199202719Sgabor<<EOF>>		return (QUIT);
200202719Sgabor.		yyerror("illegal character");
201202719Sgabor
202202719Sgabor%%
203202719Sgabor
204202719Sgaborstatic void
205202719Sgaborinit_strbuf(void)
206202719Sgabor{
207203443Sgabor
208202719Sgabor	if (strbuf == NULL) {
209202719Sgabor		strbuf = malloc(strbuf_sz);
210202719Sgabor		if (strbuf == NULL)
211202719Sgabor			err(1, NULL);
212202719Sgabor	}
213202719Sgabor	strbuf[0] = '\0';
214202719Sgabor}
215202719Sgabor
216202719Sgaborstatic void
217202719Sgaboradd_str(const char *str)
218202719Sgabor{
219203443Sgabor	size_t arglen;
220202719Sgabor
221202719Sgabor	arglen = strlen(str);
222202719Sgabor
223202719Sgabor	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
224202719Sgabor		size_t	 newsize;
225202719Sgabor		char	*p;
226202719Sgabor
227202719Sgabor		newsize = strbuf_sz + arglen + 1;
228202719Sgabor		p = realloc(strbuf, newsize);
229202719Sgabor		if (p == NULL) {
230202719Sgabor			free(strbuf);
231202719Sgabor			err(1, NULL);
232202719Sgabor		}
233202719Sgabor		strbuf_sz = newsize;
234202719Sgabor		strbuf = p;
235202719Sgabor	}
236202719Sgabor	strlcat(strbuf, str, strbuf_sz);
237202719Sgabor}
238202719Sgabor
239202719Sgaborint
240202719Sgaboryywrap(void)
241202719Sgabor{
242203443Sgabor	static YY_BUFFER_STATE buf;
243203443Sgabor	static int state;
244202719Sgabor
245202719Sgabor	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
246202719Sgabor		filename = sargv[fileindex++];
247202719Sgabor		yyin = fopen(filename, "r");
248202719Sgabor		lineno = 1;
249202719Sgabor		if (yyin == NULL)
250202719Sgabor			err(1, "cannot open %s", filename);
251202719Sgabor		return (0);
252202719Sgabor	}
253202719Sgabor	if (state == 0 && cmdexpr[0] != '\0') {
254202719Sgabor		buf = yy_scan_string(cmdexpr);
255202719Sgabor		state++;
256202719Sgabor		lineno = 1;
257202719Sgabor		filename = "command line";
258202719Sgabor		return (0);
259202719Sgabor	} else if (state == 1) {
260202719Sgabor		yy_delete_buffer(buf);
261202719Sgabor		free(cmdexpr);
262202719Sgabor		state++;
263202719Sgabor	}
264202719Sgabor	if (yyin != NULL && yyin != stdin)
265202719Sgabor		fclose(yyin);
266202719Sgabor	if (fileindex < sargc) {
267202719Sgabor		filename = sargv[fileindex++];
268202719Sgabor		yyin = fopen(filename, "r");
269202719Sgabor		lineno = 1;
270202719Sgabor		if (yyin == NULL)
271202719Sgabor			err(1, "cannot open %s", filename);
272202719Sgabor		return (0);
273202719Sgabor	} else if (fileindex == sargc) {
274202719Sgabor		fileindex++;
275202719Sgabor		yyin = stdin;
276202719Sgabor		lineno = 1;
277202719Sgabor		filename = "stdin";
278202719Sgabor		return (0);
279202719Sgabor	}
280202719Sgabor	return (1);
281202719Sgabor}
282203498Sdelphij
283203498Sdelphijstatic int
284203498Sdelphijbc_yyinput(char *buf, int maxlen)
285203498Sdelphij{
286203498Sdelphij	int num;
287203531Sdelphij	if (yyin == stdin && interactive) {
288203498Sdelphij		const char *bp;
289203498Sdelphij
290203498Sdelphij		if ((bp = el_gets(el, &num)) == NULL || num == 0)
291203498Sdelphij			return (0);
292203498Sdelphij		if (num > maxlen) {
293203498Sdelphij			el_push(el, (char *)(uintptr_t)(bp) + maxlen);
294203498Sdelphij			num = maxlen;
295203498Sdelphij		}
296203498Sdelphij		memcpy(buf, bp, num);
297203498Sdelphij		history(hist, &he, H_ENTER, bp);
298203498Sdelphij	} else {
299203498Sdelphij		int c = '*';
300203498Sdelphij		for (num = 0; num < maxlen &&
301203498Sdelphij		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
302203498Sdelphij			buf[num] = (char) c;
303203498Sdelphij		if (c == '\n')
304203498Sdelphij			buf[num++] = (char) c;
305203498Sdelphij		if (c == EOF && ferror(yyin))
306203498Sdelphij			YY_FATAL_ERROR( "input in flex scanner failed" );
307203498Sdelphij	}
308203498Sdelphij	return (num);
309203498Sdelphij}
310203498Sdelphij
311