1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
5 Permission to use, copy, modify, and distribute this software and
6 its documentation for any purpose and without fee is hereby
7 granted, provided that the above copyright notice appear in all
8 copies and that both that the copyright notice and this
9 permission notice and warranty disclaimer appear in supporting
10 documentation, and that the name Lucent Technologies or any of
11 its entities not be used in advertising or publicity pertaining
12 to distribution of the software without specific, written prior
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23 ****************************************************************/
32 extern YYSTYPE yylval;
40 typedef struct Keyword {
46 Keyword keywords[] ={ /* keep sorted: binary searched */
47 { "BEGIN", XBEGIN, XBEGIN },
48 { "END", XEND, XEND },
49 { "NF", VARNF, VARNF },
50 { "atan2", FATAN, BLTIN },
51 { "break", BREAK, BREAK },
52 { "close", CLOSE, CLOSE },
53 { "continue", CONTINUE, CONTINUE },
54 { "cos", FCOS, BLTIN },
55 { "delete", DELETE, DELETE },
57 { "else", ELSE, ELSE },
58 { "exit", EXIT, EXIT },
59 { "exp", FEXP, BLTIN },
60 { "fflush", FFLUSH, BLTIN },
62 { "func", FUNC, FUNC },
63 { "function", FUNC, FUNC },
64 { "getline", GETLINE, GETLINE },
65 { "gsub", GSUB, GSUB },
68 { "index", INDEX, INDEX },
69 { "int", FINT, BLTIN },
70 { "length", FLENGTH, BLTIN },
71 { "log", FLOG, BLTIN },
72 { "match", MATCHFCN, MATCHFCN },
73 { "next", NEXT, NEXT },
74 { "nextfile", NEXTFILE, NEXTFILE },
75 { "print", PRINT, PRINT },
76 { "printf", PRINTF, PRINTF },
77 { "rand", FRAND, BLTIN },
78 { "return", RETURN, RETURN },
79 { "sin", FSIN, BLTIN },
80 { "split", SPLIT, SPLIT },
81 { "sprintf", SPRINTF, SPRINTF },
82 { "sqrt", FSQRT, BLTIN },
83 { "srand", FSRAND, BLTIN },
85 { "substr", SUBSTR, SUBSTR },
86 { "system", FSYSTEM, BLTIN },
87 { "tolower", FTOLOWER, BLTIN },
88 { "toupper", FTOUPPER, BLTIN },
89 { "while", WHILE, WHILE },
94 #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
96 #define RET(x) return(x)
106 int gettok(char **pbuf, int *psz) /* get next input token */
118 if (!isalnum(c) && c != '.' && c != '_')
122 if (isalpha(c) || c == '_') { /* it's a varname */
123 for ( ; (c = input()) != 0; ) {
125 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
126 FATAL( "out of space for name %.10s...", buf );
127 if (isalnum(c) || c == '_')
136 retc = 'a'; /* alphanumeric */
137 } else { /* maybe it's a number, but could be . */
139 /* read input until can't be a number */
140 for ( ; (c = input()) != 0; ) {
142 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
143 FATAL( "out of space for number %.10s...", buf );
144 if (isdigit(c) || c == 'e' || c == 'E'
145 || c == '.' || c == '+' || c == '-')
153 strtod(buf, &rem); /* parse the number */
154 if (rem == buf) { /* it wasn't a valid number at all */
155 buf[1] = 0; /* return one character as token */
156 retc = buf[0]; /* character is its own type */
157 unputstr(rem+1); /* put rest back for later */
158 } else { /* some prefix was a number */
159 unputstr(rem); /* put rest back for later */
160 rem[0] = 0; /* truncate buf after number part */
161 retc = '0'; /* type is number */
172 int sc = 0; /* 1 => return a } right now */
173 int reg = 0; /* 1 => return a REGEXPR now */
178 static char *buf = 0;
179 static int bufsize = 500;
181 if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
182 FATAL( "out of space in yylex" );
191 /* printf("top\n"); */
193 c = gettok(&buf, &bufsize);
194 /* printf("gettok [%s]\n", buf); */
197 if (isalpha(c) || c == '_')
200 yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
201 /* should this also have STR set? */
207 case '\n': /* {EOL} */
209 case '\r': /* assume \n is coming */
210 case ' ': /* {WS}+ */
213 case '#': /* #.* strip comments */
214 while ((c = input()) != '\n' && c != 0)
221 if (peek() == '\n') {
223 } else if (peek() == '\r') {
224 input(); input(); /* \n */
242 input(); yylval.i = NE; RET(NE);
243 } else if (peek() == '~') {
244 input(); yylval.i = NOTMATCH; RET(MATCHOP);
252 input(); yylval.i = LE; RET(LE);
254 yylval.i = LT; RET(LT);
258 input(); yylval.i = EQ; RET(EQ);
260 yylval.i = ASSIGN; RET(ASGNOP);
264 input(); yylval.i = GE; RET(GE);
265 } else if (peek() == '>') {
266 input(); yylval.i = APPEND; RET(APPEND);
268 yylval.i = GT; RET(GT);
272 input(); yylval.i = INCR; RET(INCR);
273 } else if (peek() == '=') {
274 input(); yylval.i = ADDEQ; RET(ASGNOP);
279 input(); yylval.i = DECR; RET(DECR);
280 } else if (peek() == '=') {
281 input(); yylval.i = SUBEQ; RET(ASGNOP);
285 if (peek() == '=') { /* *= */
286 input(); yylval.i = MULTEQ; RET(ASGNOP);
287 } else if (peek() == '*') { /* ** or **= */
288 input(); /* eat 2nd * */
290 input(); yylval.i = POWEQ; RET(ASGNOP);
300 input(); yylval.i = MODEQ; RET(ASGNOP);
305 input(); yylval.i = POWEQ; RET(ASGNOP);
310 /* BUG: awkward, if not wrong */
311 c = gettok(&buf, &bufsize);
313 if (strcmp(buf, "NF") == 0) { /* very special */
318 if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
322 yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
324 } else if (c == 0) { /* */
325 SYNTAX( "unexpected end of input after $" );
356 return string(); /* BUG: should be like tran.c ? */
368 static char *buf = 0;
369 static int bufsz = 500;
371 if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
372 FATAL("out of space for strings");
373 for (bp = buf; (c = input()) != '"'; ) {
374 if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0))
375 FATAL("out of space for string %.10s...", buf);
380 SYNTAX( "non-terminated string %.10s...", buf );
382 if (c == 0) /* hopeless */
383 FATAL( "giving up" );
388 case '"': *bp++ = '"'; break;
389 case 'n': *bp++ = '\n'; break;
390 case 't': *bp++ = '\t'; break;
391 case 'f': *bp++ = '\f'; break;
392 case 'r': *bp++ = '\r'; break;
393 case 'b': *bp++ = '\b'; break;
394 case 'v': *bp++ = '\v'; break;
395 case 'a': *bp++ = '\007'; break;
396 case '\\': *bp++ = '\\'; break;
398 case '0': case '1': case '2': /* octal: \d \dd \ddd */
399 case '3': case '4': case '5': case '6': case '7':
401 if ((c = peek()) >= '0' && c < '8') {
402 n = 8 * n + input() - '0';
403 if ((c = peek()) >= '0' && c < '8')
404 n = 8 * n + input() - '0';
409 case 'x': /* hex \x0-9a-fA-F + */
410 { char xbuf[100], *px;
411 for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
413 || (c >= 'a' && c <= 'f')
414 || (c >= 'A' && c <= 'F'))
421 sscanf(xbuf, "%x", &n);
438 *bp++ = ' '; *bp++ = 0;
439 yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
444 int binsearch(char *w, Keyword *kp, int n)
446 int cond, low, mid, high;
450 while (low <= high) {
451 mid = (low + high) / 2;
452 if ((cond = strcmp(w, kp[mid].word)) < 0)
467 n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
469 if (n != -1) { /* found in table */
471 switch (kp->type) { /* special handling */
474 SYNTAX( "system is unsafe" );
478 SYNTAX( "illegal nested function" );
482 SYNTAX( "return not in function" );
485 yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
491 c = peek(); /* look for '(' */
492 if (c != '(' && infunc && (n=isarg(w)) >= 0) {
496 yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
505 void startreg(void) /* next call to yylex will return a regular expression */
513 static char *buf = 0;
514 static int bufsz = 500;
517 if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
518 FATAL("out of space for rex expr");
520 for ( ; (c = input()) != '/' && c != 0; ) {
521 if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0))
522 FATAL("out of space for reg expr %.10s...", buf);
524 SYNTAX( "newline in regular expression %.10s...", buf );
527 } else if (c == '\\') {
536 SYNTAX("non-terminated regular expression %.10s...", buf);
537 yylval.s = tostring(buf);
542 /* low-level lexical stuff, sort of inherited from lex */
546 char yysbuf[100]; /* pushback buffer */
547 char *yysptr = yysbuf;
550 int input(void) /* get next lexical input character */
553 extern char *lexprog;
556 c = (uschar)*--yysptr;
557 else if (lexprog != NULL) { /* awk '...' */
558 if ((c = (uschar)*lexprog) != 0)
560 } else /* awk -f ... */
566 if (ep >= ebuf + sizeof ebuf)
571 void unput(int c) /* put lexical character back on input */
575 if (yysptr >= yysbuf + sizeof(yysbuf))
576 FATAL("pushed back too much: %.20s...", yysbuf);
579 ep = ebuf + sizeof(ebuf) - 1;
582 void unputstr(const char *s) /* put a string back on input */
586 for (i = strlen(s)-1; i >= 0; i--)