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 /* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
472 if (n != -1) { /* found in table */
474 switch (kp->type) { /* special handling */
476 if (kp->sub == FSYSTEM && safe)
477 SYNTAX( "system is unsafe" );
481 SYNTAX( "illegal nested function" );
485 SYNTAX( "return not in function" );
488 yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
494 c = peek(); /* look for '(' */
495 if (c != '(' && infunc && (n=isarg(w)) >= 0) {
499 yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
508 void startreg(void) /* next call to yylex will return a regular expression */
516 static char *buf = NULL;
517 static int bufsz = 500;
520 if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
521 FATAL("out of space for rex expr");
523 for ( ; (c = input()) != '/' && c != 0; ) {
524 if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
525 FATAL("out of space for reg expr %.10s...", buf);
528 SYNTAX( "newline in regular expression %.10s...", buf );
531 } else if (c == '\\') {
540 SYNTAX("non-terminated regular expression %.10s...", buf);
541 yylval.s = tostring(buf);
546 /* low-level lexical stuff, sort of inherited from lex */
550 char yysbuf[100]; /* pushback buffer */
551 char *yysptr = yysbuf;
554 int input(void) /* get next lexical input character */
557 extern char *lexprog;
560 c = (uschar)*--yysptr;
561 else if (lexprog != NULL) { /* awk '...' */
562 if ((c = (uschar)*lexprog) != 0)
564 } else /* awk -f ... */
568 if (ep >= ebuf + sizeof ebuf)
577 void unput(int c) /* put lexical character back on input */
579 if (yysptr >= yysbuf + sizeof(yysbuf))
580 FATAL("pushed back too much: %.20s...", yysbuf);
583 ep = ebuf + sizeof(ebuf) - 1;
586 void unputstr(const char *s) /* put a string back on input */
590 for (i = strlen(s)-1; i >= 0; i--)