scan.l revision 265533
1202719Sgabor%{ 2265533Sdelphij/* $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto 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: stable/10/usr.bin/bc/scan.l 265533 2014-05-07 08:06:54Z delphij $"); 22202719Sgabor 23202719Sgabor#include <err.h> 24202719Sgabor#include <errno.h> 25203498Sdelphij#include <histedit.h> 26202719Sgabor#include <stdbool.h> 27265533Sdelphij#include <signal.h> 28202719Sgabor#include <string.h> 29202719Sgabor#include <unistd.h> 30202719Sgabor 31202719Sgabor#include "extern.h" 32202719Sgabor#include "bc.h" 33202719Sgabor#include "pathnames.h" 34202719Sgabor 35265533Sdelphijint lineno; 36265533Sdelphijbool interactive; 37202719Sgabor 38203498SdelphijHistEvent he; 39203498SdelphijEditLine *el; 40203498SdelphijHistory *hist; 41203498Sdelphij 42202719Sgaborstatic char *strbuf = NULL; 43265533Sdelphijstatic size_t strbuf_sz = 1; 44265533Sdelphijstatic bool dot_seen; 45265533Sdelphijstatic int use_el; 46265533Sdelphijstatic volatile sig_atomic_t skipchars; 47202719Sgabor 48265533Sdelphijstatic void init_strbuf(void); 49265533Sdelphijstatic void add_str(const char *); 50265533Sdelphij 51203498Sdelphijstatic int bc_yyinput(char *, int); 52202719Sgabor 53250926Sjkim#define YY_DECL int yylex(void) 54215704Sbrucec#define YY_NO_INPUT 55203498Sdelphij#undef YY_INPUT 56203498Sdelphij#define YY_INPUT(buf,retval,max) \ 57203498Sdelphij (retval = bc_yyinput(buf, max)) 58265533Sdelphij 59202719Sgabor%} 60202719Sgabor 61202719Sgabor%option always-interactive 62202719Sgabor 63202719SgaborDIGIT [0-9A-F] 64202719SgaborALPHA [a-z_] 65202719SgaborALPHANUM [a-z_0-9] 66202719Sgabor 67202719Sgabor%x comment string number 68202719Sgabor 69202719Sgabor%% 70202719Sgabor 71202719Sgabor"/*" BEGIN(comment); 72202719Sgabor<comment>{ 73202719Sgabor "*/" BEGIN(INITIAL); 74202719Sgabor \n lineno++; 75202719Sgabor \* ; 76202719Sgabor [^*\n]+ ; 77202719Sgabor <<EOF>> fatal("end of file in comment"); 78202719Sgabor} 79202719Sgabor 80202719Sgabor\" BEGIN(string); init_strbuf(); 81202719Sgabor<string>{ 82202719Sgabor [^"\n\\\[\]]+ add_str(yytext); 83202719Sgabor \[ add_str("\\["); 84202719Sgabor \] add_str("\\]"); 85202719Sgabor \\ add_str("\\\\"); 86202719Sgabor \n add_str("\n"); lineno++; 87202719Sgabor \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; 88202719Sgabor <<EOF>> fatal("end of file in string"); 89202719Sgabor} 90202719Sgabor 91202719Sgabor{DIGIT}+ { 92202719Sgabor BEGIN(number); 93202719Sgabor dot_seen = false; 94202719Sgabor init_strbuf(); 95202719Sgabor add_str(yytext); 96202719Sgabor } 97202719Sgabor\. { 98202719Sgabor BEGIN(number); 99202719Sgabor dot_seen = true; 100202719Sgabor init_strbuf(); 101202719Sgabor add_str("."); 102202719Sgabor } 103202719Sgabor<number>{ 104202719Sgabor {DIGIT}+ add_str(yytext); 105202719Sgabor \. { 106202719Sgabor if (dot_seen) { 107202719Sgabor BEGIN(INITIAL); 108202719Sgabor yylval.str = strbuf; 109202719Sgabor unput('.'); 110265533Sdelphij return NUMBER; 111202719Sgabor } else { 112202719Sgabor dot_seen = true; 113202719Sgabor add_str("."); 114202719Sgabor } 115202719Sgabor } 116202719Sgabor \\\n[ \t]* lineno++; 117202719Sgabor [^0-9A-F\.] { 118202719Sgabor BEGIN(INITIAL); 119202719Sgabor unput(yytext[0]); 120202719Sgabor if (strcmp(strbuf, ".") == 0) 121265533Sdelphij return DOT; 122202719Sgabor else { 123202719Sgabor yylval.str = strbuf; 124265533Sdelphij return NUMBER; 125202719Sgabor } 126202719Sgabor } 127202719Sgabor} 128202719Sgabor 129265533Sdelphij"auto" return AUTO; 130265533Sdelphij"break" return BREAK; 131265533Sdelphij"continue" return CONTINUE; 132265533Sdelphij"define" return DEFINE; 133265533Sdelphij"else" return ELSE; 134265533Sdelphij"ibase" return IBASE; 135265533Sdelphij"if" return IF; 136265533Sdelphij"last" return DOT; 137265533Sdelphij"for" return FOR; 138265533Sdelphij"length" return LENGTH; 139265533Sdelphij"obase" return OBASE; 140265533Sdelphij"print" return PRINT; 141265533Sdelphij"quit" return QUIT; 142265533Sdelphij"return" return RETURN; 143265533Sdelphij"scale" return SCALE; 144265533Sdelphij"sqrt" return SQRT; 145265533Sdelphij"while" return WHILE; 146202719Sgabor 147265533Sdelphij"^" return EXPONENT; 148265533Sdelphij"*" return MULTIPLY; 149265533Sdelphij"/" return DIVIDE; 150265533Sdelphij"%" return REMAINDER; 151202719Sgabor 152265533Sdelphij"!" return BOOL_NOT; 153265533Sdelphij"&&" return BOOL_AND; 154265533Sdelphij"||" return BOOL_OR; 155202719Sgabor 156265533Sdelphij"+" return PLUS; 157265533Sdelphij"-" return MINUS; 158202719Sgabor 159265533Sdelphij"++" return INCR; 160265533Sdelphij"--" return DECR; 161202719Sgabor 162265533Sdelphij"=" yylval.str = ""; return ASSIGN_OP; 163265533Sdelphij"+=" yylval.str = "+"; return ASSIGN_OP; 164265533Sdelphij"-=" yylval.str = "-"; return ASSIGN_OP; 165265533Sdelphij"*=" yylval.str = "*"; return ASSIGN_OP; 166265533Sdelphij"/=" yylval.str = "/"; return ASSIGN_OP; 167265533Sdelphij"%=" yylval.str = "%"; return ASSIGN_OP; 168265533Sdelphij"^=" yylval.str = "^"; return ASSIGN_OP; 169202719Sgabor 170265533Sdelphij"==" return EQUALS; 171265533Sdelphij"<=" return LESS_EQ; 172265533Sdelphij">=" return GREATER_EQ; 173265533Sdelphij"!=" return UNEQUALS; 174265533Sdelphij"<" return LESS; 175265533Sdelphij">" return GREATER; 176202719Sgabor 177265533Sdelphij"," return COMMA; 178265533Sdelphij";" return SEMICOLON; 179202719Sgabor 180265533Sdelphij"(" return LPAR; 181265533Sdelphij")" return RPAR; 182202719Sgabor 183265533Sdelphij"[" return LBRACKET; 184265533Sdelphij"]" return RBRACKET; 185202719Sgabor 186265533Sdelphij"{" return LBRACE; 187265533Sdelphij"}" return RBRACE; 188202719Sgabor 189202719Sgabor{ALPHA}{ALPHANUM}* { 190202719Sgabor /* alloc an extra byte for the type marker */ 191202719Sgabor char *p = malloc(yyleng + 2); 192202719Sgabor if (p == NULL) 193202719Sgabor err(1, NULL); 194202719Sgabor strlcpy(p, yytext, yyleng + 1); 195202719Sgabor yylval.astr = p; 196265533Sdelphij return LETTER; 197202719Sgabor } 198202719Sgabor 199202719Sgabor\\\n lineno++; 200265533Sdelphij\n lineno++; return NEWLINE; 201202719Sgabor 202202719Sgabor#[^\n]* ; 203202719Sgabor[ \t] ; 204265533Sdelphij<<EOF>> return QUIT; 205202719Sgabor. yyerror("illegal character"); 206202719Sgabor 207202719Sgabor%% 208202719Sgabor 209202719Sgaborstatic void 210202719Sgaborinit_strbuf(void) 211202719Sgabor{ 212202719Sgabor if (strbuf == NULL) { 213202719Sgabor strbuf = malloc(strbuf_sz); 214202719Sgabor if (strbuf == NULL) 215202719Sgabor err(1, NULL); 216202719Sgabor } 217202719Sgabor strbuf[0] = '\0'; 218202719Sgabor} 219202719Sgabor 220202719Sgaborstatic void 221202719Sgaboradd_str(const char *str) 222202719Sgabor{ 223203443Sgabor size_t arglen; 224202719Sgabor 225202719Sgabor arglen = strlen(str); 226202719Sgabor 227202719Sgabor if (strlen(strbuf) + arglen + 1 > strbuf_sz) { 228265533Sdelphij size_t newsize; 229265533Sdelphij char *p; 230202719Sgabor 231202719Sgabor newsize = strbuf_sz + arglen + 1; 232202719Sgabor p = realloc(strbuf, newsize); 233202719Sgabor if (p == NULL) { 234202719Sgabor free(strbuf); 235202719Sgabor err(1, NULL); 236202719Sgabor } 237202719Sgabor strbuf_sz = newsize; 238202719Sgabor strbuf = p; 239202719Sgabor } 240202719Sgabor strlcat(strbuf, str, strbuf_sz); 241202719Sgabor} 242202719Sgabor 243265533Sdelphij/* ARGSUSED */ 244265533Sdelphijvoid 245265533Sdelphijabort_line(int sig __unused) 246265533Sdelphij{ 247265533Sdelphij static const char str1[] = "[\n]P\n"; 248265533Sdelphij static const char str2[] = "[^C\n]P\n"; 249265533Sdelphij int save_errno; 250265533Sdelphij const LineInfo *info; 251265533Sdelphij 252265533Sdelphij save_errno = errno; 253265533Sdelphij if (use_el) { 254265533Sdelphij write(STDOUT_FILENO, str2, sizeof(str2) - 1); 255265533Sdelphij info = el_line(el); 256265533Sdelphij skipchars = info->lastchar - info->buffer; 257265533Sdelphij } else 258265533Sdelphij write(STDOUT_FILENO, str1, sizeof(str1) - 1); 259265533Sdelphij errno = save_errno; 260265533Sdelphij} 261265533Sdelphij 262265533Sdelphij/* 263265533Sdelphij * Avoid the echo of ^D by the default code of editline and take 264265533Sdelphij * into account skipchars to make ^D work when the cursor is at start of 265265533Sdelphij * line after a ^C. 266265533Sdelphij */ 267265533Sdelphijunsigned char 268265533Sdelphijbc_eof(EditLine *e, int ch __unused) 269265533Sdelphij{ 270265533Sdelphij const struct lineinfo *info = el_line(e); 271265533Sdelphij 272265533Sdelphij if (info->buffer + skipchars == info->cursor && 273265533Sdelphij info->cursor == info->lastchar) 274265533Sdelphij return (CC_EOF); 275265533Sdelphij else 276265533Sdelphij return (CC_ERROR); 277265533Sdelphij} 278265533Sdelphij 279202719Sgaborint 280202719Sgaboryywrap(void) 281202719Sgabor{ 282265533Sdelphij static int state; 283203443Sgabor static YY_BUFFER_STATE buf; 284202719Sgabor 285202719Sgabor if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 286202719Sgabor filename = sargv[fileindex++]; 287202719Sgabor yyin = fopen(filename, "r"); 288202719Sgabor lineno = 1; 289202719Sgabor if (yyin == NULL) 290202719Sgabor err(1, "cannot open %s", filename); 291202719Sgabor return (0); 292202719Sgabor } 293202719Sgabor if (state == 0 && cmdexpr[0] != '\0') { 294202719Sgabor buf = yy_scan_string(cmdexpr); 295202719Sgabor state++; 296202719Sgabor lineno = 1; 297202719Sgabor filename = "command line"; 298202719Sgabor return (0); 299202719Sgabor } else if (state == 1) { 300202719Sgabor yy_delete_buffer(buf); 301202719Sgabor free(cmdexpr); 302202719Sgabor state++; 303202719Sgabor } 304202719Sgabor if (yyin != NULL && yyin != stdin) 305202719Sgabor fclose(yyin); 306202719Sgabor if (fileindex < sargc) { 307202719Sgabor filename = sargv[fileindex++]; 308202719Sgabor yyin = fopen(filename, "r"); 309202719Sgabor lineno = 1; 310202719Sgabor if (yyin == NULL) 311202719Sgabor err(1, "cannot open %s", filename); 312202719Sgabor return (0); 313202719Sgabor } else if (fileindex == sargc) { 314202719Sgabor fileindex++; 315202719Sgabor yyin = stdin; 316265533Sdelphij if (interactive) { 317265533Sdelphij signal(SIGINT, abort_line); 318265533Sdelphij signal(SIGTSTP, tstpcont); 319265533Sdelphij } 320202719Sgabor lineno = 1; 321202719Sgabor filename = "stdin"; 322202719Sgabor return (0); 323202719Sgabor } 324202719Sgabor return (1); 325202719Sgabor} 326203498Sdelphij 327203498Sdelphijstatic int 328203498Sdelphijbc_yyinput(char *buf, int maxlen) 329203498Sdelphij{ 330203498Sdelphij int num; 331265533Sdelphij 332265533Sdelphij if (el != NULL) 333265533Sdelphij el_get(el, EL_EDITMODE, &use_el); 334265533Sdelphij 335265533Sdelphij if (yyin == stdin && interactive && use_el) { 336203498Sdelphij const char *bp; 337265533Sdelphij sigset_t oset, nset; 338203498Sdelphij 339203498Sdelphij if ((bp = el_gets(el, &num)) == NULL || num == 0) 340203498Sdelphij return (0); 341265533Sdelphij sigemptyset(&nset); 342265533Sdelphij sigaddset(&nset, SIGINT); 343265533Sdelphij sigprocmask(SIG_BLOCK, &nset, &oset); 344265533Sdelphij if (skipchars < num) { 345265533Sdelphij bp += skipchars; 346265533Sdelphij num -= skipchars; 347265533Sdelphij } 348265533Sdelphij skipchars = 0; 349265533Sdelphij sigprocmask(SIG_SETMASK, &oset, NULL); 350203498Sdelphij if (num > maxlen) { 351265533Sdelphij el_push(el, bp + maxlen); 352203498Sdelphij num = maxlen; 353203498Sdelphij } 354203498Sdelphij memcpy(buf, bp, num); 355203498Sdelphij history(hist, &he, H_ENTER, bp); 356265533Sdelphij el_get(el, EL_EDITMODE, &use_el); 357203498Sdelphij } else { 358203498Sdelphij int c = '*'; 359203498Sdelphij for (num = 0; num < maxlen && 360203498Sdelphij (c = getc(yyin)) != EOF && c != '\n'; ++num) 361203498Sdelphij buf[num] = (char) c; 362203498Sdelphij if (c == '\n') 363203498Sdelphij buf[num++] = (char) c; 364203498Sdelphij if (c == EOF && ferror(yyin)) 365203498Sdelphij YY_FATAL_ERROR( "input in flex scanner failed" ); 366203498Sdelphij } 367203498Sdelphij return (num); 368203498Sdelphij} 369203498Sdelphij 370265533Sdelphij 371