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