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