scan.l revision 203531
1202719Sgabor%{ 2202719Sgabor/* $OpenBSD: scan.l,v 1.23 2009/10/27 23:59:36 deraadt Exp $ */ 3202719Sgabor 4202719Sgabor/* 5202719Sgabor * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 6202719Sgabor * 7202719Sgabor * Permission to use, copy, modify, and distribute this software for any 8202719Sgabor * purpose with or without fee is hereby granted, provided that the above 9202719Sgabor * copyright notice and this permission notice appear in all copies. 10202719Sgabor * 11202719Sgabor * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12202719Sgabor * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13202719Sgabor * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14202719Sgabor * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15202719Sgabor * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16202719Sgabor * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17202719Sgabor * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18202719Sgabor */ 19202719Sgabor 20202719Sgabor#include <sys/cdefs.h> 21202719Sgabor__FBSDID("$FreeBSD: head/usr.bin/bc/scan.l 203531 2010-02-05 18:17:17Z delphij $"); 22202719Sgabor 23202719Sgabor#include <err.h> 24202719Sgabor#include <errno.h> 25203498Sdelphij#include <histedit.h> 26202719Sgabor#include <signal.h> 27202719Sgabor#include <stdbool.h> 28202719Sgabor#include <string.h> 29202719Sgabor#include <unistd.h> 30202719Sgabor 31202719Sgabor#include "extern.h" 32202719Sgabor#include "bc.h" 33202719Sgabor#include "pathnames.h" 34202719Sgabor 35202719Sgaborint lineno; 36202719Sgabor 37203498Sdelphijbool interactive; 38203498SdelphijHistEvent he; 39203498SdelphijEditLine *el; 40203498SdelphijHistory *hist; 41203498Sdelphij 42202719Sgaborstatic char *strbuf = NULL; 43202719Sgaborstatic size_t strbuf_sz = 1; 44202719Sgaborstatic bool dot_seen; 45202719Sgabor 46202719Sgaborstatic void init_strbuf(void); 47202719Sgaborstatic void add_str(const char *); 48203498Sdelphijstatic int bc_yyinput(char *, int); 49202719Sgabor 50203498Sdelphij#undef YY_INPUT 51203498Sdelphij#define YY_INPUT(buf,retval,max) \ 52203498Sdelphij (retval = bc_yyinput(buf, max)) 53202719Sgabor%} 54202719Sgabor 55202719Sgabor%option always-interactive 56202719Sgabor 57202719SgaborDIGIT [0-9A-F] 58202719SgaborALPHA [a-z_] 59202719SgaborALPHANUM [a-z_0-9] 60202719Sgabor 61202719Sgabor%x comment string number 62202719Sgabor 63202719Sgabor%% 64202719Sgabor 65202719Sgabor"/*" BEGIN(comment); 66202719Sgabor<comment>{ 67202719Sgabor "*/" BEGIN(INITIAL); 68202719Sgabor \n lineno++; 69202719Sgabor \* ; 70202719Sgabor [^*\n]+ ; 71202719Sgabor <<EOF>> fatal("end of file in comment"); 72202719Sgabor} 73202719Sgabor 74202719Sgabor\" BEGIN(string); init_strbuf(); 75202719Sgabor<string>{ 76202719Sgabor [^"\n\\\[\]]+ add_str(yytext); 77202719Sgabor \[ add_str("\\["); 78202719Sgabor \] add_str("\\]"); 79202719Sgabor \\ add_str("\\\\"); 80202719Sgabor \n add_str("\n"); lineno++; 81202719Sgabor \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; 82202719Sgabor <<EOF>> fatal("end of file in string"); 83202719Sgabor} 84202719Sgabor 85202719Sgabor{DIGIT}+ { 86202719Sgabor BEGIN(number); 87202719Sgabor dot_seen = false; 88202719Sgabor init_strbuf(); 89202719Sgabor add_str(yytext); 90202719Sgabor } 91202719Sgabor\. { 92202719Sgabor BEGIN(number); 93202719Sgabor dot_seen = true; 94202719Sgabor init_strbuf(); 95202719Sgabor add_str("."); 96202719Sgabor } 97202719Sgabor<number>{ 98202719Sgabor {DIGIT}+ add_str(yytext); 99202719Sgabor \. { 100202719Sgabor if (dot_seen) { 101202719Sgabor BEGIN(INITIAL); 102202719Sgabor yylval.str = strbuf; 103202719Sgabor unput('.'); 104202719Sgabor return (NUMBER); 105202719Sgabor } else { 106202719Sgabor dot_seen = true; 107202719Sgabor add_str("."); 108202719Sgabor } 109202719Sgabor } 110202719Sgabor \\\n[ \t]* lineno++; 111202719Sgabor [^0-9A-F\.] { 112202719Sgabor BEGIN(INITIAL); 113202719Sgabor unput(yytext[0]); 114202719Sgabor if (strcmp(strbuf, ".") == 0) 115202719Sgabor return (DOT); 116202719Sgabor else { 117202719Sgabor yylval.str = strbuf; 118202719Sgabor return (NUMBER); 119202719Sgabor } 120202719Sgabor } 121202719Sgabor} 122202719Sgabor 123202719Sgabor"auto" return (AUTO); 124202719Sgabor"break" return (BREAK); 125202719Sgabor"continue" return (CONTINUE); 126202719Sgabor"define" return (DEFINE); 127202719Sgabor"else" return (ELSE); 128202719Sgabor"ibase" return (IBASE); 129202719Sgabor"if" return (IF); 130202719Sgabor"last" return (DOT); 131202719Sgabor"for" return (FOR); 132202719Sgabor"length" return (LENGTH); 133202719Sgabor"obase" return (OBASE); 134202719Sgabor"print" return (PRINT); 135202719Sgabor"quit" return (QUIT); 136202719Sgabor"return" return (RETURN); 137202719Sgabor"scale" return (SCALE); 138202719Sgabor"sqrt" return (SQRT); 139202719Sgabor"while" return (WHILE); 140202719Sgabor 141202719Sgabor"^" return (EXPONENT); 142202719Sgabor"*" return (MULTIPLY); 143202719Sgabor"/" return (DIVIDE); 144202719Sgabor"%" return (REMAINDER); 145202719Sgabor 146202719Sgabor"!" return (BOOL_NOT); 147202719Sgabor"&&" return (BOOL_AND); 148202719Sgabor"||" return (BOOL_OR); 149202719Sgabor 150202719Sgabor"+" return (PLUS); 151202719Sgabor"-" return (MINUS); 152202719Sgabor 153202719Sgabor"++" return (INCR); 154202719Sgabor"--" return (DECR); 155202719Sgabor 156202719Sgabor"=" yylval.str = ""; return (ASSIGN_OP); 157202719Sgabor"+=" yylval.str = "+"; return (ASSIGN_OP); 158202719Sgabor"-=" yylval.str = "-"; return (ASSIGN_OP); 159202719Sgabor"*=" yylval.str = "*"; return (ASSIGN_OP); 160202719Sgabor"/=" yylval.str = "/"; return (ASSIGN_OP); 161202719Sgabor"%=" yylval.str = "%"; return (ASSIGN_OP); 162202719Sgabor"^=" yylval.str = "^"; return (ASSIGN_OP); 163202719Sgabor 164202719Sgabor"==" return (EQUALS); 165202719Sgabor"<=" return (LESS_EQ); 166202719Sgabor">=" return (GREATER_EQ); 167202719Sgabor"!=" return (UNEQUALS); 168202719Sgabor"<" return (LESS); 169202719Sgabor">" return (GREATER); 170202719Sgabor 171202719Sgabor"," return (COMMA); 172202719Sgabor";" return (SEMICOLON); 173202719Sgabor 174202719Sgabor"(" return (LPAR); 175202719Sgabor")" return (RPAR); 176202719Sgabor 177202719Sgabor"[" return (LBRACKET); 178202719Sgabor"]" return (RBRACKET); 179202719Sgabor 180202719Sgabor"{" return (LBRACE); 181202719Sgabor"}" return (RBRACE); 182202719Sgabor 183202719Sgabor{ALPHA}{ALPHANUM}* { 184202719Sgabor /* alloc an extra byte for the type marker */ 185202719Sgabor char *p = malloc(yyleng + 2); 186202719Sgabor if (p == NULL) 187202719Sgabor err(1, NULL); 188202719Sgabor strlcpy(p, yytext, yyleng + 1); 189202719Sgabor yylval.astr = p; 190202719Sgabor return (LETTER); 191202719Sgabor } 192202719Sgabor 193202719Sgabor\\\n lineno++; 194202719Sgabor\n lineno++; return (NEWLINE); 195202719Sgabor 196202719Sgabor#[^\n]* ; 197202719Sgabor[ \t] ; 198202719Sgabor<<EOF>> return (QUIT); 199202719Sgabor. yyerror("illegal character"); 200202719Sgabor 201202719Sgabor%% 202202719Sgabor 203202719Sgaborstatic void 204202719Sgaborinit_strbuf(void) 205202719Sgabor{ 206203443Sgabor 207202719Sgabor if (strbuf == NULL) { 208202719Sgabor strbuf = malloc(strbuf_sz); 209202719Sgabor if (strbuf == NULL) 210202719Sgabor err(1, NULL); 211202719Sgabor } 212202719Sgabor strbuf[0] = '\0'; 213202719Sgabor} 214202719Sgabor 215202719Sgaborstatic void 216202719Sgaboradd_str(const char *str) 217202719Sgabor{ 218203443Sgabor size_t arglen; 219202719Sgabor 220202719Sgabor arglen = strlen(str); 221202719Sgabor 222202719Sgabor if (strlen(strbuf) + arglen + 1 > strbuf_sz) { 223202719Sgabor size_t newsize; 224202719Sgabor char *p; 225202719Sgabor 226202719Sgabor newsize = strbuf_sz + arglen + 1; 227202719Sgabor p = realloc(strbuf, newsize); 228202719Sgabor if (p == NULL) { 229202719Sgabor free(strbuf); 230202719Sgabor err(1, NULL); 231202719Sgabor } 232202719Sgabor strbuf_sz = newsize; 233202719Sgabor strbuf = p; 234202719Sgabor } 235202719Sgabor strlcat(strbuf, str, strbuf_sz); 236202719Sgabor} 237202719Sgabor 238202719Sgabor/* ARGSUSED */ 239202719Sgaborvoid 240202719Sgaborabort_line(int sig) 241202719Sgabor{ 242203443Sgabor static const char str[] = "[\n]P\n"; 243203443Sgabor int save_errno; 244202719Sgabor 245202719Sgabor switch (sig) { 246202719Sgabor default: 247202719Sgabor save_errno = errno; 248202719Sgabor YY_FLUSH_BUFFER; /* XXX signal race? */ 249202719Sgabor write(STDOUT_FILENO, str, sizeof(str) - 1); 250202719Sgabor errno = save_errno; 251202719Sgabor } 252202719Sgabor} 253202719Sgabor 254202719Sgaborint 255202719Sgaboryywrap(void) 256202719Sgabor{ 257203443Sgabor static YY_BUFFER_STATE buf; 258203443Sgabor static int state; 259202719Sgabor 260202719Sgabor if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 261202719Sgabor filename = sargv[fileindex++]; 262202719Sgabor yyin = fopen(filename, "r"); 263202719Sgabor lineno = 1; 264202719Sgabor if (yyin == NULL) 265202719Sgabor err(1, "cannot open %s", filename); 266202719Sgabor return (0); 267202719Sgabor } 268202719Sgabor if (state == 0 && cmdexpr[0] != '\0') { 269202719Sgabor buf = yy_scan_string(cmdexpr); 270202719Sgabor state++; 271202719Sgabor lineno = 1; 272202719Sgabor filename = "command line"; 273202719Sgabor return (0); 274202719Sgabor } else if (state == 1) { 275202719Sgabor yy_delete_buffer(buf); 276202719Sgabor free(cmdexpr); 277202719Sgabor state++; 278202719Sgabor } 279202719Sgabor if (yyin != NULL && yyin != stdin) 280202719Sgabor fclose(yyin); 281202719Sgabor if (fileindex < sargc) { 282202719Sgabor filename = sargv[fileindex++]; 283202719Sgabor yyin = fopen(filename, "r"); 284202719Sgabor lineno = 1; 285202719Sgabor if (yyin == NULL) 286202719Sgabor err(1, "cannot open %s", filename); 287202719Sgabor return (0); 288202719Sgabor } else if (fileindex == sargc) { 289202719Sgabor fileindex++; 290202719Sgabor yyin = stdin; 291202719Sgabor if (interactive) 292202719Sgabor signal(SIGINT, abort_line); 293202719Sgabor lineno = 1; 294202719Sgabor filename = "stdin"; 295202719Sgabor return (0); 296202719Sgabor } 297202719Sgabor return (1); 298202719Sgabor} 299203498Sdelphij 300203498Sdelphijstatic int 301203498Sdelphijbc_yyinput(char *buf, int maxlen) 302203498Sdelphij{ 303203498Sdelphij int num; 304203531Sdelphij if (yyin == stdin && interactive) { 305203498Sdelphij const char *bp; 306203498Sdelphij 307203498Sdelphij if ((bp = el_gets(el, &num)) == NULL || num == 0) 308203498Sdelphij return (0); 309203498Sdelphij if (num > maxlen) { 310203498Sdelphij el_push(el, (char *)(uintptr_t)(bp) + maxlen); 311203498Sdelphij num = maxlen; 312203498Sdelphij } 313203498Sdelphij memcpy(buf, bp, num); 314203498Sdelphij history(hist, &he, H_ENTER, bp); 315203498Sdelphij } else { 316203498Sdelphij int c = '*'; 317203498Sdelphij for (num = 0; num < maxlen && 318203498Sdelphij (c = getc(yyin)) != EOF && c != '\n'; ++num) 319203498Sdelphij buf[num] = (char) c; 320203498Sdelphij if (c == '\n') 321203498Sdelphij buf[num++] = (char) c; 322203498Sdelphij if (c == EOF && ferror(yyin)) 323203498Sdelphij YY_FATAL_ERROR( "input in flex scanner failed" ); 324203498Sdelphij } 325203498Sdelphij return (num); 326203498Sdelphij} 327203498Sdelphij 328