1 %{ 2 /* 3 * $OpenBSD: scan.l,v 1.21 2006/03/18 20:44:43 otto Exp $ 4 * $DragonFly: src/usr.bin/bc/scan.l,v 1.3 2007/09/01 18:42:08 pavalos Exp $ 5 */ 6 7 /* 8 * Copyright (c) 2003, Otto Moerbeek <otto@drijf.net> 9 * 10 * Permission to use, copy, modify, and distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23 #include <err.h> 24 #include <errno.h> 25 #include <signal.h> 26 #include <stdbool.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "extern.h" 31 #include "pathnames.h" 32 #include "y.tab.h" 33 34 #define YY_NO_INPUT 35 36 int lineno; 37 bool interactive; 38 39 static char *strbuf = NULL; 40 static size_t strbuf_sz = 1; 41 static bool dot_seen; 42 43 static void init_strbuf(void); 44 static void add_str(const char *); 45 46 %} 47 48 %option always-interactive 49 50 DIGIT [0-9A-F] 51 ALPHA [a-z_] 52 ALPHANUM [a-z_0-9] 53 54 %x comment string number 55 56 %% 57 58 "/*" BEGIN(comment); 59 <comment>{ 60 "*/" BEGIN(INITIAL); 61 \n lineno++; 62 \* ; 63 [^*\n]+ ; 64 <<EOF>> fatal("end of file in comment"); 65 } 66 67 \" BEGIN(string); init_strbuf(); 68 <string>{ 69 [^"\n\\\[\]]+ add_str(yytext); 70 \[ add_str("\\["); 71 \] add_str("\\]"); 72 \\ add_str("\\\\"); 73 \n add_str("\n"); lineno++; 74 \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; 75 <<EOF>> fatal("end of file in string"); 76 } 77 78 {DIGIT}+ { 79 BEGIN(number); 80 dot_seen = false; 81 init_strbuf(); 82 add_str(yytext); 83 } 84 \. { 85 BEGIN(number); 86 dot_seen = true; 87 init_strbuf(); 88 add_str("."); 89 } 90 <number>{ 91 {DIGIT}+ add_str(yytext); 92 \. { 93 if (dot_seen) { 94 BEGIN(INITIAL); 95 yylval.str = strbuf; 96 unput('.'); 97 return NUMBER; 98 } else { 99 dot_seen = true; 100 add_str("."); 101 } 102 } 103 \\\n[ \t]* lineno++; 104 [^0-9A-F\.] { 105 BEGIN(INITIAL); 106 unput(yytext[0]); 107 if (strcmp(strbuf, ".") == 0) 108 return DOT; 109 else { 110 yylval.str = strbuf; 111 return NUMBER; 112 } 113 } 114 } 115 116 "auto" return AUTO; 117 "break" return BREAK; 118 "continue" return CONTINUE; 119 "define" return DEFINE; 120 "else" return ELSE; 121 "ibase" return IBASE; 122 "if" return IF; 123 "last" return DOT; 124 "for" return FOR; 125 "length" return LENGTH; 126 "obase" return OBASE; 127 "print" return PRINT; 128 "quit" return QUIT; 129 "return" return RETURN; 130 "scale" return SCALE; 131 "sqrt" return SQRT; 132 "while" return WHILE; 133 134 "^" return EXPONENT; 135 "*" return MULTIPLY; 136 "/" return DIVIDE; 137 "%" return REMAINDER; 138 139 "!" return BOOL_NOT; 140 "&&" return BOOL_AND; 141 "||" return BOOL_OR; 142 143 "+" return PLUS; 144 "-" return MINUS; 145 146 "++" return INCR; 147 "--" return DECR; 148 149 "=" yylval.str = ""; return ASSIGN_OP; 150 "+=" yylval.str = "+"; return ASSIGN_OP; 151 "-=" yylval.str = "-"; return ASSIGN_OP; 152 "*=" yylval.str = "*"; return ASSIGN_OP; 153 "/=" yylval.str = "/"; return ASSIGN_OP; 154 "%=" yylval.str = "%"; return ASSIGN_OP; 155 "^=" yylval.str = "^"; return ASSIGN_OP; 156 157 "==" return EQUALS; 158 "<=" return LESS_EQ; 159 ">=" return GREATER_EQ; 160 "!=" return UNEQUALS; 161 "<" return LESS; 162 ">" return GREATER; 163 164 "," return COMMA; 165 ";" return SEMICOLON; 166 167 "(" return LPAR; 168 ")" return RPAR; 169 170 "[" return LBRACKET; 171 "]" return RBRACKET; 172 173 "{" return LBRACE; 174 "}" return RBRACE; 175 176 {ALPHA}{ALPHANUM}* { 177 /* alloc an extra byte for the type marker */ 178 char *p = malloc(yyleng + 2); 179 if (p == NULL) 180 err(1, NULL); 181 strlcpy(p, yytext, yyleng + 1); 182 yylval.astr = p; 183 return LETTER; 184 } 185 186 \\\n lineno++; 187 \n lineno++; return NEWLINE; 188 189 #[^\n]* ; 190 [ \t] ; 191 <<EOF>> return QUIT; 192 . yyerror("illegal character"); 193 194 %% 195 196 static void 197 init_strbuf(void) 198 { 199 if (strbuf == NULL) { 200 strbuf = malloc(strbuf_sz); 201 if (strbuf == NULL) 202 err(1, NULL); 203 } 204 strbuf[0] = '\0'; 205 } 206 207 static void 208 add_str(const char *str) 209 { 210 size_t arglen; 211 212 arglen = strlen(str); 213 214 if (strlen(strbuf) + arglen + 1 > strbuf_sz) { 215 size_t newsize; 216 char *p; 217 218 newsize = strbuf_sz + arglen + 1; 219 p = realloc(strbuf, newsize); 220 if (p == NULL) { 221 free(strbuf); 222 err(1, NULL); 223 } 224 strbuf_sz = newsize; 225 strbuf = p; 226 } 227 strlcat(strbuf, str, strbuf_sz); 228 } 229 230 /* ARGSUSED */ 231 void 232 abort_line(int sig) 233 { 234 const char str[] = "[\n]P\n"; 235 int save_errno; 236 237 save_errno = errno; 238 YY_FLUSH_BUFFER; /* XXX signal race? */ 239 write(STDOUT_FILENO, str, sizeof(str) - 1); 240 errno = save_errno; 241 } 242 243 int 244 yywrap(void) 245 { 246 static int state; 247 static YY_BUFFER_STATE buf; 248 249 if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 250 filename = sargv[fileindex++]; 251 yyin = fopen(filename, "r"); 252 lineno = 1; 253 if (yyin == NULL) 254 err(1, "cannot open %s", filename); 255 return (0); 256 } 257 if (state == 0 && cmdexpr[0] != '\0') { 258 buf = yy_scan_string(cmdexpr); 259 state++; 260 lineno = 1; 261 filename = "command line"; 262 return (0); 263 } else if (state == 1) { 264 yy_delete_buffer(buf); 265 free(cmdexpr); 266 state++; 267 } 268 if (yyin != NULL && yyin != stdin) 269 fclose(yyin); 270 if (fileindex < sargc) { 271 filename = sargv[fileindex++]; 272 yyin = fopen(filename, "r"); 273 lineno = 1; 274 if (yyin == NULL) 275 err(1, "cannot open %s", filename); 276 return (0); 277 } else if (fileindex == sargc) { 278 fileindex++; 279 yyin = stdin; 280 if (interactive) 281 signal(SIGINT, abort_line); 282 lineno = 1; 283 filename = "stdin"; 284 return (0); 285 } 286 return (1); 287 } 288