1 1.1 christos /**************************************************************** 2 1.1 christos Copyright (C) Lucent Technologies 1997 3 1.1 christos All Rights Reserved 4 1.1 christos 5 1.1 christos Permission to use, copy, modify, and distribute this software and 6 1.1 christos its documentation for any purpose and without fee is hereby 7 1.1 christos granted, provided that the above copyright notice appear in all 8 1.1 christos copies and that both that the copyright notice and this 9 1.1 christos permission notice and warranty disclaimer appear in supporting 10 1.1 christos documentation, and that the name Lucent Technologies or any of 11 1.1 christos its entities not be used in advertising or publicity pertaining 12 1.1 christos to distribution of the software without specific, written prior 13 1.1 christos permission. 14 1.1 christos 15 1.1 christos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 1.1 christos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 17 1.1 christos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 18 1.1 christos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 1.1 christos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 20 1.1 christos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 21 1.1 christos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 22 1.1 christos THIS SOFTWARE. 23 1.1 christos ****************************************************************/ 24 1.1 christos 25 1.2 christos #if HAVE_NBTOOL_CONFIG_H 26 1.2 christos #include "nbtool_config.h" 27 1.2 christos #endif 28 1.2 christos 29 1.1 christos #include <stdio.h> 30 1.1 christos #include <stdlib.h> 31 1.1 christos #include <string.h> 32 1.1 christos #include <ctype.h> 33 1.1 christos #include "awk.h" 34 1.2 christos #include "awkgram.h" 35 1.1 christos 36 1.1 christos extern YYSTYPE yylval; 37 1.8 christos extern bool infunc; 38 1.1 christos 39 1.1 christos int lineno = 1; 40 1.1 christos int bracecnt = 0; 41 1.1 christos int brackcnt = 0; 42 1.1 christos int parencnt = 0; 43 1.1 christos 44 1.1 christos typedef struct Keyword { 45 1.1 christos const char *word; 46 1.1 christos int sub; 47 1.1 christos int type; 48 1.1 christos } Keyword; 49 1.1 christos 50 1.6 christos const Keyword keywords[] = { /* keep sorted: binary searched */ 51 1.1 christos { "BEGIN", XBEGIN, XBEGIN }, 52 1.1 christos { "END", XEND, XEND }, 53 1.1 christos { "NF", VARNF, VARNF }, 54 1.6 christos { "and", FAND, BLTIN }, 55 1.1 christos { "atan2", FATAN, BLTIN }, 56 1.1 christos { "break", BREAK, BREAK }, 57 1.1 christos { "close", CLOSE, CLOSE }, 58 1.6 christos { "compl", FCOMPL, BLTIN }, 59 1.1 christos { "continue", CONTINUE, CONTINUE }, 60 1.1 christos { "cos", FCOS, BLTIN }, 61 1.1 christos { "delete", DELETE, DELETE }, 62 1.1 christos { "do", DO, DO }, 63 1.1 christos { "else", ELSE, ELSE }, 64 1.1 christos { "exit", EXIT, EXIT }, 65 1.1 christos { "exp", FEXP, BLTIN }, 66 1.1 christos { "fflush", FFLUSH, BLTIN }, 67 1.1 christos { "for", FOR, FOR }, 68 1.1 christos { "func", FUNC, FUNC }, 69 1.1 christos { "function", FUNC, FUNC }, 70 1.2 christos { "gensub", GENSUB, GENSUB }, 71 1.1 christos { "getline", GETLINE, GETLINE }, 72 1.1 christos { "gsub", GSUB, GSUB }, 73 1.1 christos { "if", IF, IF }, 74 1.1 christos { "in", IN, IN }, 75 1.1 christos { "index", INDEX, INDEX }, 76 1.1 christos { "int", FINT, BLTIN }, 77 1.1 christos { "length", FLENGTH, BLTIN }, 78 1.1 christos { "log", FLOG, BLTIN }, 79 1.6 christos { "lshift", FLSHIFT, BLTIN }, 80 1.1 christos { "match", MATCHFCN, MATCHFCN }, 81 1.8 christos { "mktime", FMKTIME, BLTIN }, 82 1.1 christos { "next", NEXT, NEXT }, 83 1.1 christos { "nextfile", NEXTFILE, NEXTFILE }, 84 1.6 christos { "or", FFOR, BLTIN }, 85 1.1 christos { "print", PRINT, PRINT }, 86 1.1 christos { "printf", PRINTF, PRINTF }, 87 1.1 christos { "rand", FRAND, BLTIN }, 88 1.1 christos { "return", RETURN, RETURN }, 89 1.6 christos { "rshift", FRSHIFT, BLTIN }, 90 1.1 christos { "sin", FSIN, BLTIN }, 91 1.1 christos { "split", SPLIT, SPLIT }, 92 1.1 christos { "sprintf", SPRINTF, SPRINTF }, 93 1.1 christos { "sqrt", FSQRT, BLTIN }, 94 1.1 christos { "srand", FSRAND, BLTIN }, 95 1.2 christos { "strftime", FSTRFTIME, BLTIN }, 96 1.1 christos { "sub", SUB, SUB }, 97 1.1 christos { "substr", SUBSTR, SUBSTR }, 98 1.1 christos { "system", FSYSTEM, BLTIN }, 99 1.2 christos { "systime", FSYSTIME, BLTIN }, 100 1.1 christos { "tolower", FTOLOWER, BLTIN }, 101 1.1 christos { "toupper", FTOUPPER, BLTIN }, 102 1.1 christos { "while", WHILE, WHILE }, 103 1.6 christos { "xor", FXOR, BLTIN }, 104 1.1 christos }; 105 1.1 christos 106 1.1 christos #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); } 107 1.1 christos 108 1.6 christos static int peek(void) 109 1.1 christos { 110 1.1 christos int c = input(); 111 1.1 christos unput(c); 112 1.1 christos return c; 113 1.1 christos } 114 1.1 christos 115 1.6 christos static int gettok(char **pbuf, int *psz) /* get next input token */ 116 1.1 christos { 117 1.1 christos int c, retc; 118 1.6 christos char *buf = *pbuf; 119 1.1 christos int sz = *psz; 120 1.6 christos char *bp = buf; 121 1.1 christos 122 1.1 christos c = input(); 123 1.1 christos if (c == 0) 124 1.1 christos return 0; 125 1.1 christos buf[0] = c; 126 1.1 christos buf[1] = 0; 127 1.1 christos if (!isalnum(c) && c != '.' && c != '_') 128 1.1 christos return c; 129 1.1 christos 130 1.1 christos *bp++ = c; 131 1.1 christos if (isalpha(c) || c == '_') { /* it's a varname */ 132 1.1 christos for ( ; (c = input()) != 0; ) { 133 1.1 christos if (bp-buf >= sz) 134 1.1 christos if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok")) 135 1.1 christos FATAL( "out of space for name %.10s...", buf ); 136 1.1 christos if (isalnum(c) || c == '_') 137 1.1 christos *bp++ = c; 138 1.1 christos else { 139 1.1 christos *bp = 0; 140 1.1 christos unput(c); 141 1.1 christos break; 142 1.1 christos } 143 1.1 christos } 144 1.1 christos *bp = 0; 145 1.1 christos retc = 'a'; /* alphanumeric */ 146 1.1 christos } else { /* maybe it's a number, but could be . */ 147 1.1 christos char *rem; 148 1.1 christos /* read input until can't be a number */ 149 1.1 christos for ( ; (c = input()) != 0; ) { 150 1.1 christos if (bp-buf >= sz) 151 1.1 christos if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok")) 152 1.1 christos FATAL( "out of space for number %.10s...", buf ); 153 1.5 christos if (isdigit(c) || c == 'e' || c == 'E' 154 1.1 christos || c == '.' || c == '+' || c == '-') 155 1.1 christos *bp++ = c; 156 1.1 christos else { 157 1.1 christos unput(c); 158 1.1 christos break; 159 1.1 christos } 160 1.1 christos } 161 1.1 christos *bp = 0; 162 1.1 christos strtod(buf, &rem); /* parse the number */ 163 1.6 christos if (rem == buf) { /* it wasn't a valid number at all */ 164 1.1 christos buf[1] = 0; /* return one character as token */ 165 1.8 christos retc = (uschar)buf[0]; /* character is its own type */ 166 1.1 christos unputstr(rem+1); /* put rest back for later */ 167 1.1 christos } else { /* some prefix was a number */ 168 1.1 christos unputstr(rem); /* put rest back for later */ 169 1.1 christos rem[0] = 0; /* truncate buf after number part */ 170 1.1 christos retc = '0'; /* type is number */ 171 1.1 christos } 172 1.1 christos } 173 1.1 christos *pbuf = buf; 174 1.1 christos *psz = sz; 175 1.1 christos return retc; 176 1.1 christos } 177 1.1 christos 178 1.1 christos int word(char *); 179 1.1 christos int string(void); 180 1.1 christos int regexpr(void); 181 1.6 christos bool sc = false; /* true => return a } right now */ 182 1.6 christos bool reg = false; /* true => return a REGEXPR now */ 183 1.1 christos 184 1.1 christos int yylex(void) 185 1.1 christos { 186 1.1 christos int c; 187 1.6 christos static char *buf = NULL; 188 1.1 christos static int bufsize = 5; /* BUG: setting this small causes core dump! */ 189 1.1 christos 190 1.8 christos if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL) 191 1.1 christos FATAL( "out of space in yylex" ); 192 1.1 christos if (sc) { 193 1.6 christos sc = false; 194 1.1 christos RET('}'); 195 1.1 christos } 196 1.1 christos if (reg) { 197 1.6 christos reg = false; 198 1.1 christos return regexpr(); 199 1.1 christos } 200 1.1 christos for (;;) { 201 1.1 christos c = gettok(&buf, &bufsize); 202 1.1 christos if (c == 0) 203 1.1 christos return 0; 204 1.1 christos if (isalpha(c) || c == '_') 205 1.1 christos return word(buf); 206 1.1 christos if (isdigit(c)) { 207 1.6 christos char *cp = tostring(buf); 208 1.8 christos double result; 209 1.8 christos 210 1.8 christos if (is_number(cp, & result)) 211 1.8 christos yylval.cp = setsymtab(buf, cp, result, CON|NUM, symtab); 212 1.8 christos else 213 1.8 christos yylval.cp = setsymtab(buf, cp, 0.0, STR, symtab); 214 1.6 christos free(cp); 215 1.1 christos /* should this also have STR set? */ 216 1.1 christos RET(NUMBER); 217 1.1 christos } 218 1.5 christos 219 1.1 christos yylval.i = c; 220 1.1 christos switch (c) { 221 1.1 christos case '\n': /* {EOL} */ 222 1.6 christos lineno++; 223 1.1 christos RET(NL); 224 1.1 christos case '\r': /* assume \n is coming */ 225 1.1 christos case ' ': /* {WS}+ */ 226 1.1 christos case '\t': 227 1.1 christos break; 228 1.1 christos case '#': /* #.* strip comments */ 229 1.1 christos while ((c = input()) != '\n' && c != 0) 230 1.1 christos ; 231 1.1 christos unput(c); 232 1.1 christos break; 233 1.1 christos case ';': 234 1.1 christos RET(';'); 235 1.1 christos case '\\': 236 1.1 christos if (peek() == '\n') { 237 1.1 christos input(); 238 1.6 christos lineno++; 239 1.1 christos } else if (peek() == '\r') { 240 1.1 christos input(); input(); /* \n */ 241 1.1 christos lineno++; 242 1.1 christos } else { 243 1.1 christos RET(c); 244 1.1 christos } 245 1.1 christos break; 246 1.1 christos case '&': 247 1.1 christos if (peek() == '&') { 248 1.1 christos input(); RET(AND); 249 1.5 christos } else 250 1.1 christos RET('&'); 251 1.1 christos case '|': 252 1.1 christos if (peek() == '|') { 253 1.1 christos input(); RET(BOR); 254 1.1 christos } else 255 1.1 christos RET('|'); 256 1.1 christos case '!': 257 1.1 christos if (peek() == '=') { 258 1.1 christos input(); yylval.i = NE; RET(NE); 259 1.1 christos } else if (peek() == '~') { 260 1.1 christos input(); yylval.i = NOTMATCH; RET(MATCHOP); 261 1.1 christos } else 262 1.1 christos RET(NOT); 263 1.1 christos case '~': 264 1.1 christos yylval.i = MATCH; 265 1.1 christos RET(MATCHOP); 266 1.1 christos case '<': 267 1.1 christos if (peek() == '=') { 268 1.1 christos input(); yylval.i = LE; RET(LE); 269 1.1 christos } else { 270 1.1 christos yylval.i = LT; RET(LT); 271 1.1 christos } 272 1.1 christos case '=': 273 1.1 christos if (peek() == '=') { 274 1.1 christos input(); yylval.i = EQ; RET(EQ); 275 1.1 christos } else { 276 1.1 christos yylval.i = ASSIGN; RET(ASGNOP); 277 1.1 christos } 278 1.1 christos case '>': 279 1.1 christos if (peek() == '=') { 280 1.1 christos input(); yylval.i = GE; RET(GE); 281 1.1 christos } else if (peek() == '>') { 282 1.1 christos input(); yylval.i = APPEND; RET(APPEND); 283 1.1 christos } else { 284 1.1 christos yylval.i = GT; RET(GT); 285 1.1 christos } 286 1.1 christos case '+': 287 1.1 christos if (peek() == '+') { 288 1.1 christos input(); yylval.i = INCR; RET(INCR); 289 1.1 christos } else if (peek() == '=') { 290 1.1 christos input(); yylval.i = ADDEQ; RET(ASGNOP); 291 1.1 christos } else 292 1.1 christos RET('+'); 293 1.1 christos case '-': 294 1.1 christos if (peek() == '-') { 295 1.1 christos input(); yylval.i = DECR; RET(DECR); 296 1.1 christos } else if (peek() == '=') { 297 1.1 christos input(); yylval.i = SUBEQ; RET(ASGNOP); 298 1.1 christos } else 299 1.1 christos RET('-'); 300 1.1 christos case '*': 301 1.1 christos if (peek() == '=') { /* *= */ 302 1.1 christos input(); yylval.i = MULTEQ; RET(ASGNOP); 303 1.1 christos } else if (peek() == '*') { /* ** or **= */ 304 1.1 christos input(); /* eat 2nd * */ 305 1.1 christos if (peek() == '=') { 306 1.1 christos input(); yylval.i = POWEQ; RET(ASGNOP); 307 1.1 christos } else { 308 1.1 christos RET(POWER); 309 1.1 christos } 310 1.1 christos } else 311 1.1 christos RET('*'); 312 1.1 christos case '/': 313 1.1 christos RET('/'); 314 1.1 christos case '%': 315 1.1 christos if (peek() == '=') { 316 1.1 christos input(); yylval.i = MODEQ; RET(ASGNOP); 317 1.1 christos } else 318 1.1 christos RET('%'); 319 1.1 christos case '^': 320 1.1 christos if (peek() == '=') { 321 1.1 christos input(); yylval.i = POWEQ; RET(ASGNOP); 322 1.1 christos } else 323 1.1 christos RET(POWER); 324 1.1 christos 325 1.1 christos case '$': 326 1.1 christos /* BUG: awkward, if not wrong */ 327 1.1 christos c = gettok(&buf, &bufsize); 328 1.1 christos if (isalpha(c)) { 329 1.1 christos if (strcmp(buf, "NF") == 0) { /* very special */ 330 1.1 christos unputstr("(NF)"); 331 1.1 christos RET(INDIRECT); 332 1.1 christos } 333 1.1 christos c = peek(); 334 1.1 christos if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) { 335 1.1 christos unputstr(buf); 336 1.1 christos RET(INDIRECT); 337 1.1 christos } 338 1.1 christos yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab); 339 1.1 christos RET(IVAR); 340 1.1 christos } else if (c == 0) { /* */ 341 1.1 christos SYNTAX( "unexpected end of input after $" ); 342 1.1 christos RET(';'); 343 1.1 christos } else { 344 1.1 christos unputstr(buf); 345 1.1 christos RET(INDIRECT); 346 1.1 christos } 347 1.5 christos 348 1.1 christos case '}': 349 1.1 christos if (--bracecnt < 0) 350 1.1 christos SYNTAX( "extra }" ); 351 1.6 christos sc = true; 352 1.1 christos RET(';'); 353 1.1 christos case ']': 354 1.1 christos if (--brackcnt < 0) 355 1.1 christos SYNTAX( "extra ]" ); 356 1.1 christos RET(']'); 357 1.1 christos case ')': 358 1.1 christos if (--parencnt < 0) 359 1.1 christos SYNTAX( "extra )" ); 360 1.1 christos RET(')'); 361 1.1 christos case '{': 362 1.1 christos bracecnt++; 363 1.1 christos RET('{'); 364 1.1 christos case '[': 365 1.1 christos brackcnt++; 366 1.1 christos RET('['); 367 1.1 christos case '(': 368 1.1 christos parencnt++; 369 1.1 christos RET('('); 370 1.5 christos 371 1.1 christos case '"': 372 1.1 christos return string(); /* BUG: should be like tran.c ? */ 373 1.5 christos 374 1.1 christos default: 375 1.1 christos RET(c); 376 1.1 christos } 377 1.1 christos } 378 1.1 christos } 379 1.1 christos 380 1.1 christos int string(void) 381 1.1 christos { 382 1.1 christos int c, n; 383 1.6 christos char *s, *bp; 384 1.6 christos static char *buf = NULL; 385 1.1 christos static int bufsz = 500; 386 1.1 christos 387 1.8 christos if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL) 388 1.1 christos FATAL("out of space for strings"); 389 1.1 christos for (bp = buf; (c = input()) != '"'; ) { 390 1.1 christos if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string")) 391 1.1 christos FATAL("out of space for string %.10s...", buf); 392 1.1 christos switch (c) { 393 1.1 christos case '\n': 394 1.1 christos case '\r': 395 1.1 christos case 0: 396 1.6 christos *bp = '\0'; 397 1.1 christos SYNTAX( "non-terminated string %.10s...", buf ); 398 1.1 christos if (c == 0) /* hopeless */ 399 1.1 christos FATAL( "giving up" ); 400 1.6 christos lineno++; 401 1.1 christos break; 402 1.1 christos case '\\': 403 1.1 christos c = input(); 404 1.1 christos switch (c) { 405 1.7 christos case '\n': break; 406 1.1 christos case '"': *bp++ = '"'; break; 407 1.5 christos case 'n': *bp++ = '\n'; break; 408 1.1 christos case 't': *bp++ = '\t'; break; 409 1.1 christos case 'f': *bp++ = '\f'; break; 410 1.1 christos case 'r': *bp++ = '\r'; break; 411 1.1 christos case 'b': *bp++ = '\b'; break; 412 1.1 christos case 'v': *bp++ = '\v'; break; 413 1.6 christos case 'a': *bp++ = '\a'; break; 414 1.1 christos case '\\': *bp++ = '\\'; break; 415 1.1 christos 416 1.1 christos case '0': case '1': case '2': /* octal: \d \dd \ddd */ 417 1.1 christos case '3': case '4': case '5': case '6': case '7': 418 1.1 christos n = c - '0'; 419 1.1 christos if ((c = peek()) >= '0' && c < '8') { 420 1.1 christos n = 8 * n + input() - '0'; 421 1.1 christos if ((c = peek()) >= '0' && c < '8') 422 1.1 christos n = 8 * n + input() - '0'; 423 1.1 christos } 424 1.1 christos *bp++ = n; 425 1.1 christos break; 426 1.1 christos 427 1.8 christos case 'x': /* hex \x0-9a-fA-F (exactly two) */ 428 1.8 christos { 429 1.8 christos int i; 430 1.8 christos 431 1.8 christos if (!isxdigit(peek())) { 432 1.8 christos unput(c); 433 1.8 christos break; 434 1.8 christos } 435 1.8 christos n = 0; 436 1.8 christos for (i = 0; i < 2; i++) { 437 1.8 christos c = input(); 438 1.8 christos if (c == 0) 439 1.8 christos break; 440 1.8 christos if (isxdigit(c)) { 441 1.8 christos c = tolower(c); 442 1.8 christos n *= 16; 443 1.8 christos if (isdigit(c)) 444 1.8 christos n += (c - '0'); 445 1.8 christos else 446 1.8 christos n += 10 + (c - 'a'); 447 1.8 christos } else { 448 1.8 christos unput(c); 449 1.8 christos break; 450 1.8 christos } 451 1.8 christos } 452 1.8 christos if (i) 453 1.8 christos *bp++ = n; 454 1.8 christos break; 455 1.8 christos } 456 1.8 christos 457 1.8 christos case 'u': /* utf \u0-9a-fA-F (1..8) */ 458 1.8 christos { 459 1.8 christos int i; 460 1.8 christos 461 1.8 christos n = 0; 462 1.8 christos for (i = 0; i < 8; i++) { 463 1.8 christos c = input(); 464 1.8 christos if (!isxdigit(c) || c == 0) 465 1.8 christos break; 466 1.8 christos c = tolower(c); 467 1.8 christos n *= 16; 468 1.8 christos if (isdigit(c)) 469 1.8 christos n += (c - '0'); 470 1.1 christos else 471 1.8 christos n += 10 + (c - 'a'); 472 1.1 christos } 473 1.1 christos unput(c); 474 1.8 christos bp += runetochar(bp, n); 475 1.1 christos break; 476 1.1 christos } 477 1.1 christos 478 1.2 christos default: 479 1.1 christos *bp++ = c; 480 1.1 christos break; 481 1.1 christos } 482 1.1 christos break; 483 1.1 christos default: 484 1.1 christos *bp++ = c; 485 1.1 christos break; 486 1.1 christos } 487 1.1 christos } 488 1.5 christos *bp = 0; 489 1.1 christos s = tostring(buf); 490 1.6 christos *bp++ = ' '; *bp++ = '\0'; 491 1.1 christos yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab); 492 1.6 christos free(s); 493 1.1 christos RET(STRING); 494 1.1 christos } 495 1.1 christos 496 1.1 christos 497 1.6 christos static int binsearch(char *w, const Keyword *kp, int n) 498 1.1 christos { 499 1.1 christos int cond, low, mid, high; 500 1.1 christos 501 1.1 christos low = 0; 502 1.1 christos high = n - 1; 503 1.1 christos while (low <= high) { 504 1.1 christos mid = (low + high) / 2; 505 1.1 christos if ((cond = strcmp(w, kp[mid].word)) < 0) 506 1.1 christos high = mid - 1; 507 1.1 christos else if (cond > 0) 508 1.1 christos low = mid + 1; 509 1.1 christos else 510 1.1 christos return mid; 511 1.1 christos } 512 1.1 christos return -1; 513 1.1 christos } 514 1.1 christos 515 1.5 christos int word(char *w) 516 1.1 christos { 517 1.2 christos const Keyword *kp; 518 1.1 christos int c, n; 519 1.1 christos 520 1.1 christos n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0])); 521 1.1 christos if (n != -1) { /* found in table */ 522 1.4 kamil kp = keywords + n; 523 1.1 christos yylval.i = kp->sub; 524 1.1 christos switch (kp->type) { /* special handling */ 525 1.1 christos case BLTIN: 526 1.1 christos if (kp->sub == FSYSTEM && safe) 527 1.1 christos SYNTAX( "system is unsafe" ); 528 1.1 christos RET(kp->type); 529 1.1 christos case FUNC: 530 1.1 christos if (infunc) 531 1.1 christos SYNTAX( "illegal nested function" ); 532 1.1 christos RET(kp->type); 533 1.1 christos case RETURN: 534 1.1 christos if (!infunc) 535 1.1 christos SYNTAX( "return not in function" ); 536 1.1 christos RET(kp->type); 537 1.1 christos case VARNF: 538 1.1 christos yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab); 539 1.1 christos RET(VARNF); 540 1.1 christos default: 541 1.1 christos RET(kp->type); 542 1.1 christos } 543 1.1 christos } 544 1.1 christos c = peek(); /* look for '(' */ 545 1.1 christos if (c != '(' && infunc && (n=isarg(w)) >= 0) { 546 1.1 christos yylval.i = n; 547 1.1 christos RET(ARG); 548 1.1 christos } else { 549 1.1 christos yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab); 550 1.1 christos if (c == '(') { 551 1.1 christos RET(CALL); 552 1.1 christos } else { 553 1.1 christos RET(VAR); 554 1.1 christos } 555 1.1 christos } 556 1.1 christos } 557 1.1 christos 558 1.1 christos void startreg(void) /* next call to yylex will return a regular expression */ 559 1.1 christos { 560 1.6 christos reg = true; 561 1.1 christos } 562 1.1 christos 563 1.1 christos int regexpr(void) 564 1.1 christos { 565 1.1 christos int c; 566 1.6 christos static char *buf = NULL; 567 1.1 christos static int bufsz = 500; 568 1.6 christos char *bp; 569 1.1 christos 570 1.8 christos if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL) 571 1.8 christos FATAL("out of space for reg expr"); 572 1.1 christos bp = buf; 573 1.1 christos for ( ; (c = input()) != '/' && c != 0; ) { 574 1.1 christos if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr")) 575 1.1 christos FATAL("out of space for reg expr %.10s...", buf); 576 1.1 christos if (c == '\n') { 577 1.6 christos *bp = '\0'; 578 1.5 christos SYNTAX( "newline in regular expression %.10s...", buf ); 579 1.1 christos unput('\n'); 580 1.1 christos break; 581 1.1 christos } else if (c == '\\') { 582 1.5 christos *bp++ = '\\'; 583 1.1 christos *bp++ = input(); 584 1.1 christos } else { 585 1.1 christos *bp++ = c; 586 1.1 christos } 587 1.1 christos } 588 1.1 christos *bp = 0; 589 1.1 christos if (c == 0) 590 1.1 christos SYNTAX("non-terminated regular expression %.10s...", buf); 591 1.1 christos yylval.s = tostring(buf); 592 1.1 christos unput('/'); 593 1.1 christos RET(REGEXPR); 594 1.1 christos } 595 1.1 christos 596 1.1 christos /* low-level lexical stuff, sort of inherited from lex */ 597 1.1 christos 598 1.1 christos char ebuf[300]; 599 1.1 christos char *ep = ebuf; 600 1.1 christos char yysbuf[100]; /* pushback buffer */ 601 1.1 christos char *yysptr = yysbuf; 602 1.6 christos FILE *yyin = NULL; 603 1.1 christos 604 1.1 christos int input(void) /* get next lexical input character */ 605 1.1 christos { 606 1.1 christos int c; 607 1.1 christos extern char *lexprog; 608 1.1 christos 609 1.1 christos if (yysptr > yysbuf) 610 1.1 christos c = (uschar)*--yysptr; 611 1.1 christos else if (lexprog != NULL) { /* awk '...' */ 612 1.1 christos if ((c = (uschar)*lexprog) != 0) 613 1.1 christos lexprog++; 614 1.1 christos } else /* awk -f ... */ 615 1.1 christos c = pgetc(); 616 1.6 christos if (c == EOF) 617 1.1 christos c = 0; 618 1.1 christos if (ep >= ebuf + sizeof ebuf) 619 1.1 christos ep = ebuf; 620 1.6 christos *ep = c; 621 1.6 christos if (c != 0) { 622 1.6 christos ep++; 623 1.6 christos } 624 1.6 christos return (c); 625 1.1 christos } 626 1.1 christos 627 1.1 christos void unput(int c) /* put lexical character back on input */ 628 1.1 christos { 629 1.1 christos if (yysptr >= yysbuf + sizeof(yysbuf)) 630 1.1 christos FATAL("pushed back too much: %.20s...", yysbuf); 631 1.1 christos *yysptr++ = c; 632 1.1 christos if (--ep < ebuf) 633 1.1 christos ep = ebuf + sizeof(ebuf) - 1; 634 1.1 christos } 635 1.1 christos 636 1.1 christos void unputstr(const char *s) /* put a string back on input */ 637 1.1 christos { 638 1.1 christos int i; 639 1.1 christos 640 1.1 christos for (i = strlen(s)-1; i >= 0; i--) 641 1.1 christos unput(s[i]); 642 1.1 christos } 643