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} */
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') {
224 } else if (peek() == '\r') {
225 input(); input(); /* \n */
243 input(); yylval.i = NE; RET(NE);
244 } else if (peek() == '~') {
245 input(); yylval.i = NOTMATCH; RET(MATCHOP);
253 input(); yylval.i = LE; RET(LE);
255 yylval.i = LT; RET(LT);
259 input(); yylval.i = EQ; RET(EQ);
261 yylval.i = ASSIGN; RET(ASGNOP);
265 input(); yylval.i = GE; RET(GE);
266 } else if (peek() == '>') {
267 input(); yylval.i = APPEND; RET(APPEND);
269 yylval.i = GT; RET(GT);
273 input(); yylval.i = INCR; RET(INCR);
274 } else if (peek() == '=') {
275 input(); yylval.i = ADDEQ; RET(ASGNOP);
280 input(); yylval.i = DECR; RET(DECR);
281 } else if (peek() == '=') {
282 input(); yylval.i = SUBEQ; RET(ASGNOP);
286 if (peek() == '=') { /* *= */
287 input(); yylval.i = MULTEQ; RET(ASGNOP);
288 } else if (peek() == '*') { /* ** or **= */
289 input(); /* eat 2nd * */
291 input(); yylval.i = POWEQ; RET(ASGNOP);
301 input(); yylval.i = MODEQ; RET(ASGNOP);
306 input(); yylval.i = POWEQ; RET(ASGNOP);
311 /* BUG: awkward, if not wrong */
312 c = gettok(&buf, &bufsize);
314 if (strcmp(buf, "NF") == 0) { /* very special */
319 if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
323 yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
325 } else if (c == 0) { /* */
326 SYNTAX( "unexpected end of input after $" );
357 return string(); /* BUG: should be like tran.c ? */
369 static char *buf = NULL;
370 static int bufsz = 500;
372 if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
373 FATAL("out of space for strings");
374 for (bp = buf; (c = input()) != '"'; ) {
375 if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
376 FATAL("out of space for string %.10s...", buf);
382 SYNTAX( "non-terminated string %.10s...", buf );
383 if (c == 0) /* hopeless */
384 FATAL( "giving up" );
390 case '"': *bp++ = '"'; break;
391 case 'n': *bp++ = '\n'; break;
392 case 't': *bp++ = '\t'; break;
393 case 'f': *bp++ = '\f'; break;
394 case 'r': *bp++ = '\r'; break;
395 case 'b': *bp++ = '\b'; break;
396 case 'v': *bp++ = '\v'; break;
397 case 'a': *bp++ = '\007'; break;
398 case '\\': *bp++ = '\\'; break;
400 case '0': case '1': case '2': /* octal: \d \dd \ddd */
401 case '3': case '4': case '5': case '6': case '7':
403 if ((c = peek()) >= '0' && c < '8') {
404 n = 8 * n + input() - '0';
405 if ((c = peek()) >= '0' && c < '8')
406 n = 8 * n + input() - '0';
411 case 'x': /* hex \x0-9a-fA-F + */
412 { char xbuf[100], *px;
413 for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
415 || (c >= 'a' && c <= 'f')
416 || (c >= 'A' && c <= 'F'))
423 sscanf(xbuf, "%x", (unsigned int *) &n);
440 *bp++ = ' '; *bp++ = 0;
441 yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
446 int binsearch(char *w, Keyword *kp, int n)
448 int cond, low, mid, high;
452 while (low <= high) {
453 mid = (low + high) / 2;
454 if ((cond = strcmp(w, kp[mid].word)) < 0)
469 n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
470 if (n != -1) { /* found in table */
473 switch (kp->type) { /* special handling */
475 if (kp->sub == FSYSTEM && safe)
476 SYNTAX( "system is unsafe" );
480 SYNTAX( "illegal nested function" );
484 SYNTAX( "return not in function" );
487 yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
493 c = peek(); /* look for '(' */
494 if (c != '(' && infunc && (n=isarg(w)) >= 0) {
498 yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
507 void startreg(void) /* next call to yylex will return a regular expression */
515 static char *buf = NULL;
516 static int bufsz = 500;
519 if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
520 FATAL("out of space for rex expr");
522 for ( ; (c = input()) != '/' && c != 0; ) {
523 if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
524 FATAL("out of space for reg expr %.10s...", buf);
527 SYNTAX( "newline in regular expression %.10s...", buf );
530 } else if (c == '\\') {
539 SYNTAX("non-terminated regular expression %.10s...", buf);
540 yylval.s = tostring(buf);
545 /* low-level lexical stuff, sort of inherited from lex */
549 char yysbuf[100]; /* pushback buffer */
550 char *yysptr = yysbuf;
553 int input(void) /* get next lexical input character */
556 extern char *lexprog;
559 c = (uschar)*--yysptr;
560 else if (lexprog != NULL) { /* awk '...' */
561 if ((c = (uschar)*lexprog) != 0)
563 } else /* awk -f ... */
567 if (ep >= ebuf + sizeof ebuf)
576 void unput(int c) /* put lexical character back on input */
578 if (yysptr >= yysbuf + sizeof(yysbuf))
579 FATAL("pushed back too much: %.20s...", yysbuf);
582 ep = ebuf + sizeof(ebuf) - 1;
585 void unputstr(const char *s) /* put a string back on input */
589 for (i = strlen(s)-1; i >= 0; i--)