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
},
92 #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
101 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 int sc
= 0; /* 1 => return a } right now */
168 int reg
= 0; /* 1 => return a REGEXPR now */
173 static char *buf
= 0;
174 static int bufsize
= 5; /* BUG: setting this small causes core dump! */
176 if (buf
== 0 && (buf
= (char *) malloc(bufsize
)) == NULL
)
177 FATAL( "out of space in yylex" );
187 c
= gettok(&buf
, &bufsize
);
190 if (isalpha(c
) || c
== '_')
193 yylval
.cp
= setsymtab(buf
, tostring(buf
), atof(buf
), CON
|NUM
, symtab
);
194 /* should this also have STR set? */
200 case '\n': /* {EOL} */
202 case '\r': /* assume \n is coming */
203 case ' ': /* {WS}+ */
206 case '#': /* #.* strip comments */
207 while ((c
= input()) != '\n' && c
!= 0)
214 if (peek() == '\n') {
216 } else if (peek() == '\r') {
217 input(); input(); /* \n */
235 input(); yylval
.i
= NE
; RET(NE
);
236 } else if (peek() == '~') {
237 input(); yylval
.i
= NOTMATCH
; RET(MATCHOP
);
245 input(); yylval
.i
= LE
; RET(LE
);
247 yylval
.i
= LT
; RET(LT
);
251 input(); yylval
.i
= EQ
; RET(EQ
);
253 yylval
.i
= ASSIGN
; RET(ASGNOP
);
257 input(); yylval
.i
= GE
; RET(GE
);
258 } else if (peek() == '>') {
259 input(); yylval
.i
= APPEND
; RET(APPEND
);
261 yylval
.i
= GT
; RET(GT
);
265 input(); yylval
.i
= INCR
; RET(INCR
);
266 } else if (peek() == '=') {
267 input(); yylval
.i
= ADDEQ
; RET(ASGNOP
);
272 input(); yylval
.i
= DECR
; RET(DECR
);
273 } else if (peek() == '=') {
274 input(); yylval
.i
= SUBEQ
; RET(ASGNOP
);
278 if (peek() == '=') { /* *= */
279 input(); yylval
.i
= MULTEQ
; RET(ASGNOP
);
280 } else if (peek() == '*') { /* ** or **= */
281 input(); /* eat 2nd * */
283 input(); yylval
.i
= POWEQ
; RET(ASGNOP
);
293 input(); yylval
.i
= MODEQ
; RET(ASGNOP
);
298 input(); yylval
.i
= POWEQ
; RET(ASGNOP
);
303 /* BUG: awkward, if not wrong */
304 c
= gettok(&buf
, &bufsize
);
306 if (strcmp(buf
, "NF") == 0) { /* very special */
311 if (c
== '(' || c
== '[' || (infunc
&& isarg(buf
) >= 0)) {
315 yylval
.cp
= setsymtab(buf
, "", 0.0, STR
|NUM
, symtab
);
317 } else if (c
== 0) { /* */
318 SYNTAX( "unexpected end of input after $" );
349 return string(); /* BUG: should be like tran.c ? */
361 static char *buf
= 0;
362 static int bufsz
= 500;
364 if (buf
== 0 && (buf
= (char *) malloc(bufsz
)) == NULL
)
365 FATAL("out of space for strings");
366 for (bp
= buf
; (c
= input()) != '"'; ) {
367 if (!adjbuf(&buf
, &bufsz
, bp
-buf
+2, 500, &bp
, "string"))
368 FATAL("out of space for string %.10s...", buf
);
373 SYNTAX( "non-terminated string %.10s...", buf
);
375 if (c
== 0) /* hopeless */
376 FATAL( "giving up" );
381 case '"': *bp
++ = '"'; break;
382 case 'n': *bp
++ = '\n'; break;
383 case 't': *bp
++ = '\t'; break;
384 case 'f': *bp
++ = '\f'; break;
385 case 'r': *bp
++ = '\r'; break;
386 case 'b': *bp
++ = '\b'; break;
387 case 'v': *bp
++ = '\v'; break;
388 case 'a': *bp
++ = '\007'; break;
389 case '\\': *bp
++ = '\\'; break;
391 case '0': case '1': case '2': /* octal: \d \dd \ddd */
392 case '3': case '4': case '5': case '6': case '7':
394 if ((c
= peek()) >= '0' && c
< '8') {
395 n
= 8 * n
+ input() - '0';
396 if ((c
= peek()) >= '0' && c
< '8')
397 n
= 8 * n
+ input() - '0';
402 case 'x': /* hex \x0-9a-fA-F + */
403 { char xbuf
[100], *px
;
404 for (px
= xbuf
; (c
= input()) != 0 && px
-xbuf
< 100-2; ) {
406 || (c
>= 'a' && c
<= 'f')
407 || (c
>= 'A' && c
<= 'F'))
414 sscanf(xbuf
, "%x", &n
);
431 *bp
++ = ' '; *bp
++ = 0;
432 yylval
.cp
= setsymtab(buf
, s
, 0.0, CON
|STR
|DONTFREE
, symtab
);
437 int binsearch(const char *w
, const Keyword
*kp
, int n
)
439 int cond
, low
, mid
, high
;
443 while (low
<= high
) {
444 mid
= (low
+ high
) / 2;
445 if ((cond
= strcmp(w
, kp
[mid
].word
)) < 0)
460 n
= binsearch(w
, keywords
, sizeof(keywords
)/sizeof(keywords
[0]));
461 /* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
463 if (n
!= -1) { /* found in table */
465 switch (kp
->type
) { /* special handling */
467 if (kp
->sub
== FSYSTEM
&& safe
)
468 SYNTAX( "system is unsafe" );
472 SYNTAX( "illegal nested function" );
476 SYNTAX( "return not in function" );
479 yylval
.cp
= setsymtab("NF", "", 0.0, NUM
, symtab
);
485 c
= peek(); /* look for '(' */
486 if (c
!= '(' && infunc
&& (n
=isarg(w
)) >= 0) {
490 yylval
.cp
= setsymtab(w
, "", 0.0, STR
|NUM
|DONTFREE
, symtab
);
499 void startreg(void) /* next call to yylex will return a regular expression */
507 static char *buf
= 0;
508 static int bufsz
= 500;
511 if (buf
== 0 && (buf
= (char *) malloc(bufsz
)) == NULL
)
512 FATAL("out of space for rex expr");
514 for ( ; (c
= input()) != '/' && c
!= 0; ) {
515 if (!adjbuf(&buf
, &bufsz
, bp
-buf
+3, 500, &bp
, "regexpr"))
516 FATAL("out of space for reg expr %.10s...", buf
);
518 SYNTAX( "newline in regular expression %.10s...", buf
);
521 } else if (c
== '\\') {
530 SYNTAX("non-terminated regular expression %.10s...", buf
);
531 yylval
.s
= tostring(buf
);
536 /* low-level lexical stuff, sort of inherited from lex */
540 char yysbuf
[100]; /* pushback buffer */
541 char *yysptr
= yysbuf
;
544 int input(void) /* get next lexical input character */
547 extern char *lexprog
;
550 c
= (uschar
)*--yysptr
;
551 else if (lexprog
!= NULL
) { /* awk '...' */
552 if ((c
= (uschar
)*lexprog
) != 0)
554 } else /* awk -f ... */
560 if (ep
>= ebuf
+ sizeof ebuf
)
565 void unput(int c
) /* put lexical character back on input */
569 if (yysptr
>= yysbuf
+ sizeof(yysbuf
))
570 FATAL("pushed back too much: %.20s...", yysbuf
);
573 ep
= ebuf
+ sizeof(ebuf
) - 1;
576 void unputstr(const char *s
) /* put a string back on input */
580 for (i
= strlen(s
)-1; i
>= 0; i
--)