scan.l revision 203498
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: head/usr.bin/bc/scan.l 203498 2010-02-04 18:43:05Z delphij $"); 22 23#include <err.h> 24#include <errno.h> 25#include <histedit.h> 26#include <signal.h> 27#include <stdbool.h> 28#include <string.h> 29#include <unistd.h> 30 31#include "extern.h" 32#include "bc.h" 33#include "pathnames.h" 34 35int lineno; 36 37bool interactive; 38HistEvent he; 39EditLine *el; 40History *hist; 41 42static char *strbuf = NULL; 43static size_t strbuf_sz = 1; 44static bool dot_seen; 45 46static void init_strbuf(void); 47static void add_str(const char *); 48static int bc_yyinput(char *, int); 49 50#undef YY_INPUT 51#define YY_INPUT(buf,retval,max) \ 52 (retval = bc_yyinput(buf, max)) 53%} 54 55%option always-interactive 56 57DIGIT [0-9A-F] 58ALPHA [a-z_] 59ALPHANUM [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 203static void 204init_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 215static void 216add_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/* ARGSUSED */ 239void 240abort_line(int sig) 241{ 242 static const char str[] = "[\n]P\n"; 243 int save_errno; 244 245 switch (sig) { 246 default: 247 save_errno = errno; 248 YY_FLUSH_BUFFER; /* XXX signal race? */ 249 write(STDOUT_FILENO, str, sizeof(str) - 1); 250 errno = save_errno; 251 } 252} 253 254int 255yywrap(void) 256{ 257 static YY_BUFFER_STATE buf; 258 static int state; 259 260 if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 261 filename = sargv[fileindex++]; 262 yyin = fopen(filename, "r"); 263 lineno = 1; 264 if (yyin == NULL) 265 err(1, "cannot open %s", filename); 266 return (0); 267 } 268 if (state == 0 && cmdexpr[0] != '\0') { 269 buf = yy_scan_string(cmdexpr); 270 state++; 271 lineno = 1; 272 filename = "command line"; 273 return (0); 274 } else if (state == 1) { 275 yy_delete_buffer(buf); 276 free(cmdexpr); 277 state++; 278 } 279 if (yyin != NULL && yyin != stdin) 280 fclose(yyin); 281 if (fileindex < sargc) { 282 filename = sargv[fileindex++]; 283 yyin = fopen(filename, "r"); 284 lineno = 1; 285 if (yyin == NULL) 286 err(1, "cannot open %s", filename); 287 return (0); 288 } else if (fileindex == sargc) { 289 fileindex++; 290 yyin = stdin; 291 if (interactive) 292 signal(SIGINT, abort_line); 293 lineno = 1; 294 filename = "stdin"; 295 return (0); 296 } 297 return (1); 298} 299 300static int 301bc_yyinput(char *buf, int maxlen) 302{ 303 int num; 304 if (interactive) { 305 const char *bp; 306 307 if ((bp = el_gets(el, &num)) == NULL || num == 0) 308 return (0); 309 if (num > maxlen) { 310 el_push(el, (char *)(uintptr_t)(bp) + maxlen); 311 num = maxlen; 312 } 313 memcpy(buf, bp, num); 314 history(hist, &he, H_ENTER, bp); 315 } else { 316 int c = '*'; 317 for (num = 0; num < maxlen && 318 (c = getc(yyin)) != EOF && c != '\n'; ++num) 319 buf[num] = (char) c; 320 if (c == '\n') 321 buf[num++] = (char) c; 322 if (c == EOF && ferror(yyin)) 323 YY_FATAL_ERROR( "input in flex scanner failed" ); 324 } 325 return (num); 326} 327 328