1 %{ 2 /* 3 * $OpenBSD: scan.l,v 1.18 2005/04/13 06:36:03 otto Exp $ 4 * $DragonFly: src/usr.bin/bc/scan.l,v 1.2 2005/04/21 18:50:22 swildner 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 int lineno; 35 36 static char *strbuf = NULL; 37 static size_t strbuf_sz = 1; 38 static bool dot_seen; 39 static volatile sig_atomic_t interactive = 0; 40 41 static void init_strbuf(void); 42 static void add_str(const char *); 43 44 %} 45 46 %option always-interactive 47 48 DIGIT [0-9A-F] 49 ALPHA [a-z_] 50 ALPHANUM [a-z_0-9] 51 52 %x comment string number 53 54 %% 55 56 "/*" BEGIN(comment); 57 <comment>{ 58 "*/" BEGIN(INITIAL); 59 \n lineno++; 60 \* ; 61 [^*\n]+ ; 62 <<EOF>> fatal("end of file in comment"); 63 } 64 65 \" BEGIN(string); init_strbuf(); 66 <string>{ 67 [^"\n\\\[\]]+ add_str(yytext); 68 \[ add_str("\\["); 69 \] add_str("\\]"); 70 \\ add_str("\\\\"); 71 \n add_str("\n"); lineno++; 72 \" BEGIN(INITIAL); yylval.str = strbuf; return STRING; 73 <<EOF>> fatal("end of file in string"); 74 } 75 76 {DIGIT}+ { 77 BEGIN(number); 78 dot_seen = false; 79 init_strbuf(); 80 add_str(yytext); 81 } 82 \. { 83 BEGIN(number); 84 dot_seen = true; 85 init_strbuf(); 86 add_str("."); 87 } 88 <number>{ 89 {DIGIT}+ add_str(yytext); 90 \. { 91 if (dot_seen) { 92 BEGIN(INITIAL); 93 yylval.str = strbuf; 94 unput('.'); 95 return NUMBER; 96 } else { 97 dot_seen = true; 98 add_str("."); 99 } 100 } 101 \\\n[ \t]* lineno++; 102 [^0-9A-F\.] { 103 BEGIN(INITIAL); 104 unput(yytext[0]); 105 if (strcmp(strbuf, ".") == 0) 106 return DOT; 107 else { 108 yylval.str = strbuf; 109 return NUMBER; 110 } 111 } 112 } 113 114 "auto" return AUTO; 115 "break" return BREAK; 116 "continue" return CONTINUE; 117 "define" return DEFINE; 118 "else" return ELSE; 119 "ibase" return IBASE; 120 "if" return IF; 121 "last" return DOT; 122 "for" return FOR; 123 "length" return LENGTH; 124 "obase" return OBASE; 125 "print" return PRINT; 126 "quit" return QUIT; 127 "return" return RETURN; 128 "scale" return SCALE; 129 "sqrt" return SQRT; 130 "while" return WHILE; 131 132 "^" return EXPONENT; 133 "*" return MULTIPLY; 134 "/" return DIVIDE; 135 "%" return REMAINDER; 136 137 "!" return BOOL_NOT; 138 "&&" return BOOL_AND; 139 "||" return BOOL_OR; 140 141 "+" return PLUS; 142 "-" return MINUS; 143 144 "++" return INCR; 145 "--" return DECR; 146 147 "=" yylval.str = ""; return ASSIGN_OP; 148 "+=" yylval.str = "+"; return ASSIGN_OP; 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 155 "==" return EQUALS; 156 "<=" return LESS_EQ; 157 ">=" return GREATER_EQ; 158 "!=" return UNEQUALS; 159 "<" return LESS; 160 ">" return GREATER; 161 162 "," return COMMA; 163 ";" return SEMICOLON; 164 165 "(" return LPAR; 166 ")" return RPAR; 167 168 "[" return LBRACKET; 169 "]" return RBRACKET; 170 171 "{" return LBRACE; 172 "}" return RBRACE; 173 174 {ALPHA}{ALPHANUM}* { 175 /* alloc an extra byte for the type marker */ 176 char *p = malloc(yyleng + 2); 177 if (p == NULL) 178 err(1, NULL); 179 strlcpy(p, yytext, yyleng + 1); 180 yylval.astr = p; 181 return LETTER; 182 } 183 184 \\\n lineno++; 185 \n lineno++; return NEWLINE; 186 187 #[^\n]* ; 188 [ \t] ; 189 <<EOF>> return QUIT; 190 . yyerror("illegal character"); 191 192 %% 193 194 static void 195 init_strbuf(void) 196 { 197 if (strbuf == NULL) { 198 strbuf = malloc(strbuf_sz); 199 if (strbuf == NULL) 200 err(1, NULL); 201 } 202 strbuf[0] = '\0'; 203 } 204 205 static void 206 add_str(const char *str) 207 { 208 size_t arglen; 209 210 arglen = strlen(str); 211 212 if (strlen(strbuf) + arglen + 1 > strbuf_sz) { 213 size_t newsize; 214 char *p; 215 216 newsize = strbuf_sz + arglen + 1; 217 p = realloc(strbuf, newsize); 218 if (p == NULL) { 219 free(strbuf); 220 err(1, NULL); 221 } 222 strbuf_sz = newsize; 223 strbuf = p; 224 } 225 strlcat(strbuf, str, strbuf_sz); 226 } 227 228 void 229 abort_line(int sig) 230 { 231 const char str[] = "[\n]P\n"; 232 int save_errno; 233 234 if (interactive) { 235 save_errno = errno; 236 YY_FLUSH_BUFFER; /* XXX signal race? */ 237 write(STDOUT_FILENO, str, sizeof(str) - 1); 238 errno = save_errno; 239 } 240 } 241 242 int 243 yywrap(void) 244 { 245 static int state; 246 static YY_BUFFER_STATE buf; 247 248 if (fileindex == 0 && sargc > 0 && strcmp(sargv[0], _PATH_LIBB) == 0) { 249 filename = sargv[fileindex++]; 250 yyin = fopen(filename, "r"); 251 lineno = 1; 252 if (yyin == NULL) 253 err(1, "cannot open %s", filename); 254 return (0); 255 } 256 if (state == 0 && cmdexpr[0] != '\0') { 257 buf = yy_scan_string(cmdexpr); 258 state++; 259 lineno = 1; 260 filename = "command line"; 261 return (0); 262 } else if (state == 1) { 263 yy_delete_buffer(buf); 264 free(cmdexpr); 265 state++; 266 } 267 if (fileindex < sargc) { 268 filename = sargv[fileindex++]; 269 yyin = fopen(filename, "r"); 270 lineno = 1; 271 if (yyin == NULL) 272 err(1, "cannot open %s", filename); 273 return (0); 274 } else if (fileindex == sargc) { 275 fileindex++; 276 yyin = stdin; 277 interactive = isatty(fileno(yyin)); 278 lineno = 1; 279 filename = "stdin"; 280 return (0); 281 } 282 return (1); 283 } 284