%{ /* $OpenBSD: scan.l,v 1.22 2008/12/15 19:46:29 otto Exp $ */ /* * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> * * 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. */ #ifndef lint static const char rcsid[] = "$OpenBSD: scan.l,v 1.22 2008/12/15 19:46:29 otto Exp $"; #endif /* not lint */ #include <err.h> #include <signal.h> #include <stdbool.h> #include <string.h> #include <unistd.h> #include "extern.h" #include "pathnames.h" #include "y.tab.h" int lineno; bool interactive; 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 *); %} %option always-interactive DIGIT [0-9A-F] ALPHA [a-z_] ALPHANUM [a-z_0-9] %x comment string number %% "/*" BEGIN(comment); <comment>{ "*/" BEGIN(INITIAL); \n lineno++; \* ; [^*\n]+ ; <<EOF>> fatal("end of file in comment"); } \" BEGIN(string); init_strbuf(); <string>{ [^"\n\\\[\]]+ add_str(yytext); \[ add_str("\\["); \] add_str("\\]"); \\ add_str("\\\\"); \n add_str("\n"); lineno++; \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; <<EOF>> 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("."); } <number>{ {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] ; <<EOF>> 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); } /* ARGSUSED */ void abort_line(int sig) { static const char str[] = "[\n]P\n"; int save_errno; save_errno = errno; YY_FLUSH_BUFFER; /* XXX signal race? */ write(STDOUT_FILENO, str, sizeof(str) - 1); errno = save_errno; } int yywrap(void) { static int state; static YY_BUFFER_STATE buf; 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; if (interactive) signal(SIGINT, abort_line); lineno = 1; filename = "stdin"; return (0); } return (1); }