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