1%{
2/*      $OpenBSD: scan.l,v 1.23 2009/10/27 23:59:36 deraadt Exp $	*/
3
4/*
5 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/cdefs.h>
21__FBSDID("$FreeBSD$");
22
23#include <err.h>
24#include <errno.h>
25#include <histedit.h>
26#include <stdbool.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "extern.h"
31#include "bc.h"
32#include "pathnames.h"
33
34int		 lineno;
35
36bool		 interactive;
37HistEvent	 he;
38EditLine	*el;
39History		*hist;
40
41static char	*strbuf = NULL;
42static size_t	 strbuf_sz = 1;
43static bool	 dot_seen;
44
45static void	 init_strbuf(void);
46static void	 add_str(const char *);
47static int	 bc_yyinput(char *, int);
48
49#define YY_DECL	int yylex(void)
50#define YY_NO_INPUT
51#undef YY_INPUT
52#define YY_INPUT(buf,retval,max) \
53	(retval = bc_yyinput(buf, max))
54%}
55
56%option always-interactive
57
58DIGIT		[0-9A-F]
59ALPHA		[a-z_]
60ALPHANUM	[a-z_0-9]
61
62%x		comment string number
63
64%%
65
66"/*"		BEGIN(comment);
67<comment>{
68	"*/"	BEGIN(INITIAL);
69	\n	lineno++;
70	\*	;
71	[^*\n]+	;
72	<<EOF>>	fatal("end of file in comment");
73}
74
75\"		BEGIN(string); init_strbuf();
76<string>{
77	[^"\n\\\[\]]+	add_str(yytext);
78	\[	add_str("\\[");
79	\]	add_str("\\]");
80	\\	add_str("\\\\");
81	\n	add_str("\n"); lineno++;
82	\"	BEGIN(INITIAL); yylval.str = strbuf; return STRING;
83	<<EOF>>	fatal("end of file in string");
84}
85
86{DIGIT}+	{
87			BEGIN(number);
88			dot_seen = false;
89			init_strbuf();
90			add_str(yytext);
91		}
92\.		{
93			BEGIN(number);
94			dot_seen = true;
95			init_strbuf();
96			add_str(".");
97		}
98<number>{
99	{DIGIT}+	add_str(yytext);
100	\.	{
101			if (dot_seen) {
102				BEGIN(INITIAL);
103				yylval.str = strbuf;
104				unput('.');
105				return (NUMBER);
106			} else {
107				dot_seen = true;
108				add_str(".");
109			}
110		}
111	\\\n[ \t]*	lineno++;
112	[^0-9A-F\.]	{
113			BEGIN(INITIAL);
114			unput(yytext[0]);
115			if (strcmp(strbuf, ".") == 0)
116				return (DOT);
117			else {
118				yylval.str = strbuf;
119				return (NUMBER);
120			}
121		}
122}
123
124"auto"		return (AUTO);
125"break"		return (BREAK);
126"continue"	return (CONTINUE);
127"define"	return (DEFINE);
128"else"		return (ELSE);
129"ibase"		return (IBASE);
130"if"		return (IF);
131"last"		return (DOT);
132"for"		return (FOR);
133"length"	return (LENGTH);
134"obase"		return (OBASE);
135"print"		return (PRINT);
136"quit"		return (QUIT);
137"return"	return (RETURN);
138"scale"		return (SCALE);
139"sqrt"		return (SQRT);
140"while"		return (WHILE);
141
142"^"		return (EXPONENT);
143"*"		return (MULTIPLY);
144"/"		return (DIVIDE);
145"%"		return (REMAINDER);
146
147"!"		return (BOOL_NOT);
148"&&"		return (BOOL_AND);
149"||"		return (BOOL_OR);
150
151"+"		return (PLUS);
152"-"		return (MINUS);
153
154"++"		return (INCR);
155"--"		return (DECR);
156
157"="		yylval.str = ""; return (ASSIGN_OP);
158"+="		yylval.str = "+"; return (ASSIGN_OP);
159"-="		yylval.str = "-"; return (ASSIGN_OP);
160"*="		yylval.str = "*"; return (ASSIGN_OP);
161"/="		yylval.str = "/"; return (ASSIGN_OP);
162"%="		yylval.str = "%"; return (ASSIGN_OP);
163"^="		yylval.str = "^"; return (ASSIGN_OP);
164
165"=="		return (EQUALS);
166"<="		return (LESS_EQ);
167">="		return (GREATER_EQ);
168"!="		return (UNEQUALS);
169"<"		return (LESS);
170">"		return (GREATER);
171
172","		return (COMMA);
173";"		return (SEMICOLON);
174
175"("		return (LPAR);
176")"		return (RPAR);
177
178"["		return (LBRACKET);
179"]"		return (RBRACKET);
180
181"{"		return (LBRACE);
182"}"		return (RBRACE);
183
184{ALPHA}{ALPHANUM}* {
185			/* alloc an extra byte for the type marker */
186			char *p = malloc(yyleng + 2);
187			if (p == NULL)
188				err(1, NULL);
189			strlcpy(p, yytext, yyleng + 1);
190			yylval.astr = p;
191			return (LETTER);
192		}
193
194\\\n		lineno++;
195\n		lineno++; return (NEWLINE);
196
197#[^\n]*		;
198[ \t]		;
199<<EOF>>		return (QUIT);
200.		yyerror("illegal character");
201
202%%
203
204static void
205init_strbuf(void)
206{
207
208	if (strbuf == NULL) {
209		strbuf = malloc(strbuf_sz);
210		if (strbuf == NULL)
211			err(1, NULL);
212	}
213	strbuf[0] = '\0';
214}
215
216static void
217add_str(const char *str)
218{
219	size_t arglen;
220
221	arglen = strlen(str);
222
223	if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
224		size_t	 newsize;
225		char	*p;
226
227		newsize = strbuf_sz + arglen + 1;
228		p = realloc(strbuf, newsize);
229		if (p == NULL) {
230			free(strbuf);
231			err(1, NULL);
232		}
233		strbuf_sz = newsize;
234		strbuf = p;
235	}
236	strlcat(strbuf, str, strbuf_sz);
237}
238
239int
240yywrap(void)
241{
242	static YY_BUFFER_STATE buf;
243	static int state;
244
245	if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
246		filename = sargv[fileindex++];
247		yyin = fopen(filename, "r");
248		lineno = 1;
249		if (yyin == NULL)
250			err(1, "cannot open %s", filename);
251		return (0);
252	}
253	if (state == 0 && cmdexpr[0] != '\0') {
254		buf = yy_scan_string(cmdexpr);
255		state++;
256		lineno = 1;
257		filename = "command line";
258		return (0);
259	} else if (state == 1) {
260		yy_delete_buffer(buf);
261		free(cmdexpr);
262		state++;
263	}
264	if (yyin != NULL && yyin != stdin)
265		fclose(yyin);
266	if (fileindex < sargc) {
267		filename = sargv[fileindex++];
268		yyin = fopen(filename, "r");
269		lineno = 1;
270		if (yyin == NULL)
271			err(1, "cannot open %s", filename);
272		return (0);
273	} else if (fileindex == sargc) {
274		fileindex++;
275		yyin = stdin;
276		lineno = 1;
277		filename = "stdin";
278		return (0);
279	}
280	return (1);
281}
282
283static int
284bc_yyinput(char *buf, int maxlen)
285{
286	int num;
287	if (yyin == stdin && interactive) {
288		const char *bp;
289
290		if ((bp = el_gets(el, &num)) == NULL || num == 0)
291			return (0);
292		if (num > maxlen) {
293			el_push(el, (char *)(uintptr_t)(bp) + maxlen);
294			num = maxlen;
295		}
296		memcpy(buf, bp, num);
297		history(hist, &he, H_ENTER, bp);
298	} else {
299		int c = '*';
300		for (num = 0; num < maxlen &&
301		    (c = getc(yyin)) != EOF && c != '\n'; ++num)
302			buf[num] = (char) c;
303		if (c == '\n')
304			buf[num++] = (char) c;
305		if (c == EOF && ferror(yyin))
306			YY_FATAL_ERROR( "input in flex scanner failed" );
307	}
308	return (num);
309}
310
311