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 const 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 },
92 #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
101 static int gettok(char **pbuf, int *psz) /* get next input token */
113 if (!isalnum(c) && c != '.' && c != '_')
117 if (isalpha(c) || c == '_') { /* it's a varname */
118 for ( ; (c = input()) != 0; ) {
120 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
121 FATAL( "out of space for name %.10s...", buf );
122 if (isalnum(c) || c == '_')
131 retc = 'a'; /* alphanumeric */
132 } else { /* maybe it's a number, but could be . */
134 /* read input until can't be a number */
135 for ( ; (c = input()) != 0; ) {
137 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
138 FATAL( "out of space for number %.10s...", buf );
139 if (isdigit(c) || c == 'e' || c == 'E'
140 || c == '.' || c == '+' || c == '-')
148 strtod(buf, &rem); /* parse the number */
149 if (rem == buf) { /* it wasn't a valid number at all */
150 buf[1] = 0; /* return one character as token */
151 retc = buf[0]; /* character is its own type */
152 unputstr(rem+1); /* put rest back for later */
153 } else { /* some prefix was a number */
154 unputstr(rem); /* put rest back for later */
155 rem[0] = 0; /* truncate buf after number part */
156 retc = '0'; /* type is number */
167 bool sc = false; /* true => return a } right now */
168 bool reg = false; /* true => return a REGEXPR now */
173 static char *buf = NULL;
174 static int bufsize = 5; /* BUG: setting this small causes core dump! */
176 if (buf == NULL && (buf = malloc(bufsize)) == NULL)
177 FATAL( "out of space in yylex" );
187 c = gettok(&buf, &bufsize);
190 if (isalpha(c) || c == '_')
193 char *cp = tostring(buf);
194 yylval.cp = setsymtab(buf, cp, atof(buf), CON|NUM, symtab);
196 /* should this also have STR set? */
202 case '\n': /* {EOL} */
205 case '\r': /* assume \n is coming */
206 case ' ': /* {WS}+ */
209 case '#': /* #.* strip comments */
210 while ((c = input()) != '\n' && c != 0)
214 * Next line is a hack, itcompensates for
215 * unput's treatment of \n.
222 if (peek() == '\n') {
225 } else if (peek() == '\r') {
226 input(); input(); /* \n */
244 input(); yylval.i = NE; RET(NE);
245 } else if (peek() == '~') {
246 input(); yylval.i = NOTMATCH; RET(MATCHOP);
254 input(); yylval.i = LE; RET(LE);
256 yylval.i = LT; RET(LT);
260 input(); yylval.i = EQ; RET(EQ);
262 yylval.i = ASSIGN; RET(ASGNOP);
266 input(); yylval.i = GE; RET(GE);
267 } else if (peek() == '>') {
268 input(); yylval.i = APPEND; RET(APPEND);
270 yylval.i = GT; RET(GT);
274 input(); yylval.i = INCR; RET(INCR);
275 } else if (peek() == '=') {
276 input(); yylval.i = ADDEQ; RET(ASGNOP);
281 input(); yylval.i = DECR; RET(DECR);
282 } else if (peek() == '=') {
283 input(); yylval.i = SUBEQ; RET(ASGNOP);
287 if (peek() == '=') { /* *= */
288 input(); yylval.i = MULTEQ; RET(ASGNOP);
289 } else if (peek() == '*') { /* ** or **= */
290 input(); /* eat 2nd * */
292 input(); yylval.i = POWEQ; RET(ASGNOP);
302 input(); yylval.i = MODEQ; RET(ASGNOP);
307 input(); yylval.i = POWEQ; RET(ASGNOP);
312 /* BUG: awkward, if not wrong */
313 c = gettok(&buf, &bufsize);
315 if (strcmp(buf, "NF") == 0) { /* very special */
320 if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
324 yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
326 } else if (c == 0) { /* */
327 SYNTAX( "unexpected end of input after $" );
358 return string(); /* BUG: should be like tran.c ? */
370 static char *buf = NULL;
371 static int bufsz = 500;
373 if (buf == NULL && (buf = malloc(bufsz)) == NULL)
374 FATAL("out of space for strings");
375 for (bp = buf; (c = input()) != '"'; ) {
376 if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
377 FATAL("out of space for string %.10s...", buf);
383 SYNTAX( "non-terminated string %.10s...", buf );
384 if (c == 0) /* hopeless */
385 FATAL( "giving up" );
392 case '"': *bp++ = '"'; break;
393 case 'n': *bp++ = '\n'; break;
394 case 't': *bp++ = '\t'; break;
395 case 'f': *bp++ = '\f'; break;
396 case 'r': *bp++ = '\r'; break;
397 case 'b': *bp++ = '\b'; break;
398 case 'v': *bp++ = '\v'; break;
399 case 'a': *bp++ = '\a'; break;
400 case '\\': *bp++ = '\\'; break;
402 case '0': case '1': case '2': /* octal: \d \dd \ddd */
403 case '3': case '4': case '5': case '6': case '7':
405 if ((c = peek()) >= '0' && c < '8') {
406 n = 8 * n + input() - '0';
407 if ((c = peek()) >= '0' && c < '8')
408 n = 8 * n + input() - '0';
413 case 'x': /* hex \x0-9a-fA-F + */
414 { char xbuf[100], *px;
415 for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
417 || (c >= 'a' && c <= 'f')
418 || (c >= 'A' && c <= 'F'))
425 sscanf(xbuf, "%x", (unsigned int *) &n);
442 *bp++ = ' '; *bp++ = '\0';
443 yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
449 static int binsearch(char *w, const Keyword *kp, int n)
451 int cond, low, mid, high;
455 while (low <= high) {
456 mid = (low + high) / 2;
457 if ((cond = strcmp(w, kp[mid].word)) < 0)
472 n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
473 if (n != -1) { /* found in table */
476 switch (kp->type) { /* special handling */
478 if (kp->sub == FSYSTEM && safe)
479 SYNTAX( "system is unsafe" );
483 SYNTAX( "illegal nested function" );
487 SYNTAX( "return not in function" );
490 yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
496 c = peek(); /* look for '(' */
497 if (c != '(' && infunc && (n=isarg(w)) >= 0) {
501 yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
510 void startreg(void) /* next call to yylex will return a regular expression */
518 static char *buf = NULL;
519 static int bufsz = 500;
522 if (buf == NULL && (buf = malloc(bufsz)) == NULL)
523 FATAL("out of space for rex expr");
525 for ( ; (c = input()) != '/' && c != 0; ) {
526 if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
527 FATAL("out of space for reg expr %.10s...", buf);
530 SYNTAX( "newline in regular expression %.10s...", buf );
533 } else if (c == '\\') {
542 SYNTAX("non-terminated regular expression %.10s...", buf);
543 yylval.s = tostring(buf);
548 /* low-level lexical stuff, sort of inherited from lex */
552 char yysbuf[100]; /* pushback buffer */
553 char *yysptr = yysbuf;
556 int input(void) /* get next lexical input character */
559 extern char *lexprog;
562 c = (uschar)*--yysptr;
563 else if (lexprog != NULL) { /* awk '...' */
564 if ((c = (uschar)*lexprog) != 0)
566 } else /* awk -f ... */
570 if (ep >= ebuf + sizeof ebuf)
579 void unput(int c) /* put lexical character back on input */
583 if (yysptr >= yysbuf + sizeof(yysbuf))
584 FATAL("pushed back too much: %.20s...", yysbuf);
587 ep = ebuf + sizeof(ebuf) - 1;
590 void unputstr(const char *s) /* put a string back on input */
594 for (i = strlen(s)-1; i >= 0; i--)