scan.l revision 265533
1121663Sharti%{ 2121663Sharti/* $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto Exp $ */ 3121663Sharti 4121663Sharti/* 5121663Sharti * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 6131823Sharti * 7131823Sharti * Permission to use, copy, modify, and distribute this software for any 8121663Sharti * purpose with or without fee is hereby granted, provided that the above 9121663Sharti * copyright notice and this permission notice appear in all copies. 10121663Sharti * 11121663Sharti * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12121663Sharti * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13121663Sharti * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14121663Sharti * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15121663Sharti * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16121663Sharti * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17121663Sharti * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18121663Sharti */ 19121663Sharti 20121663Sharti#include <sys/cdefs.h> 21121663Sharti__FBSDID("$FreeBSD: stable/10/usr.bin/bc/scan.l 265533 2014-05-07 08:06:54Z delphij $"); 22121663Sharti 23121663Sharti#include <err.h> 24121663Sharti#include <errno.h> 25121663Sharti#include <histedit.h> 26121663Sharti#include <stdbool.h> 27121663Sharti#include <signal.h> 28121663Sharti#include <string.h> 29146532Sharti#include <unistd.h> 30121663Sharti 31121663Sharti#include "extern.h" 32121663Sharti#include "bc.h" 33121663Sharti#include "pathnames.h" 34121663Sharti 35121663Shartiint lineno; 36121663Shartibool interactive; 37121663Sharti 38121663ShartiHistEvent he; 39121663ShartiEditLine *el; 40121663ShartiHistory *hist; 41121663Sharti 42121663Shartistatic char *strbuf = NULL; 43121663Shartistatic size_t strbuf_sz = 1; 44121663Shartistatic bool dot_seen; 45121663Shartistatic int use_el; 46121663Shartistatic volatile sig_atomic_t skipchars; 47121663Sharti 48121663Shartistatic void init_strbuf(void); 49121663Shartistatic void add_str(const char *); 50121663Sharti 51121663Shartistatic int bc_yyinput(char *, int); 52121663Sharti 53121663Sharti#define YY_DECL int yylex(void) 54121663Sharti#define YY_NO_INPUT 55121663Sharti#undef YY_INPUT 56121663Sharti#define YY_INPUT(buf,retval,max) \ 57121663Sharti (retval = bc_yyinput(buf, max)) 58121663Sharti 59121663Sharti%} 60121663Sharti 61121663Sharti%option always-interactive 62121663Sharti 63121663ShartiDIGIT [0-9A-F] 64121663ShartiALPHA [a-z_] 65121663ShartiALPHANUM [a-z_0-9] 66135923Strhodes 67121663Sharti%x comment string number 68135923Strhodes 69121663Sharti%% 70121663Sharti 71121663Sharti"/*" BEGIN(comment); 72121663Sharti<comment>{ 73121663Sharti "*/" BEGIN(INITIAL); 74121663Sharti \n lineno++; 75121663Sharti \* ; 76121663Sharti [^*\n]+ ; 77121663Sharti <<EOF>> fatal("end of file in comment"); 78121663Sharti} 79121663Sharti 80121663Sharti\" BEGIN(string); init_strbuf(); 81121663Sharti<string>{ 82121663Sharti [^"\n\\\[\]]+ add_str(yytext); 83121663Sharti \[ add_str("\\["); 84121663Sharti \] add_str("\\]"); 85121663Sharti \\ add_str("\\\\"); 86121663Sharti \n add_str("\n"); lineno++; 87121663Sharti \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; 88121663Sharti <<EOF>> fatal("end of file in string"); 89121663Sharti} 90121663Sharti 91121663Sharti{DIGIT}+ { 92121663Sharti BEGIN(number); 93121663Sharti dot_seen = false; 94121663Sharti init_strbuf(); 95121663Sharti add_str(yytext); 96121663Sharti } 97121663Sharti\. { 98121663Sharti BEGIN(number); 99121663Sharti dot_seen = true; 100121663Sharti init_strbuf(); 101121663Sharti add_str("."); 102121663Sharti } 103121663Sharti<number>{ 104121663Sharti {DIGIT}+ add_str(yytext); 105121663Sharti \. { 106121663Sharti if (dot_seen) { 107121663Sharti BEGIN(INITIAL); 108121663Sharti yylval.str = strbuf; 109121663Sharti unput('.'); 110121663Sharti return NUMBER; 111121663Sharti } else { 112121663Sharti dot_seen = true; 113121663Sharti add_str("."); 114121663Sharti } 115121663Sharti } 116121663Sharti \\\n[ \t]* lineno++; 117121663Sharti [^0-9A-F\.] { 118121663Sharti BEGIN(INITIAL); 119121663Sharti unput(yytext[0]); 120121663Sharti if (strcmp(strbuf, ".") == 0) 121121663Sharti return DOT; 122121663Sharti else { 123121663Sharti yylval.str = strbuf; 124121663Sharti return NUMBER; 125121663Sharti } 126121663Sharti } 127121663Sharti} 128121663Sharti 129121663Sharti"auto" return AUTO; 130121663Sharti"break" return BREAK; 131121663Sharti"continue" return CONTINUE; 132121663Sharti"define" return DEFINE; 133121663Sharti"else" return ELSE; 134121663Sharti"ibase" return IBASE; 135121663Sharti"if" return IF; 136121663Sharti"last" return DOT; 137121663Sharti"for" return FOR; 138121663Sharti"length" return LENGTH; 139121663Sharti"obase" return OBASE; 140121663Sharti"print" return PRINT; 141121663Sharti"quit" return QUIT; 142121663Sharti"return" return RETURN; 143121663Sharti"scale" return SCALE; 144121663Sharti"sqrt" return SQRT; 145121663Sharti"while" return WHILE; 146121663Sharti 147121663Sharti"^" return EXPONENT; 148121663Sharti"*" return MULTIPLY; 149121663Sharti"/" return DIVIDE; 150121663Sharti"%" return REMAINDER; 151121663Sharti 152121663Sharti"!" return BOOL_NOT; 153121663Sharti"&&" return BOOL_AND; 154121663Sharti"||" return BOOL_OR; 155121663Sharti 156121663Sharti"+" return PLUS; 157135923Strhodes"-" return MINUS; 158135923Strhodes 159135923Strhodes"++" return INCR; 160121663Sharti"--" return DECR; 161135923Strhodes 162121663Sharti"=" yylval.str = ""; return ASSIGN_OP; 163121663Sharti"+=" yylval.str = "+"; return ASSIGN_OP; 164121663Sharti"-=" yylval.str = "-"; return ASSIGN_OP; 165121663Sharti"*=" yylval.str = "*"; return ASSIGN_OP; 166121663Sharti"/=" yylval.str = "/"; return ASSIGN_OP; 167121663Sharti"%=" yylval.str = "%"; return ASSIGN_OP; 168121663Sharti"^=" yylval.str = "^"; return ASSIGN_OP; 169121663Sharti 170121663Sharti"==" return EQUALS; 171121663Sharti"<=" return LESS_EQ; 172121663Sharti">=" return GREATER_EQ; 173121663Sharti"!=" return UNEQUALS; 174121663Sharti"<" return LESS; 175121663Sharti">" return GREATER; 176121663Sharti 177121663Sharti"," return COMMA; 178121663Sharti";" return SEMICOLON; 179121663Sharti 180121663Sharti"(" return LPAR; 181121663Sharti")" return RPAR; 182121663Sharti 183121663Sharti"[" return LBRACKET; 184121663Sharti"]" return RBRACKET; 185121663Sharti 186121663Sharti"{" return LBRACE; 187121663Sharti"}" return RBRACE; 188121663Sharti 189121663Sharti{ALPHA}{ALPHANUM}* { 190121663Sharti /* alloc an extra byte for the type marker */ 191121663Sharti char *p = malloc(yyleng + 2); 192121663Sharti if (p == NULL) 193121663Sharti err(1, NULL); 194121663Sharti strlcpy(p, yytext, yyleng + 1); 195121663Sharti yylval.astr = p; 196121663Sharti return LETTER; 197121663Sharti } 198121663Sharti 199121663Sharti\\\n lineno++; 200121663Sharti\n lineno++; return NEWLINE; 201121663Sharti 202121663Sharti#[^\n]* ; 203121663Sharti[ \t] ; 204121663Sharti<<EOF>> return QUIT; 205121663Sharti. yyerror("illegal character"); 206121663Sharti 207121663Sharti%% 208121663Sharti 209121663Shartistatic void 210121663Shartiinit_strbuf(void) 211121663Sharti{ 212121663Sharti if (strbuf == NULL) { 213121663Sharti strbuf = malloc(strbuf_sz); 214121663Sharti if (strbuf == NULL) 215121663Sharti err(1, NULL); 216121663Sharti } 217121663Sharti strbuf[0] = '\0'; 218121663Sharti} 219121663Sharti 220135923Strhodesstatic void 221135923Strhodesadd_str(const char *str) 222135923Strhodes{ 223121663Sharti size_t arglen; 224135923Strhodes 225121663Sharti arglen = strlen(str); 226121663Sharti 227121663Sharti if (strlen(strbuf) + arglen + 1 > strbuf_sz) { 228121663Sharti size_t newsize; 229121663Sharti char *p; 230121663Sharti 231121663Sharti newsize = strbuf_sz + arglen + 1; 232121663Sharti p = realloc(strbuf, newsize); 233121663Sharti if (p == NULL) { 234121663Sharti free(strbuf); 235121663Sharti err(1, NULL); 236121663Sharti } 237121663Sharti strbuf_sz = newsize; 238121663Sharti strbuf = p; 239121663Sharti } 240121663Sharti strlcat(strbuf, str, strbuf_sz); 241121663Sharti} 242121663Sharti 243121663Sharti/* ARGSUSED */ 244121663Shartivoid 245121663Shartiabort_line(int sig __unused) 246121663Sharti{ 247121663Sharti static const char str1[] = "[\n]P\n"; 248121663Sharti static const char str2[] = "[^C\n]P\n"; 249121663Sharti int save_errno; 250121663Sharti const LineInfo *info; 251121663Sharti 252121663Sharti save_errno = errno; 253121663Sharti if (use_el) { 254121663Sharti write(STDOUT_FILENO, str2, sizeof(str2) - 1); 255121663Sharti info = el_line(el); 256121663Sharti skipchars = info->lastchar - info->buffer; 257121663Sharti } else 258121663Sharti write(STDOUT_FILENO, str1, sizeof(str1) - 1); 259121663Sharti errno = save_errno; 260121663Sharti} 261121663Sharti 262121663Sharti/* 263121663Sharti * Avoid the echo of ^D by the default code of editline and take 264121663Sharti * into account skipchars to make ^D work when the cursor is at start of 265121663Sharti * line after a ^C. 266121663Sharti */ 267121663Shartiunsigned char 268121663Shartibc_eof(EditLine *e, int ch __unused) 269121663Sharti{ 270121663Sharti const struct lineinfo *info = el_line(e); 271121663Sharti 272121663Sharti if (info->buffer + skipchars == info->cursor && 273121663Sharti info->cursor == info->lastchar) 274121663Sharti return (CC_EOF); 275121663Sharti else 276121663Sharti return (CC_ERROR); 277121663Sharti} 278121663Sharti 279121663Shartiint 280121663Shartiyywrap(void) 281121663Sharti{ 282121663Sharti static int state; 283121663Sharti static YY_BUFFER_STATE buf; 284121663Sharti 285121663Sharti if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 286121663Sharti filename = sargv[fileindex++]; 287121663Sharti yyin = fopen(filename, "r"); 288121663Sharti lineno = 1; 289121663Sharti if (yyin == NULL) 290121663Sharti err(1, "cannot open %s", filename); 291121663Sharti return (0); 292121663Sharti } 293121663Sharti if (state == 0 && cmdexpr[0] != '\0') { 294121663Sharti buf = yy_scan_string(cmdexpr); 295121663Sharti state++; 296121663Sharti lineno = 1; 297121663Sharti filename = "command line"; 298121663Sharti return (0); 299121663Sharti } else if (state == 1) { 300121663Sharti yy_delete_buffer(buf); 301121663Sharti free(cmdexpr); 302121663Sharti state++; 303121663Sharti } 304121663Sharti if (yyin != NULL && yyin != stdin) 305121663Sharti fclose(yyin); 306121663Sharti if (fileindex < sargc) { 307121663Sharti filename = sargv[fileindex++]; 308121663Sharti yyin = fopen(filename, "r"); 309121663Sharti lineno = 1; 310121663Sharti if (yyin == NULL) 311121663Sharti err(1, "cannot open %s", filename); 312121663Sharti return (0); 313121663Sharti } else if (fileindex == sargc) { 314121663Sharti fileindex++; 315121663Sharti yyin = stdin; 316121663Sharti if (interactive) { 317121663Sharti signal(SIGINT, abort_line); 318121663Sharti signal(SIGTSTP, tstpcont); 319121663Sharti } 320121663Sharti lineno = 1; 321121663Sharti filename = "stdin"; 322121663Sharti return (0); 323121663Sharti } 324121663Sharti return (1); 325121663Sharti} 326121663Sharti 327121663Shartistatic int 328121663Shartibc_yyinput(char *buf, int maxlen) 329121663Sharti{ 330121663Sharti int num; 331121663Sharti 332121663Sharti if (el != NULL) 333121663Sharti el_get(el, EL_EDITMODE, &use_el); 334121663Sharti 335121663Sharti if (yyin == stdin && interactive && use_el) { 336121663Sharti const char *bp; 337121663Sharti sigset_t oset, nset; 338121663Sharti 339121663Sharti if ((bp = el_gets(el, &num)) == NULL || num == 0) 340121663Sharti return (0); 341121663Sharti sigemptyset(&nset); 342121663Sharti sigaddset(&nset, SIGINT); 343121663Sharti sigprocmask(SIG_BLOCK, &nset, &oset); 344121663Sharti if (skipchars < num) { 345121663Sharti bp += skipchars; 346121663Sharti num -= skipchars; 347121663Sharti } 348121663Sharti skipchars = 0; 349121663Sharti sigprocmask(SIG_SETMASK, &oset, NULL); 350121663Sharti if (num > maxlen) { 351121663Sharti el_push(el, bp + maxlen); 352121663Sharti num = maxlen; 353121663Sharti } 354121663Sharti memcpy(buf, bp, num); 355121663Sharti history(hist, &he, H_ENTER, bp); 356121663Sharti el_get(el, EL_EDITMODE, &use_el); 357121663Sharti } else { 358121663Sharti int c = '*'; 359121663Sharti for (num = 0; num < maxlen && 360121663Sharti (c = getc(yyin)) != EOF && c != '\n'; ++num) 361121663Sharti buf[num] = (char) c; 362121663Sharti if (c == '\n') 363121663Sharti buf[num++] = (char) c; 364121663Sharti if (c == EOF && ferror(yyin)) 365121663Sharti YY_FATAL_ERROR( "input in flex scanner failed" ); 366121663Sharti } 367121663Sharti return (num); 368121663Sharti} 369121663Sharti 370121663Sharti 371121663Sharti