1%{ 2/* $OpenBSD: scan.l,v 1.28 2013/09/19 16:12:01 otto 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#include <err.h> 22#include <errno.h> 23#include <histedit.h> 24#include <stdbool.h> 25#include <signal.h> 26#include <string.h> 27#include <unistd.h> 28 29#include "extern.h" 30#include "bc.h" 31#include "pathnames.h" 32 33int lineno; 34bool interactive; 35 36HistEvent he; 37EditLine *el; 38History *hist; 39 40static char *strbuf = NULL; 41static size_t strbuf_sz = 1; 42static bool dot_seen; 43static int use_el; 44static volatile sig_atomic_t skipchars; 45 46static void init_strbuf(void); 47static void add_str(const char *); 48 49static int bc_yyinput(char *, int); 50 51#define YY_DECL int yylex(void) 52#define YY_NO_INPUT 53#undef YY_INPUT 54#define YY_INPUT(buf,retval,max) \ 55 (retval = bc_yyinput(buf, max)) 56 57%} 58 59%option always-interactive 60 61DIGIT [0-9A-F] 62ALPHA [a-z_] 63ALPHANUM [a-z_0-9] 64 65%x comment string number 66 67%% 68 69"/*" BEGIN(comment); 70<comment>{ 71 "*/" BEGIN(INITIAL); 72 \n lineno++; 73 \* ; 74 [^*\n]+ ; 75 <<EOF>> fatal("end of file in comment"); 76} 77 78\" BEGIN(string); init_strbuf(); 79<string>{ 80 [^"\n\\\[\]]+ add_str(yytext); 81 \[ add_str("\\["); 82 \] add_str("\\]"); 83 \\ add_str("\\\\"); 84 \n add_str("\n"); lineno++; 85 \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; 86 <<EOF>> fatal("end of file in string"); 87} 88 89{DIGIT}+ { 90 BEGIN(number); 91 dot_seen = false; 92 init_strbuf(); 93 add_str(yytext); 94 } 95\. { 96 BEGIN(number); 97 dot_seen = true; 98 init_strbuf(); 99 add_str("."); 100 } 101<number>{ 102 {DIGIT}+ add_str(yytext); 103 \. { 104 if (dot_seen) { 105 BEGIN(INITIAL); 106 yylval.str = strbuf; 107 unput('.'); 108 return NUMBER; 109 } else { 110 dot_seen = true; 111 add_str("."); 112 } 113 } 114 \\\n[ \t]* lineno++; 115 [^0-9A-F\.] { 116 BEGIN(INITIAL); 117 unput(yytext[0]); 118 if (strcmp(strbuf, ".") == 0) 119 return DOT; 120 else { 121 yylval.str = strbuf; 122 return NUMBER; 123 } 124 } 125} 126 127"auto" return AUTO; 128"break" return BREAK; 129"continue" return CONTINUE; 130"define" return DEFINE; 131"else" return ELSE; 132"ibase" return IBASE; 133"if" return IF; 134"last" return DOT; 135"for" return FOR; 136"length" return LENGTH; 137"obase" return OBASE; 138"print" return PRINT; 139"quit" return QUIT; 140"return" return RETURN; 141"scale" return SCALE; 142"sqrt" return SQRT; 143"while" return WHILE; 144 145"^" return EXPONENT; 146"*" return MULTIPLY; 147"/" return DIVIDE; 148"%" return REMAINDER; 149 150"!" return BOOL_NOT; 151"&&" return BOOL_AND; 152"||" return BOOL_OR; 153 154"+" return PLUS; 155"-" return MINUS; 156 157"++" return INCR; 158"--" return DECR; 159 160"=" yylval.str = ""; return ASSIGN_OP; 161"+=" yylval.str = "+"; return ASSIGN_OP; 162"-=" yylval.str = "-"; return ASSIGN_OP; 163"*=" yylval.str = "*"; return ASSIGN_OP; 164"/=" yylval.str = "/"; return ASSIGN_OP; 165"%=" yylval.str = "%"; return ASSIGN_OP; 166"^=" yylval.str = "^"; return ASSIGN_OP; 167 168"==" return EQUALS; 169"<=" return LESS_EQ; 170">=" return GREATER_EQ; 171"!=" return UNEQUALS; 172"<" return LESS; 173">" return GREATER; 174 175"," return COMMA; 176";" return SEMICOLON; 177 178"(" return LPAR; 179")" return RPAR; 180 181"[" return LBRACKET; 182"]" return RBRACKET; 183 184"{" return LBRACE; 185"}" return RBRACE; 186 187{ALPHA}{ALPHANUM}* { 188 /* alloc an extra byte for the type marker */ 189 char *p = malloc(yyleng + 2); 190 if (p == NULL) 191 err(1, NULL); 192 strlcpy(p, yytext, yyleng + 1); 193 yylval.astr = p; 194 return LETTER; 195 } 196 197\\\n lineno++; 198\n lineno++; return NEWLINE; 199 200#[^\n]* ; 201[ \t] ; 202<<EOF>> return QUIT; 203. yyerror("illegal character"); 204 205%% 206 207static void 208init_strbuf(void) 209{ 210 if (strbuf == NULL) { 211 strbuf = malloc(strbuf_sz); 212 if (strbuf == NULL) 213 err(1, NULL); 214 } 215 strbuf[0] = '\0'; 216} 217 218static void 219add_str(const char *str) 220{ 221 size_t arglen; 222 223 arglen = strlen(str); 224 225 if (strlen(strbuf) + arglen + 1 > strbuf_sz) { 226 size_t newsize; 227 char *p; 228 229 newsize = strbuf_sz + arglen + 1; 230 p = realloc(strbuf, newsize); 231 if (p == NULL) { 232 free(strbuf); 233 err(1, NULL); 234 } 235 strbuf_sz = newsize; 236 strbuf = p; 237 } 238 strlcat(strbuf, str, strbuf_sz); 239} 240 241/* ARGSUSED */ 242void 243abort_line(int sig __unused) 244{ 245 static const char str1[] = "[\n]P\n"; 246 static const char str2[] = "[^C\n]P\n"; 247 int save_errno; 248 const LineInfo *info; 249 250 save_errno = errno; 251 if (use_el) { 252 write(STDOUT_FILENO, str2, sizeof(str2) - 1); 253 info = el_line(el); 254 skipchars = info->lastchar - info->buffer; 255 } else 256 write(STDOUT_FILENO, str1, sizeof(str1) - 1); 257 errno = save_errno; 258} 259 260/* 261 * Avoid the echo of ^D by the default code of editline and take 262 * into account skipchars to make ^D work when the cursor is at start of 263 * line after a ^C. 264 */ 265unsigned char 266bc_eof(EditLine *e, int ch __unused) 267{ 268 const struct lineinfo *info = el_line(e); 269 270 if (info->buffer + skipchars == info->cursor && 271 info->cursor == info->lastchar) 272 return (CC_EOF); 273 else 274 return (CC_ERROR); 275} 276 277int 278yywrap(void) 279{ 280 static int state; 281 static YY_BUFFER_STATE buf; 282 283 if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 284 filename = sargv[fileindex++]; 285 yyin = fopen(filename, "r"); 286 lineno = 1; 287 if (yyin == NULL) 288 err(1, "cannot open %s", filename); 289 return (0); 290 } 291 if (state == 0 && cmdexpr[0] != '\0') { 292 buf = yy_scan_string(cmdexpr); 293 state++; 294 lineno = 1; 295 filename = "command line"; 296 return (0); 297 } else if (state == 1) { 298 yy_delete_buffer(buf); 299 free(cmdexpr); 300 state++; 301 } 302 if (yyin != NULL && yyin != stdin) 303 fclose(yyin); 304 if (fileindex < sargc) { 305 filename = sargv[fileindex++]; 306 yyin = fopen(filename, "r"); 307 lineno = 1; 308 if (yyin == NULL) 309 err(1, "cannot open %s", filename); 310 return (0); 311 } else if (fileindex == sargc) { 312 fileindex++; 313 yyin = stdin; 314 if (interactive) { 315 signal(SIGINT, abort_line); 316 signal(SIGTSTP, tstpcont); 317 } 318 lineno = 1; 319 filename = "stdin"; 320 return (0); 321 } 322 return (1); 323} 324 325static int 326bc_yyinput(char *buf, int maxlen) 327{ 328 int num; 329 330 if (el != NULL) 331 el_get(el, EL_EDITMODE, &use_el); 332 333 if (yyin == stdin && interactive && use_el) { 334 const char *bp; 335 sigset_t oset, nset; 336 337 if ((bp = el_gets(el, &num)) == NULL || num == 0) 338 return (0); 339 sigemptyset(&nset); 340 sigaddset(&nset, SIGINT); 341 sigprocmask(SIG_BLOCK, &nset, &oset); 342 if (skipchars < num) { 343 bp += skipchars; 344 num -= skipchars; 345 } 346 skipchars = 0; 347 sigprocmask(SIG_SETMASK, &oset, NULL); 348 if (num > maxlen) { 349 el_push(el, bp + maxlen); 350 num = maxlen; 351 } 352 memcpy(buf, bp, num); 353 history(hist, &he, H_ENTER, bp); 354 el_get(el, EL_EDITMODE, &use_el); 355 } else { 356 int c = '*'; 357 for (num = 0; num < maxlen && 358 (c = getc(yyin)) != EOF && c != '\n'; ++num) 359 buf[num] = (char) c; 360 if (c == '\n') 361 buf[num++] = (char) c; 362 if (c == EOF && ferror(yyin)) 363 YY_FATAL_ERROR( "input in flex scanner failed" ); 364 } 365 return (num); 366} 367 368 369