]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - usr.bin/bc/scan.l
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / usr.bin / bc / scan.l
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_NO_INPUT
50 #undef YY_INPUT
51 #define YY_INPUT(buf,retval,max) \
52         (retval = bc_yyinput(buf, max))
53 %}
54
55 %option always-interactive
56
57 DIGIT           [0-9A-F]
58 ALPHA           [a-z_]
59 ALPHANUM        [a-z_0-9]
60
61 %x              comment string number
62
63 %%
64
65 "/*"            BEGIN(comment);
66 <comment>{
67         "*/"    BEGIN(INITIAL);
68         \n      lineno++;
69         \*      ;
70         [^*\n]+ ;
71         <<EOF>> fatal("end of file in comment");
72 }
73
74 \"              BEGIN(string); init_strbuf();
75 <string>{
76         [^"\n\\\[\]]+   add_str(yytext);
77         \[      add_str("\\[");
78         \]      add_str("\\]");
79         \\      add_str("\\\\");
80         \n      add_str("\n"); lineno++;
81         \"      BEGIN(INITIAL); yylval.str = strbuf; return STRING;
82         <<EOF>> fatal("end of file in string");
83 }
84
85 {DIGIT}+        {
86                         BEGIN(number);
87                         dot_seen = false;
88                         init_strbuf();
89                         add_str(yytext);
90                 }
91 \.              {
92                         BEGIN(number);
93                         dot_seen = true;
94                         init_strbuf();
95                         add_str(".");
96                 }
97 <number>{
98         {DIGIT}+        add_str(yytext);
99         \.      {
100                         if (dot_seen) {
101                                 BEGIN(INITIAL);
102                                 yylval.str = strbuf;
103                                 unput('.');
104                                 return (NUMBER);
105                         } else {
106                                 dot_seen = true;
107                                 add_str(".");
108                         }
109                 }
110         \\\n[ \t]*      lineno++;
111         [^0-9A-F\.]     {
112                         BEGIN(INITIAL);
113                         unput(yytext[0]);
114                         if (strcmp(strbuf, ".") == 0)
115                                 return (DOT);
116                         else {
117                                 yylval.str = strbuf;
118                                 return (NUMBER);
119                         }
120                 }
121 }
122
123 "auto"          return (AUTO);
124 "break"         return (BREAK);
125 "continue"      return (CONTINUE);
126 "define"        return (DEFINE);
127 "else"          return (ELSE);
128 "ibase"         return (IBASE);
129 "if"            return (IF);
130 "last"          return (DOT);
131 "for"           return (FOR);
132 "length"        return (LENGTH);
133 "obase"         return (OBASE);
134 "print"         return (PRINT);
135 "quit"          return (QUIT);
136 "return"        return (RETURN);
137 "scale"         return (SCALE);
138 "sqrt"          return (SQRT);
139 "while"         return (WHILE);
140
141 "^"             return (EXPONENT);
142 "*"             return (MULTIPLY);
143 "/"             return (DIVIDE);
144 "%"             return (REMAINDER);
145
146 "!"             return (BOOL_NOT);
147 "&&"            return (BOOL_AND);
148 "||"            return (BOOL_OR);
149
150 "+"             return (PLUS);
151 "-"             return (MINUS);
152
153 "++"            return (INCR);
154 "--"            return (DECR);
155
156 "="             yylval.str = ""; return (ASSIGN_OP);
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
164 "=="            return (EQUALS);
165 "<="            return (LESS_EQ);
166 ">="            return (GREATER_EQ);
167 "!="            return (UNEQUALS);
168 "<"             return (LESS);
169 ">"             return (GREATER);
170
171 ","             return (COMMA);
172 ";"             return (SEMICOLON);
173
174 "("             return (LPAR);
175 ")"             return (RPAR);
176
177 "["             return (LBRACKET);
178 "]"             return (RBRACKET);
179
180 "{"             return (LBRACE);
181 "}"             return (RBRACE);
182
183 {ALPHA}{ALPHANUM}* {
184                         /* alloc an extra byte for the type marker */
185                         char *p = malloc(yyleng + 2);
186                         if (p == NULL)
187                                 err(1, NULL);
188                         strlcpy(p, yytext, yyleng + 1);
189                         yylval.astr = p;
190                         return (LETTER);
191                 }
192
193 \\\n            lineno++;
194 \n              lineno++; return (NEWLINE);
195
196 #[^\n]*         ;
197 [ \t]           ;
198 <<EOF>>         return (QUIT);
199 .               yyerror("illegal character");
200
201 %%
202
203 static void
204 init_strbuf(void)
205 {
206
207         if (strbuf == NULL) {
208                 strbuf = malloc(strbuf_sz);
209                 if (strbuf == NULL)
210                         err(1, NULL);
211         }
212         strbuf[0] = '\0';
213 }
214
215 static void
216 add_str(const char *str)
217 {
218         size_t arglen;
219
220         arglen = strlen(str);
221
222         if (strlen(strbuf) + arglen + 1 > strbuf_sz) {
223                 size_t   newsize;
224                 char    *p;
225
226                 newsize = strbuf_sz + arglen + 1;
227                 p = realloc(strbuf, newsize);
228                 if (p == NULL) {
229                         free(strbuf);
230                         err(1, NULL);
231                 }
232                 strbuf_sz = newsize;
233                 strbuf = p;
234         }
235         strlcat(strbuf, str, strbuf_sz);
236 }
237
238 int
239 yywrap(void)
240 {
241         static YY_BUFFER_STATE buf;
242         static int state;
243
244         if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) {
245                 filename = sargv[fileindex++];
246                 yyin = fopen(filename, "r");
247                 lineno = 1;
248                 if (yyin == NULL)
249                         err(1, "cannot open %s", filename);
250                 return (0);
251         }
252         if (state == 0 && cmdexpr[0] != '\0') {
253                 buf = yy_scan_string(cmdexpr);
254                 state++;
255                 lineno = 1;
256                 filename = "command line";
257                 return (0);
258         } else if (state == 1) {
259                 yy_delete_buffer(buf);
260                 free(cmdexpr);
261                 state++;
262         }
263         if (yyin != NULL && yyin != stdin)
264                 fclose(yyin);
265         if (fileindex < sargc) {
266                 filename = sargv[fileindex++];
267                 yyin = fopen(filename, "r");
268                 lineno = 1;
269                 if (yyin == NULL)
270                         err(1, "cannot open %s", filename);
271                 return (0);
272         } else if (fileindex == sargc) {
273                 fileindex++;
274                 yyin = stdin;
275                 lineno = 1;
276                 filename = "stdin";
277                 return (0);
278         }
279         return (1);
280 }
281
282 static int
283 bc_yyinput(char *buf, int maxlen)
284 {
285         int num;
286         if (yyin == stdin && interactive) {
287                 const char *bp;
288
289                 if ((bp = el_gets(el, &num)) == NULL || num == 0)
290                         return (0);
291                 if (num > maxlen) {
292                         el_push(el, (char *)(uintptr_t)(bp) + maxlen);
293                         num = maxlen;
294                 }
295                 memcpy(buf, bp, num);
296                 history(hist, &he, H_ENTER, bp);
297         } else {
298                 int c = '*';
299                 for (num = 0; num < maxlen &&
300                     (c = getc(yyin)) != EOF && c != '\n'; ++num)
301                         buf[num] = (char) c;
302                 if (c == '\n')
303                         buf[num++] = (char) c;
304                 if (c == EOF && ferror(yyin))
305                         YY_FATAL_ERROR( "input in flex scanner failed" );
306         }
307         return (num);
308 }
309