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