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