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