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 { "and", FAND, BLTIN },
51 { "atan2", FATAN, BLTIN },
52 { "break", BREAK, BREAK },
53 { "close", CLOSE, CLOSE },
54 { "compl", FCOMPL, BLTIN },
55 { "continue", CONTINUE, CONTINUE },
56 { "cos", FCOS, BLTIN },
57 { "delete", DELETE, DELETE },
59 { "else", ELSE, ELSE },
60 { "exit", EXIT, EXIT },
61 { "exp", FEXP, BLTIN },
62 { "fflush", FFLUSH, BLTIN },
64 { "func", FUNC, FUNC },
65 { "function", FUNC, FUNC },
66 { "getline", GETLINE, GETLINE },
67 { "gsub", GSUB, GSUB },
70 { "index", INDEX, INDEX },
71 { "int", FINT, BLTIN },
72 { "length", FLENGTH, BLTIN },
73 { "log", FLOG, BLTIN },
74 { "lshift", FLSHIFT, BLTIN },
75 { "match", MATCHFCN, MATCHFCN },
76 { "next", NEXT, NEXT },
77 { "nextfile", NEXTFILE, NEXTFILE },
78 { "or", FFOR, BLTIN },
79 { "print", PRINT, PRINT },
80 { "printf", PRINTF, PRINTF },
81 { "rand", FRAND, BLTIN },
82 { "return", RETURN, RETURN },
83 { "rshift", FRSHIFT, BLTIN },
84 { "sin", FSIN, BLTIN },
85 { "split", SPLIT, SPLIT },
86 { "sprintf", SPRINTF, SPRINTF },
87 { "sqrt", FSQRT, BLTIN },
88 { "srand", FSRAND, BLTIN },
90 { "substr", SUBSTR, SUBSTR },
91 { "system", FSYSTEM, BLTIN },
92 { "tolower", FTOLOWER, BLTIN },
93 { "toupper", FTOUPPER, BLTIN },
94 { "while", WHILE, WHILE },
95 { "xor", FXOR, BLTIN },
98 #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
107 int gettok(char **pbuf, int *psz) /* get next input token */
119 if (!isalnum(c) && c != '.' && c != '_')
123 if (isalpha(c) || c == '_') { /* it's a varname */
124 for ( ; (c = input()) != 0; ) {
126 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
127 FATAL( "out of space for name %.10s...", buf );
128 if (isalnum(c) || c == '_')
137 retc = 'a'; /* alphanumeric */
138 } else { /* maybe it's a number, but could be . */
140 /* read input until can't be a number */
141 for ( ; (c = input()) != 0; ) {
143 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
144 FATAL( "out of space for number %.10s...", buf );
145 if (isdigit(c) || c == 'e' || c == 'E'
146 || c == '.' || c == '+' || c == '-')
154 strtod(buf, &rem); /* parse the number */
155 if (rem == buf) { /* it wasn't a valid number at all */
156 buf[1] = 0; /* return one character as token */
157 retc = buf[0]; /* character is its own type */
158 unputstr(rem+1); /* put rest back for later */
159 } else { /* some prefix was a number */
160 unputstr(rem); /* put rest back for later */
161 rem[0] = 0; /* truncate buf after number part */
162 retc = '0'; /* type is number */
173 int sc = 0; /* 1 => return a } right now */
174 int reg = 0; /* 1 => return a REGEXPR now */
179 static char *buf = NULL;
180 static int bufsize = 5; /* BUG: setting this small causes core dump! */
182 if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL)
183 FATAL( "out of space in yylex" );
193 c = gettok(&buf, &bufsize);
196 if (isalpha(c) || c == '_')
199 yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
200 /* should this also have STR set? */
206 case '\n': /* {EOL} */
208 case '\r': /* assume \n is coming */
209 case ' ': /* {WS}+ */
212 case '#': /* #.* strip comments */
213 while ((c = input()) != '\n' && c != 0)
220 if (peek() == '\n') {
222 } else if (peek() == '\r') {
223 input(); input(); /* \n */
241 input(); yylval.i = NE; RET(NE);
242 } else if (peek() == '~') {
243 input(); yylval.i = NOTMATCH; RET(MATCHOP);
251 input(); yylval.i = LE; RET(LE);
253 yylval.i = LT; RET(LT);
257 input(); yylval.i = EQ; RET(EQ);
259 yylval.i = ASSIGN; RET(ASGNOP);
263 input(); yylval.i = GE; RET(GE);
264 } else if (peek() == '>') {
265 input(); yylval.i = APPEND; RET(APPEND);
267 yylval.i = GT; RET(GT);
271 input(); yylval.i = INCR; RET(INCR);
272 } else if (peek() == '=') {
273 input(); yylval.i = ADDEQ; RET(ASGNOP);
278 input(); yylval.i = DECR; RET(DECR);
279 } else if (peek() == '=') {
280 input(); yylval.i = SUBEQ; RET(ASGNOP);
284 if (peek() == '=') { /* *= */
285 input(); yylval.i = MULTEQ; RET(ASGNOP);
286 } else if (peek() == '*') { /* ** or **= */
287 input(); /* eat 2nd * */
289 input(); yylval.i = POWEQ; RET(ASGNOP);
299 input(); yylval.i = MODEQ; RET(ASGNOP);
304 input(); yylval.i = POWEQ; RET(ASGNOP);
309 /* BUG: awkward, if not wrong */
310 c = gettok(&buf, &bufsize);
312 if (strcmp(buf, "NF") == 0) { /* very special */
317 if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
321 yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
323 } else if (c == 0) { /* */
324 SYNTAX( "unexpected end of input after $" );
355 return string(); /* BUG: should be like tran.c ? */
367 static char *buf = NULL;
368 static int bufsz = 500;
370 if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
371 FATAL("out of space for strings");
372 for (bp = buf; (c = input()) != '"'; ) {
373 if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
374 FATAL("out of space for string %.10s...", buf);
379 SYNTAX( "non-terminated string %.10s...", buf );
381 if (c == 0) /* hopeless */
382 FATAL( "giving up" );
387 case '"': *bp++ = '"'; break;
388 case 'n': *bp++ = '\n'; break;
389 case 't': *bp++ = '\t'; break;
390 case 'f': *bp++ = '\f'; break;
391 case 'r': *bp++ = '\r'; break;
392 case 'b': *bp++ = '\b'; break;
393 case 'v': *bp++ = '\v'; break;
394 case 'a': *bp++ = '\007'; break;
395 case '\\': *bp++ = '\\'; break;
397 case '0': case '1': case '2': /* octal: \d \dd \ddd */
398 case '3': case '4': case '5': case '6': case '7':
400 if ((c = peek()) >= '0' && c < '8') {
401 n = 8 * n + input() - '0';
402 if ((c = peek()) >= '0' && c < '8')
403 n = 8 * n + input() - '0';
408 case 'x': /* hex \x0-9a-fA-F + */
409 { char xbuf[100], *px;
410 for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
412 || (c >= 'a' && c <= 'f')
413 || (c >= 'A' && c <= 'F'))
420 sscanf(xbuf, "%x", (unsigned int *) &n);
437 *bp++ = ' '; *bp++ = 0;
438 yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
443 int binsearch(char *w, Keyword *kp, int n)
445 int cond, low, mid, high;
449 while (low <= high) {
450 mid = (low + high) / 2;
451 if ((cond = strcmp(w, kp[mid].word)) < 0)
466 n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
467 /* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
469 if (n != -1) { /* found in table */
471 switch (kp->type) { /* special handling */
473 if (kp->sub == FSYSTEM && safe)
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 = NULL;
514 static int bufsz = 500;
517 if (buf == NULL && (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, "regexpr"))
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--)