1202719Sgabor%{
2264573Sdelphij/*      $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto 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>
27264573Sdelphij#include <signal.h>
28202719Sgabor#include <string.h>
29202719Sgabor#include <unistd.h>
30202719Sgabor
31202719Sgabor#include "extern.h"
32202719Sgabor#include "bc.h"
33202719Sgabor#include "pathnames.h"
34202719Sgabor
35264573Sdelphijint		lineno;
36264573Sdelphijbool		interactive;
37202719Sgabor
38203498SdelphijHistEvent	 he;
39203498SdelphijEditLine	*el;
40203498SdelphijHistory		*hist;
41203498Sdelphij
42202719Sgaborstatic char	*strbuf = NULL;
43264573Sdelphijstatic size_t	strbuf_sz = 1;
44264573Sdelphijstatic bool	dot_seen;
45264573Sdelphijstatic int	use_el;
46264573Sdelphijstatic volatile sig_atomic_t skipchars;
47202719Sgabor
48264573Sdelphijstatic void	init_strbuf(void);
49264573Sdelphijstatic void	add_str(const char *);
50264573Sdelphij
51203498Sdelphijstatic int	 bc_yyinput(char *, int);
52202719Sgabor
53250926Sjkim#define YY_DECL	int yylex(void)
54215704Sbrucec#define YY_NO_INPUT
55203498Sdelphij#undef YY_INPUT
56203498Sdelphij#define YY_INPUT(buf,retval,max) \
57203498Sdelphij	(retval = bc_yyinput(buf, max))
58264573Sdelphij
59202719Sgabor%}
60202719Sgabor
61202719Sgabor%option always-interactive
62202719Sgabor
63202719SgaborDIGIT		[0-9A-F]
64202719SgaborALPHA		[a-z_]
65202719SgaborALPHANUM	[a-z_0-9]
66202719Sgabor
67202719Sgabor%x		comment string number
68202719Sgabor
69202719Sgabor%%
70202719Sgabor
71202719Sgabor"/*"		BEGIN(comment);
72202719Sgabor<comment>{
73202719Sgabor	"*/"	BEGIN(INITIAL);
74202719Sgabor	\n	lineno++;
75202719Sgabor	\*	;
76202719Sgabor	[^*\n]+	;
77202719Sgabor	<<EOF>>	fatal("end of file in comment");
78202719Sgabor}
79202719Sgabor
80202719Sgabor\"		BEGIN(string); init_strbuf();
81202719Sgabor<string>{
82202719Sgabor	[^"\n\\\[\]]+	add_str(yytext);
83202719Sgabor	\[	add_str("\\[");
84202719Sgabor	\]	add_str("\\]");
85202719Sgabor	\\	add_str("\\\\");
86202719Sgabor	\n	add_str("\n"); lineno++;
87202719Sgabor	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
88202719Sgabor	<<EOF>>	fatal("end of file in string");
89202719Sgabor}
90202719Sgabor
91202719Sgabor{DIGIT}+	{
92202719Sgabor			BEGIN(number);
93202719Sgabor			dot_seen = false;
94202719Sgabor			init_strbuf();
95202719Sgabor			add_str(yytext);
96202719Sgabor		}
97202719Sgabor\.		{
98202719Sgabor			BEGIN(number);
99202719Sgabor			dot_seen = true;
100202719Sgabor			init_strbuf();
101202719Sgabor			add_str(".");
102202719Sgabor		}
103202719Sgabor<number>{
104202719Sgabor	{DIGIT}+	add_str(yytext);
105202719Sgabor	\.	{
106202719Sgabor			if (dot_seen) {
107202719Sgabor				BEGIN(INITIAL);
108202719Sgabor				yylval.str = strbuf;
109202719Sgabor				unput('.');
110264573Sdelphij				return NUMBER;
111202719Sgabor			} else {
112202719Sgabor				dot_seen = true;
113202719Sgabor				add_str(".");
114202719Sgabor			}
115202719Sgabor		}
116202719Sgabor	\\\n[ \t]*	lineno++;
117202719Sgabor	[^0-9A-F\.]	{
118202719Sgabor			BEGIN(INITIAL);
119202719Sgabor			unput(yytext[0]);
120202719Sgabor			if (strcmp(strbuf, ".") == 0)
121264573Sdelphij				return DOT;
122202719Sgabor			else {
123202719Sgabor				yylval.str = strbuf;
124264573Sdelphij				return NUMBER;
125202719Sgabor			}
126202719Sgabor		}
127202719Sgabor}
128202719Sgabor
129264573Sdelphij"auto"		return AUTO;
130264573Sdelphij"break"		return BREAK;
131264573Sdelphij"continue"	return CONTINUE;
132264573Sdelphij"define"	return DEFINE;
133264573Sdelphij"else"		return ELSE;
134264573Sdelphij"ibase"		return IBASE;
135264573Sdelphij"if"		return IF;
136264573Sdelphij"last"		return DOT;
137264573Sdelphij"for"		return FOR;
138264573Sdelphij"length"	return LENGTH;
139264573Sdelphij"obase"		return OBASE;
140264573Sdelphij"print"		return PRINT;
141264573Sdelphij"quit"		return QUIT;
142264573Sdelphij"return"	return RETURN;
143264573Sdelphij"scale"		return SCALE;
144264573Sdelphij"sqrt"		return SQRT;
145264573Sdelphij"while"		return WHILE;
146202719Sgabor
147264573Sdelphij"^"		return EXPONENT;
148264573Sdelphij"*"		return MULTIPLY;
149264573Sdelphij"/"		return DIVIDE;
150264573Sdelphij"%"		return REMAINDER;
151202719Sgabor
152264573Sdelphij"!"		return BOOL_NOT;
153264573Sdelphij"&&"		return BOOL_AND;
154264573Sdelphij"||"		return BOOL_OR;
155202719Sgabor
156264573Sdelphij"+"		return PLUS;
157264573Sdelphij"-"		return MINUS;
158202719Sgabor
159264573Sdelphij"++"		return INCR;
160264573Sdelphij"--"		return DECR;
161202719Sgabor
162264573Sdelphij"="		yylval.str = ""; return ASSIGN_OP;
163264573Sdelphij"+="		yylval.str = "+"; return ASSIGN_OP;
164264573Sdelphij"-="		yylval.str = "-"; return ASSIGN_OP;
165264573Sdelphij"*="		yylval.str = "*"; return ASSIGN_OP;
166264573Sdelphij"/="		yylval.str = "/"; return ASSIGN_OP;
167264573Sdelphij"%="		yylval.str = "%"; return ASSIGN_OP;
168264573Sdelphij"^="		yylval.str = "^"; return ASSIGN_OP;
169202719Sgabor
170264573Sdelphij"=="		return EQUALS;
171264573Sdelphij"<="		return LESS_EQ;
172264573Sdelphij">="		return GREATER_EQ;
173264573Sdelphij"!="		return UNEQUALS;
174264573Sdelphij"<"		return LESS;
175264573Sdelphij">"		return GREATER;
176202719Sgabor
177264573Sdelphij","		return COMMA;
178264573Sdelphij";"		return SEMICOLON;
179202719Sgabor
180264573Sdelphij"("		return LPAR;
181264573Sdelphij")"		return RPAR;
182202719Sgabor
183264573Sdelphij"["		return LBRACKET;
184264573Sdelphij"]"		return RBRACKET;
185202719Sgabor
186264573Sdelphij"{"		return LBRACE;
187264573Sdelphij"}"		return RBRACE;
188202719Sgabor
189202719Sgabor{ALPHA}{ALPHANUM}* {
190202719Sgabor			/* alloc an extra byte for the type marker */
191202719Sgabor			char *p = malloc(yyleng + 2);
192202719Sgabor			if (p == NULL)
193202719Sgabor				err(1, NULL);
194202719Sgabor			strlcpy(p, yytext, yyleng + 1);
195202719Sgabor			yylval.astr = p;
196264573Sdelphij			return LETTER;
197202719Sgabor		}
198202719Sgabor
199202719Sgabor\\\n		lineno++;
200264573Sdelphij\n		lineno++; return NEWLINE;
201202719Sgabor
202202719Sgabor#[^\n]*		;
203202719Sgabor[ \t]		;
204264573Sdelphij<<EOF>>		return QUIT;
205202719Sgabor.		yyerror("illegal character");
206202719Sgabor
207202719Sgabor%%
208202719Sgabor
209202719Sgaborstatic void
210202719Sgaborinit_strbuf(void)
211202719Sgabor{
212202719Sgabor	if (strbuf == NULL) {
213202719Sgabor		strbuf = malloc(strbuf_sz);
214202719Sgabor		if (strbuf == NULL)
215202719Sgabor			err(1, NULL);
216202719Sgabor	}
217202719Sgabor	strbuf[0] = '\0';
218202719Sgabor}
219202719Sgabor
220202719Sgaborstatic void
221202719Sgaboradd_str(const char *str)
222202719Sgabor{
223203443Sgabor	size_t arglen;
224202719Sgabor
225202719Sgabor	arglen = strlen(str);
226202719Sgabor
227202719Sgabor	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
228264573Sdelphij		size_t newsize;
229264573Sdelphij		char *p;
230202719Sgabor
231202719Sgabor		newsize = strbuf_sz + arglen + 1;
232202719Sgabor		p = realloc(strbuf, newsize);
233202719Sgabor		if (p == NULL) {
234202719Sgabor			free(strbuf);
235202719Sgabor			err(1, NULL);
236202719Sgabor		}
237202719Sgabor		strbuf_sz = newsize;
238202719Sgabor		strbuf = p;
239202719Sgabor	}
240202719Sgabor	strlcat(strbuf, str, strbuf_sz);
241202719Sgabor}
242202719Sgabor
243264573Sdelphij/* ARGSUSED */
244264573Sdelphijvoid
245264573Sdelphijabort_line(int sig __unused)
246264573Sdelphij{
247264573Sdelphij	static const char str1[] = "[\n]P\n";
248264573Sdelphij	static const char str2[] = "[^C\n]P\n";
249264573Sdelphij	int save_errno;
250264573Sdelphij	const LineInfo *info;
251264573Sdelphij
252264573Sdelphij	save_errno = errno;
253264573Sdelphij	if (use_el) {
254264573Sdelphij		write(STDOUT_FILENO, str2, sizeof(str2) - 1);
255264573Sdelphij		info = el_line(el);
256264573Sdelphij		skipchars = info->lastchar - info->buffer;
257264573Sdelphij	} else
258264573Sdelphij		write(STDOUT_FILENO, str1, sizeof(str1) - 1);
259264573Sdelphij	errno = save_errno;
260264573Sdelphij}
261264573Sdelphij
262264573Sdelphij/*
263264573Sdelphij * Avoid the echo of ^D by the default code of editline and take
264264573Sdelphij * into account skipchars to make ^D work when the cursor is at start of
265264573Sdelphij * line after a ^C.
266264573Sdelphij */
267264573Sdelphijunsigned char
268264573Sdelphijbc_eof(EditLine *e, int ch __unused)
269264573Sdelphij{
270264573Sdelphij	const struct lineinfo *info = el_line(e);
271264573Sdelphij
272264573Sdelphij	if (info->buffer + skipchars == info->cursor &&
273264573Sdelphij	    info->cursor == info->lastchar)
274264573Sdelphij		return (CC_EOF);
275264573Sdelphij	else
276264573Sdelphij		return (CC_ERROR);
277264573Sdelphij}
278264573Sdelphij
279202719Sgaborint
280202719Sgaboryywrap(void)
281202719Sgabor{
282264573Sdelphij	static int state;
283203443Sgabor	static YY_BUFFER_STATE buf;
284202719Sgabor
285202719Sgabor	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
286202719Sgabor		filename = sargv[fileindex++];
287202719Sgabor		yyin = fopen(filename, "r");
288202719Sgabor		lineno = 1;
289202719Sgabor		if (yyin == NULL)
290202719Sgabor			err(1, "cannot open %s", filename);
291202719Sgabor		return (0);
292202719Sgabor	}
293202719Sgabor	if (state == 0 && cmdexpr[0] != '\0') {
294202719Sgabor		buf = yy_scan_string(cmdexpr);
295202719Sgabor		state++;
296202719Sgabor		lineno = 1;
297202719Sgabor		filename = "command line";
298202719Sgabor		return (0);
299202719Sgabor	} else if (state == 1) {
300202719Sgabor		yy_delete_buffer(buf);
301202719Sgabor		free(cmdexpr);
302202719Sgabor		state++;
303202719Sgabor	}
304202719Sgabor	if (yyin != NULL && yyin != stdin)
305202719Sgabor		fclose(yyin);
306202719Sgabor	if (fileindex < sargc) {
307202719Sgabor		filename = sargv[fileindex++];
308202719Sgabor		yyin = fopen(filename, "r");
309202719Sgabor		lineno = 1;
310202719Sgabor		if (yyin == NULL)
311202719Sgabor			err(1, "cannot open %s", filename);
312202719Sgabor		return (0);
313202719Sgabor	} else if (fileindex == sargc) {
314202719Sgabor		fileindex++;
315202719Sgabor		yyin = stdin;
316264573Sdelphij		if (interactive) {
317264573Sdelphij			signal(SIGINT, abort_line);
318264573Sdelphij			signal(SIGTSTP, tstpcont);
319264573Sdelphij		}
320202719Sgabor		lineno = 1;
321202719Sgabor		filename = "stdin";
322202719Sgabor		return (0);
323202719Sgabor	}
324202719Sgabor	return (1);
325202719Sgabor}
326203498Sdelphij
327203498Sdelphijstatic int
328203498Sdelphijbc_yyinput(char *buf, int maxlen)
329203498Sdelphij{
330203498Sdelphij	int num;
331264573Sdelphij
332264573Sdelphij	if (el != NULL)
333264573Sdelphij		el_get(el, EL_EDITMODE, &use_el);
334264573Sdelphij
335264573Sdelphij	if (yyin == stdin && interactive && use_el) {
336203498Sdelphij		const char *bp;
337264573Sdelphij		sigset_t oset, nset;
338203498Sdelphij
339203498Sdelphij		if ((bp = el_gets(el, &num)) == NULL || num == 0)
340203498Sdelphij			return (0);
341264573Sdelphij		sigemptyset(&nset);
342264573Sdelphij		sigaddset(&nset, SIGINT);
343264573Sdelphij		sigprocmask(SIG_BLOCK, &nset, &oset);
344264573Sdelphij		if (skipchars < num) {
345264573Sdelphij			bp += skipchars;
346264573Sdelphij			num -= skipchars;
347264573Sdelphij		}
348264573Sdelphij		skipchars = 0;
349264573Sdelphij		sigprocmask(SIG_SETMASK, &oset, NULL);
350203498Sdelphij		if (num > maxlen) {
351264609Sbz			el_push(el, bp + maxlen);
352203498Sdelphij			num = maxlen;
353203498Sdelphij		}
354203498Sdelphij		memcpy(buf, bp, num);
355203498Sdelphij		history(hist, &he, H_ENTER, bp);
356264573Sdelphij		el_get(el, EL_EDITMODE, &use_el);
357203498Sdelphij	} else {
358203498Sdelphij		int c = '*';
359203498Sdelphij		for (num = 0; num < maxlen &&
360203498Sdelphij		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
361203498Sdelphij			buf[num] = (char) c;
362203498Sdelphij		if (c == '\n')
363203498Sdelphij			buf[num++] = (char) c;
364203498Sdelphij		if (c == EOF && ferror(yyin))
365203498Sdelphij			YY_FATAL_ERROR( "input in flex scanner failed" );
366203498Sdelphij	}
367203498Sdelphij	return (num);
368203498Sdelphij}
369203498Sdelphij
370264573Sdelphij
371