scan.l revision 265533
1121663Sharti%{
2121663Sharti/*      $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto Exp $	*/
3121663Sharti
4121663Sharti/*
5121663Sharti * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6131823Sharti *
7131823Sharti * Permission to use, copy, modify, and distribute this software for any
8121663Sharti * purpose with or without fee is hereby granted, provided that the above
9121663Sharti * copyright notice and this permission notice appear in all copies.
10121663Sharti *
11121663Sharti * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12121663Sharti * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13121663Sharti * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14121663Sharti * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15121663Sharti * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16121663Sharti * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17121663Sharti * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18121663Sharti */
19121663Sharti
20121663Sharti#include <sys/cdefs.h>
21121663Sharti__FBSDID("$FreeBSD: stable/10/usr.bin/bc/scan.l 265533 2014-05-07 08:06:54Z delphij $");
22121663Sharti
23121663Sharti#include <err.h>
24121663Sharti#include <errno.h>
25121663Sharti#include <histedit.h>
26121663Sharti#include <stdbool.h>
27121663Sharti#include <signal.h>
28121663Sharti#include <string.h>
29146532Sharti#include <unistd.h>
30121663Sharti
31121663Sharti#include "extern.h"
32121663Sharti#include "bc.h"
33121663Sharti#include "pathnames.h"
34121663Sharti
35121663Shartiint		lineno;
36121663Shartibool		interactive;
37121663Sharti
38121663ShartiHistEvent	 he;
39121663ShartiEditLine	*el;
40121663ShartiHistory		*hist;
41121663Sharti
42121663Shartistatic char	*strbuf = NULL;
43121663Shartistatic size_t	strbuf_sz = 1;
44121663Shartistatic bool	dot_seen;
45121663Shartistatic int	use_el;
46121663Shartistatic volatile sig_atomic_t skipchars;
47121663Sharti
48121663Shartistatic void	init_strbuf(void);
49121663Shartistatic void	add_str(const char *);
50121663Sharti
51121663Shartistatic int	 bc_yyinput(char *, int);
52121663Sharti
53121663Sharti#define YY_DECL	int yylex(void)
54121663Sharti#define YY_NO_INPUT
55121663Sharti#undef YY_INPUT
56121663Sharti#define YY_INPUT(buf,retval,max) \
57121663Sharti	(retval = bc_yyinput(buf, max))
58121663Sharti
59121663Sharti%}
60121663Sharti
61121663Sharti%option always-interactive
62121663Sharti
63121663ShartiDIGIT		[0-9A-F]
64121663ShartiALPHA		[a-z_]
65121663ShartiALPHANUM	[a-z_0-9]
66135923Strhodes
67121663Sharti%x		comment string number
68135923Strhodes
69121663Sharti%%
70121663Sharti
71121663Sharti"/*"		BEGIN(comment);
72121663Sharti<comment>{
73121663Sharti	"*/"	BEGIN(INITIAL);
74121663Sharti	\n	lineno++;
75121663Sharti	\*	;
76121663Sharti	[^*\n]+	;
77121663Sharti	<<EOF>>	fatal("end of file in comment");
78121663Sharti}
79121663Sharti
80121663Sharti\"		BEGIN(string); init_strbuf();
81121663Sharti<string>{
82121663Sharti	[^"\n\\\[\]]+	add_str(yytext);
83121663Sharti	\[	add_str("\\[");
84121663Sharti	\]	add_str("\\]");
85121663Sharti	\\	add_str("\\\\");
86121663Sharti	\n	add_str("\n"); lineno++;
87121663Sharti	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
88121663Sharti	<<EOF>>	fatal("end of file in string");
89121663Sharti}
90121663Sharti
91121663Sharti{DIGIT}+	{
92121663Sharti			BEGIN(number);
93121663Sharti			dot_seen = false;
94121663Sharti			init_strbuf();
95121663Sharti			add_str(yytext);
96121663Sharti		}
97121663Sharti\.		{
98121663Sharti			BEGIN(number);
99121663Sharti			dot_seen = true;
100121663Sharti			init_strbuf();
101121663Sharti			add_str(".");
102121663Sharti		}
103121663Sharti<number>{
104121663Sharti	{DIGIT}+	add_str(yytext);
105121663Sharti	\.	{
106121663Sharti			if (dot_seen) {
107121663Sharti				BEGIN(INITIAL);
108121663Sharti				yylval.str = strbuf;
109121663Sharti				unput('.');
110121663Sharti				return NUMBER;
111121663Sharti			} else {
112121663Sharti				dot_seen = true;
113121663Sharti				add_str(".");
114121663Sharti			}
115121663Sharti		}
116121663Sharti	\\\n[ \t]*	lineno++;
117121663Sharti	[^0-9A-F\.]	{
118121663Sharti			BEGIN(INITIAL);
119121663Sharti			unput(yytext[0]);
120121663Sharti			if (strcmp(strbuf, ".") == 0)
121121663Sharti				return DOT;
122121663Sharti			else {
123121663Sharti				yylval.str = strbuf;
124121663Sharti				return NUMBER;
125121663Sharti			}
126121663Sharti		}
127121663Sharti}
128121663Sharti
129121663Sharti"auto"		return AUTO;
130121663Sharti"break"		return BREAK;
131121663Sharti"continue"	return CONTINUE;
132121663Sharti"define"	return DEFINE;
133121663Sharti"else"		return ELSE;
134121663Sharti"ibase"		return IBASE;
135121663Sharti"if"		return IF;
136121663Sharti"last"		return DOT;
137121663Sharti"for"		return FOR;
138121663Sharti"length"	return LENGTH;
139121663Sharti"obase"		return OBASE;
140121663Sharti"print"		return PRINT;
141121663Sharti"quit"		return QUIT;
142121663Sharti"return"	return RETURN;
143121663Sharti"scale"		return SCALE;
144121663Sharti"sqrt"		return SQRT;
145121663Sharti"while"		return WHILE;
146121663Sharti
147121663Sharti"^"		return EXPONENT;
148121663Sharti"*"		return MULTIPLY;
149121663Sharti"/"		return DIVIDE;
150121663Sharti"%"		return REMAINDER;
151121663Sharti
152121663Sharti"!"		return BOOL_NOT;
153121663Sharti"&&"		return BOOL_AND;
154121663Sharti"||"		return BOOL_OR;
155121663Sharti
156121663Sharti"+"		return PLUS;
157135923Strhodes"-"		return MINUS;
158135923Strhodes
159135923Strhodes"++"		return INCR;
160121663Sharti"--"		return DECR;
161135923Strhodes
162121663Sharti"="		yylval.str = ""; return ASSIGN_OP;
163121663Sharti"+="		yylval.str = "+"; return ASSIGN_OP;
164121663Sharti"-="		yylval.str = "-"; return ASSIGN_OP;
165121663Sharti"*="		yylval.str = "*"; return ASSIGN_OP;
166121663Sharti"/="		yylval.str = "/"; return ASSIGN_OP;
167121663Sharti"%="		yylval.str = "%"; return ASSIGN_OP;
168121663Sharti"^="		yylval.str = "^"; return ASSIGN_OP;
169121663Sharti
170121663Sharti"=="		return EQUALS;
171121663Sharti"<="		return LESS_EQ;
172121663Sharti">="		return GREATER_EQ;
173121663Sharti"!="		return UNEQUALS;
174121663Sharti"<"		return LESS;
175121663Sharti">"		return GREATER;
176121663Sharti
177121663Sharti","		return COMMA;
178121663Sharti";"		return SEMICOLON;
179121663Sharti
180121663Sharti"("		return LPAR;
181121663Sharti")"		return RPAR;
182121663Sharti
183121663Sharti"["		return LBRACKET;
184121663Sharti"]"		return RBRACKET;
185121663Sharti
186121663Sharti"{"		return LBRACE;
187121663Sharti"}"		return RBRACE;
188121663Sharti
189121663Sharti{ALPHA}{ALPHANUM}* {
190121663Sharti			/* alloc an extra byte for the type marker */
191121663Sharti			char *p = malloc(yyleng + 2);
192121663Sharti			if (p == NULL)
193121663Sharti				err(1, NULL);
194121663Sharti			strlcpy(p, yytext, yyleng + 1);
195121663Sharti			yylval.astr = p;
196121663Sharti			return LETTER;
197121663Sharti		}
198121663Sharti
199121663Sharti\\\n		lineno++;
200121663Sharti\n		lineno++; return NEWLINE;
201121663Sharti
202121663Sharti#[^\n]*		;
203121663Sharti[ \t]		;
204121663Sharti<<EOF>>		return QUIT;
205121663Sharti.		yyerror("illegal character");
206121663Sharti
207121663Sharti%%
208121663Sharti
209121663Shartistatic void
210121663Shartiinit_strbuf(void)
211121663Sharti{
212121663Sharti	if (strbuf == NULL) {
213121663Sharti		strbuf = malloc(strbuf_sz);
214121663Sharti		if (strbuf == NULL)
215121663Sharti			err(1, NULL);
216121663Sharti	}
217121663Sharti	strbuf[0] = '\0';
218121663Sharti}
219121663Sharti
220135923Strhodesstatic void
221135923Strhodesadd_str(const char *str)
222135923Strhodes{
223121663Sharti	size_t arglen;
224135923Strhodes
225121663Sharti	arglen = strlen(str);
226121663Sharti
227121663Sharti	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
228121663Sharti		size_t newsize;
229121663Sharti		char *p;
230121663Sharti
231121663Sharti		newsize = strbuf_sz + arglen + 1;
232121663Sharti		p = realloc(strbuf, newsize);
233121663Sharti		if (p == NULL) {
234121663Sharti			free(strbuf);
235121663Sharti			err(1, NULL);
236121663Sharti		}
237121663Sharti		strbuf_sz = newsize;
238121663Sharti		strbuf = p;
239121663Sharti	}
240121663Sharti	strlcat(strbuf, str, strbuf_sz);
241121663Sharti}
242121663Sharti
243121663Sharti/* ARGSUSED */
244121663Shartivoid
245121663Shartiabort_line(int sig __unused)
246121663Sharti{
247121663Sharti	static const char str1[] = "[\n]P\n";
248121663Sharti	static const char str2[] = "[^C\n]P\n";
249121663Sharti	int save_errno;
250121663Sharti	const LineInfo *info;
251121663Sharti
252121663Sharti	save_errno = errno;
253121663Sharti	if (use_el) {
254121663Sharti		write(STDOUT_FILENO, str2, sizeof(str2) - 1);
255121663Sharti		info = el_line(el);
256121663Sharti		skipchars = info->lastchar - info->buffer;
257121663Sharti	} else
258121663Sharti		write(STDOUT_FILENO, str1, sizeof(str1) - 1);
259121663Sharti	errno = save_errno;
260121663Sharti}
261121663Sharti
262121663Sharti/*
263121663Sharti * Avoid the echo of ^D by the default code of editline and take
264121663Sharti * into account skipchars to make ^D work when the cursor is at start of
265121663Sharti * line after a ^C.
266121663Sharti */
267121663Shartiunsigned char
268121663Shartibc_eof(EditLine *e, int ch __unused)
269121663Sharti{
270121663Sharti	const struct lineinfo *info = el_line(e);
271121663Sharti
272121663Sharti	if (info->buffer + skipchars == info->cursor &&
273121663Sharti	    info->cursor == info->lastchar)
274121663Sharti		return (CC_EOF);
275121663Sharti	else
276121663Sharti		return (CC_ERROR);
277121663Sharti}
278121663Sharti
279121663Shartiint
280121663Shartiyywrap(void)
281121663Sharti{
282121663Sharti	static int state;
283121663Sharti	static YY_BUFFER_STATE buf;
284121663Sharti
285121663Sharti	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
286121663Sharti		filename = sargv[fileindex++];
287121663Sharti		yyin = fopen(filename, "r");
288121663Sharti		lineno = 1;
289121663Sharti		if (yyin == NULL)
290121663Sharti			err(1, "cannot open %s", filename);
291121663Sharti		return (0);
292121663Sharti	}
293121663Sharti	if (state == 0 && cmdexpr[0] != '\0') {
294121663Sharti		buf = yy_scan_string(cmdexpr);
295121663Sharti		state++;
296121663Sharti		lineno = 1;
297121663Sharti		filename = "command line";
298121663Sharti		return (0);
299121663Sharti	} else if (state == 1) {
300121663Sharti		yy_delete_buffer(buf);
301121663Sharti		free(cmdexpr);
302121663Sharti		state++;
303121663Sharti	}
304121663Sharti	if (yyin != NULL && yyin != stdin)
305121663Sharti		fclose(yyin);
306121663Sharti	if (fileindex < sargc) {
307121663Sharti		filename = sargv[fileindex++];
308121663Sharti		yyin = fopen(filename, "r");
309121663Sharti		lineno = 1;
310121663Sharti		if (yyin == NULL)
311121663Sharti			err(1, "cannot open %s", filename);
312121663Sharti		return (0);
313121663Sharti	} else if (fileindex == sargc) {
314121663Sharti		fileindex++;
315121663Sharti		yyin = stdin;
316121663Sharti		if (interactive) {
317121663Sharti			signal(SIGINT, abort_line);
318121663Sharti			signal(SIGTSTP, tstpcont);
319121663Sharti		}
320121663Sharti		lineno = 1;
321121663Sharti		filename = "stdin";
322121663Sharti		return (0);
323121663Sharti	}
324121663Sharti	return (1);
325121663Sharti}
326121663Sharti
327121663Shartistatic int
328121663Shartibc_yyinput(char *buf, int maxlen)
329121663Sharti{
330121663Sharti	int num;
331121663Sharti
332121663Sharti	if (el != NULL)
333121663Sharti		el_get(el, EL_EDITMODE, &use_el);
334121663Sharti
335121663Sharti	if (yyin == stdin && interactive && use_el) {
336121663Sharti		const char *bp;
337121663Sharti		sigset_t oset, nset;
338121663Sharti
339121663Sharti		if ((bp = el_gets(el, &num)) == NULL || num == 0)
340121663Sharti			return (0);
341121663Sharti		sigemptyset(&nset);
342121663Sharti		sigaddset(&nset, SIGINT);
343121663Sharti		sigprocmask(SIG_BLOCK, &nset, &oset);
344121663Sharti		if (skipchars < num) {
345121663Sharti			bp += skipchars;
346121663Sharti			num -= skipchars;
347121663Sharti		}
348121663Sharti		skipchars = 0;
349121663Sharti		sigprocmask(SIG_SETMASK, &oset, NULL);
350121663Sharti		if (num > maxlen) {
351121663Sharti			el_push(el, bp + maxlen);
352121663Sharti			num = maxlen;
353121663Sharti		}
354121663Sharti		memcpy(buf, bp, num);
355121663Sharti		history(hist, &he, H_ENTER, bp);
356121663Sharti		el_get(el, EL_EDITMODE, &use_el);
357121663Sharti	} else {
358121663Sharti		int c = '*';
359121663Sharti		for (num = 0; num < maxlen &&
360121663Sharti		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
361121663Sharti			buf[num] = (char) c;
362121663Sharti		if (c == '\n')
363121663Sharti			buf[num++] = (char) c;
364121663Sharti		if (c == EOF && ferror(yyin))
365121663Sharti			YY_FATAL_ERROR( "input in flex scanner failed" );
366121663Sharti	}
367121663Sharti	return (num);
368121663Sharti}
369121663Sharti
370121663Sharti
371121663Sharti