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