1202719Sgabor%{ 2264573Sdelphij/* $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$"); 22202719Sgabor 23202719Sgabor#include <err.h> 24202719Sgabor#include <errno.h> 25203498Sdelphij#include <histedit.h> 26202719Sgabor#include <stdbool.h> 27264573Sdelphij#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 35264573Sdelphijint lineno; 36264573Sdelphijbool interactive; 37202719Sgabor 38203498SdelphijHistEvent he; 39203498SdelphijEditLine *el; 40203498SdelphijHistory *hist; 41203498Sdelphij 42202719Sgaborstatic char *strbuf = NULL; 43264573Sdelphijstatic size_t strbuf_sz = 1; 44264573Sdelphijstatic bool dot_seen; 45264573Sdelphijstatic int use_el; 46264573Sdelphijstatic volatile sig_atomic_t skipchars; 47202719Sgabor 48264573Sdelphijstatic void init_strbuf(void); 49264573Sdelphijstatic void add_str(const char *); 50264573Sdelphij 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)) 58264573Sdelphij 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('.'); 110264573Sdelphij 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) 121264573Sdelphij return DOT; 122202719Sgabor else { 123202719Sgabor yylval.str = strbuf; 124264573Sdelphij return NUMBER; 125202719Sgabor } 126202719Sgabor } 127202719Sgabor} 128202719Sgabor 129264573Sdelphij"auto" return AUTO; 130264573Sdelphij"break" return BREAK; 131264573Sdelphij"continue" return CONTINUE; 132264573Sdelphij"define" return DEFINE; 133264573Sdelphij"else" return ELSE; 134264573Sdelphij"ibase" return IBASE; 135264573Sdelphij"if" return IF; 136264573Sdelphij"last" return DOT; 137264573Sdelphij"for" return FOR; 138264573Sdelphij"length" return LENGTH; 139264573Sdelphij"obase" return OBASE; 140264573Sdelphij"print" return PRINT; 141264573Sdelphij"quit" return QUIT; 142264573Sdelphij"return" return RETURN; 143264573Sdelphij"scale" return SCALE; 144264573Sdelphij"sqrt" return SQRT; 145264573Sdelphij"while" return WHILE; 146202719Sgabor 147264573Sdelphij"^" return EXPONENT; 148264573Sdelphij"*" return MULTIPLY; 149264573Sdelphij"/" return DIVIDE; 150264573Sdelphij"%" return REMAINDER; 151202719Sgabor 152264573Sdelphij"!" return BOOL_NOT; 153264573Sdelphij"&&" return BOOL_AND; 154264573Sdelphij"||" return BOOL_OR; 155202719Sgabor 156264573Sdelphij"+" return PLUS; 157264573Sdelphij"-" return MINUS; 158202719Sgabor 159264573Sdelphij"++" return INCR; 160264573Sdelphij"--" return DECR; 161202719Sgabor 162264573Sdelphij"=" yylval.str = ""; return ASSIGN_OP; 163264573Sdelphij"+=" yylval.str = "+"; return ASSIGN_OP; 164264573Sdelphij"-=" yylval.str = "-"; return ASSIGN_OP; 165264573Sdelphij"*=" yylval.str = "*"; return ASSIGN_OP; 166264573Sdelphij"/=" yylval.str = "/"; return ASSIGN_OP; 167264573Sdelphij"%=" yylval.str = "%"; return ASSIGN_OP; 168264573Sdelphij"^=" yylval.str = "^"; return ASSIGN_OP; 169202719Sgabor 170264573Sdelphij"==" return EQUALS; 171264573Sdelphij"<=" return LESS_EQ; 172264573Sdelphij">=" return GREATER_EQ; 173264573Sdelphij"!=" return UNEQUALS; 174264573Sdelphij"<" return LESS; 175264573Sdelphij">" return GREATER; 176202719Sgabor 177264573Sdelphij"," return COMMA; 178264573Sdelphij";" return SEMICOLON; 179202719Sgabor 180264573Sdelphij"(" return LPAR; 181264573Sdelphij")" return RPAR; 182202719Sgabor 183264573Sdelphij"[" return LBRACKET; 184264573Sdelphij"]" return RBRACKET; 185202719Sgabor 186264573Sdelphij"{" return LBRACE; 187264573Sdelphij"}" 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; 196264573Sdelphij return LETTER; 197202719Sgabor } 198202719Sgabor 199202719Sgabor\\\n lineno++; 200264573Sdelphij\n lineno++; return NEWLINE; 201202719Sgabor 202202719Sgabor#[^\n]* ; 203202719Sgabor[ \t] ; 204264573Sdelphij<<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) { 228264573Sdelphij size_t newsize; 229264573Sdelphij 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 243264573Sdelphij/* ARGSUSED */ 244264573Sdelphijvoid 245264573Sdelphijabort_line(int sig __unused) 246264573Sdelphij{ 247264573Sdelphij static const char str1[] = "[\n]P\n"; 248264573Sdelphij static const char str2[] = "[^C\n]P\n"; 249264573Sdelphij int save_errno; 250264573Sdelphij const LineInfo *info; 251264573Sdelphij 252264573Sdelphij save_errno = errno; 253264573Sdelphij if (use_el) { 254264573Sdelphij write(STDOUT_FILENO, str2, sizeof(str2) - 1); 255264573Sdelphij info = el_line(el); 256264573Sdelphij skipchars = info->lastchar - info->buffer; 257264573Sdelphij } else 258264573Sdelphij write(STDOUT_FILENO, str1, sizeof(str1) - 1); 259264573Sdelphij errno = save_errno; 260264573Sdelphij} 261264573Sdelphij 262264573Sdelphij/* 263264573Sdelphij * Avoid the echo of ^D by the default code of editline and take 264264573Sdelphij * into account skipchars to make ^D work when the cursor is at start of 265264573Sdelphij * line after a ^C. 266264573Sdelphij */ 267264573Sdelphijunsigned char 268264573Sdelphijbc_eof(EditLine *e, int ch __unused) 269264573Sdelphij{ 270264573Sdelphij const struct lineinfo *info = el_line(e); 271264573Sdelphij 272264573Sdelphij if (info->buffer + skipchars == info->cursor && 273264573Sdelphij info->cursor == info->lastchar) 274264573Sdelphij return (CC_EOF); 275264573Sdelphij else 276264573Sdelphij return (CC_ERROR); 277264573Sdelphij} 278264573Sdelphij 279202719Sgaborint 280202719Sgaboryywrap(void) 281202719Sgabor{ 282264573Sdelphij 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; 316264573Sdelphij if (interactive) { 317264573Sdelphij signal(SIGINT, abort_line); 318264573Sdelphij signal(SIGTSTP, tstpcont); 319264573Sdelphij } 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; 331264573Sdelphij 332264573Sdelphij if (el != NULL) 333264573Sdelphij el_get(el, EL_EDITMODE, &use_el); 334264573Sdelphij 335264573Sdelphij if (yyin == stdin && interactive && use_el) { 336203498Sdelphij const char *bp; 337264573Sdelphij sigset_t oset, nset; 338203498Sdelphij 339203498Sdelphij if ((bp = el_gets(el, &num)) == NULL || num == 0) 340203498Sdelphij return (0); 341264573Sdelphij sigemptyset(&nset); 342264573Sdelphij sigaddset(&nset, SIGINT); 343264573Sdelphij sigprocmask(SIG_BLOCK, &nset, &oset); 344264573Sdelphij if (skipchars < num) { 345264573Sdelphij bp += skipchars; 346264573Sdelphij num -= skipchars; 347264573Sdelphij } 348264573Sdelphij skipchars = 0; 349264573Sdelphij sigprocmask(SIG_SETMASK, &oset, NULL); 350203498Sdelphij if (num > maxlen) { 351264609Sbz el_push(el, bp + maxlen); 352203498Sdelphij num = maxlen; 353203498Sdelphij } 354203498Sdelphij memcpy(buf, bp, num); 355203498Sdelphij history(hist, &he, H_ENTER, bp); 356264573Sdelphij 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 370264573Sdelphij 371