xref: /freebsd/usr.bin/bc/scan.l (revision 595e514d0df2bac5b813d35f83e32875dbf16a83)
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 
34 int		 lineno;
35 
36 bool		 interactive;
37 HistEvent	 he;
38 EditLine	*el;
39 History		*hist;
40 
41 static char	*strbuf = NULL;
42 static size_t	 strbuf_sz = 1;
43 static bool	 dot_seen;
44 
45 static void	 init_strbuf(void);
46 static void	 add_str(const char *);
47 static 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 
58 DIGIT		[0-9A-F]
59 ALPHA		[a-z_]
60 ALPHANUM	[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 
204 static void
205 init_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 
216 static void
217 add_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 
239 int
240 yywrap(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 
283 static int
284 bc_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