%{ /* $OpenBSD: scan.l,v 1.23 2009/10/27 23:59:36 deraadt Exp $ */ /* * Copyright (c) 2003, Otto Moerbeek * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "extern.h" #include "bc.h" #include "pathnames.h" int lineno; bool interactive; HistEvent he; EditLine *el; History *hist; static char *strbuf = NULL; static size_t strbuf_sz = 1; static bool dot_seen; static void init_strbuf(void); static void add_str(const char *); static int bc_yyinput(char *, int); #define YY_NO_INPUT #undef YY_INPUT #define YY_INPUT(buf,retval,max) \ (retval = bc_yyinput(buf, max)) %} %option always-interactive DIGIT [0-9A-F] ALPHA [a-z_] ALPHANUM [a-z_0-9] %x comment string number %% "/*" BEGIN(comment); { "*/" BEGIN(INITIAL); \n lineno++; \* ; [^*\n]+ ; <> fatal("end of file in comment"); } \" BEGIN(string); init_strbuf(); { [^"\n\\\[\]]+ add_str(yytext); \[ add_str("\\["); \] add_str("\\]"); \\ add_str("\\\\"); \n add_str("\n"); lineno++; \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; <> fatal("end of file in string"); } {DIGIT}+ { BEGIN(number); dot_seen = false; init_strbuf(); add_str(yytext); } \. { BEGIN(number); dot_seen = true; init_strbuf(); add_str("."); } { {DIGIT}+ add_str(yytext); \. { if (dot_seen) { BEGIN(INITIAL); yylval.str = strbuf; unput('.'); return (NUMBER); } else { dot_seen = true; add_str("."); } } \\\n[ \t]* lineno++; [^0-9A-F\.] { BEGIN(INITIAL); unput(yytext[0]); if (strcmp(strbuf, ".") == 0) return (DOT); else { yylval.str = strbuf; return (NUMBER); } } } "auto" return (AUTO); "break" return (BREAK); "continue" return (CONTINUE); "define" return (DEFINE); "else" return (ELSE); "ibase" return (IBASE); "if" return (IF); "last" return (DOT); "for" return (FOR); "length" return (LENGTH); "obase" return (OBASE); "print" return (PRINT); "quit" return (QUIT); "return" return (RETURN); "scale" return (SCALE); "sqrt" return (SQRT); "while" return (WHILE); "^" return (EXPONENT); "*" return (MULTIPLY); "/" return (DIVIDE); "%" return (REMAINDER); "!" return (BOOL_NOT); "&&" return (BOOL_AND); "||" return (BOOL_OR); "+" return (PLUS); "-" return (MINUS); "++" return (INCR); "--" return (DECR); "=" yylval.str = ""; return (ASSIGN_OP); "+=" yylval.str = "+"; return (ASSIGN_OP); "-=" yylval.str = "-"; return (ASSIGN_OP); "*=" yylval.str = "*"; return (ASSIGN_OP); "/=" yylval.str = "/"; return (ASSIGN_OP); "%=" yylval.str = "%"; return (ASSIGN_OP); "^=" yylval.str = "^"; return (ASSIGN_OP); "==" return (EQUALS); "<=" return (LESS_EQ); ">=" return (GREATER_EQ); "!=" return (UNEQUALS); "<" return (LESS); ">" return (GREATER); "," return (COMMA); ";" return (SEMICOLON); "(" return (LPAR); ")" return (RPAR); "[" return (LBRACKET); "]" return (RBRACKET); "{" return (LBRACE); "}" return (RBRACE); {ALPHA}{ALPHANUM}* { /* alloc an extra byte for the type marker */ char *p = malloc(yyleng + 2); if (p == NULL) err(1, NULL); strlcpy(p, yytext, yyleng + 1); yylval.astr = p; return (LETTER); } \\\n lineno++; \n lineno++; return (NEWLINE); #[^\n]* ; [ \t] ; <> return (QUIT); . yyerror("illegal character"); %% static void init_strbuf(void) { if (strbuf == NULL) { strbuf = malloc(strbuf_sz); if (strbuf == NULL) err(1, NULL); } strbuf[0] = '\0'; } static void add_str(const char *str) { size_t arglen; arglen = strlen(str); if (strlen(strbuf) + arglen + 1 > strbuf_sz) { size_t newsize; char *p; newsize = strbuf_sz + arglen + 1; p = realloc(strbuf, newsize); if (p == NULL) { free(strbuf); err(1, NULL); } strbuf_sz = newsize; strbuf = p; } strlcat(strbuf, str, strbuf_sz); } int yywrap(void) { static YY_BUFFER_STATE buf; static int state; if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { filename = sargv[fileindex++]; yyin = fopen(filename, "r"); lineno = 1; if (yyin == NULL) err(1, "cannot open %s", filename); return (0); } if (state == 0 && cmdexpr[0] != '\0') { buf = yy_scan_string(cmdexpr); state++; lineno = 1; filename = "command line"; return (0); } else if (state == 1) { yy_delete_buffer(buf); free(cmdexpr); state++; } if (yyin != NULL && yyin != stdin) fclose(yyin); if (fileindex < sargc) { filename = sargv[fileindex++]; yyin = fopen(filename, "r"); lineno = 1; if (yyin == NULL) err(1, "cannot open %s", filename); return (0); } else if (fileindex == sargc) { fileindex++; yyin = stdin; lineno = 1; filename = "stdin"; return (0); } return (1); } static int bc_yyinput(char *buf, int maxlen) { int num; if (yyin == stdin && interactive) { const char *bp; if ((bp = el_gets(el, &num)) == NULL || num == 0) return (0); if (num > maxlen) { el_push(el, (char *)(uintptr_t)(bp) + maxlen); num = maxlen; } memcpy(buf, bp, num); history(hist, &he, H_ENTER, bp); } else { int c = '*'; for (num = 0; num < maxlen && (c = getc(yyin)) != EOF && c != '\n'; ++num) buf[num] = (char) c; if (c == '\n') buf[num++] = (char) c; if (c == EOF && ferror(yyin)) YY_FATAL_ERROR( "input in flex scanner failed" ); } return (num); }