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
},
94 #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
96 #define RET(x) return(x)
106 int gettok(char **pbuf
, int *psz
) /* get next input token */
118 if (!isalnum(c
) && c
!= '.' && c
!= '_')
122 if (isalpha(c
) || c
== '_') { /* it's a varname */
123 for ( ; (c
= input()) != 0; ) {
125 if (!adjbuf(&buf
, &sz
, bp
-buf
+2, 100, &bp
, 0))
126 FATAL( "out of space for name %.10s...", buf
);
127 if (isalnum(c
) || c
== '_')
136 retc
= 'a'; /* alphanumeric */
137 } else { /* it's a number */
139 /* read input until can't be a number */
140 for ( ; (c
= input()) != 0; ) {
142 if (!adjbuf(&buf
, &sz
, bp
-buf
+2, 100, &bp
, 0))
143 FATAL( "out of space for number %.10s...", buf
);
144 if (isdigit(c
) || c
== 'e' || c
== 'E'
145 || c
== '.' || c
== '+' || c
== '-')
153 strtod(buf
, &rem
); /* parse the number */
154 unputstr(rem
); /* put rest back for later */
155 if (rem
== buf
) { /* it wasn't a valid number at all */
156 buf
[1] = 0; /* so return one character as token */
157 retc
= buf
[0]; /* character is its own type */
158 } else { /* some prefix was a number */
159 rem
[0] = 0; /* so truncate where failure started */
160 retc
= '0'; /* number */
171 int sc
= 0; /* 1 => return a } right now */
172 int reg
= 0; /* 1 => return a REGEXPR now */
177 static char *buf
= 0;
178 static int bufsize
= 500;
180 if (buf
== 0 && (buf
= (char *) malloc(bufsize
)) == NULL
)
181 FATAL( "out of space in yylex" );
191 c
= gettok(&buf
, &bufsize
);
194 if (isalpha(c
) || c
== '_')
197 yylval
.cp
= setsymtab(buf
, tostring(buf
), atof(buf
), CON
|NUM
, symtab
);
198 /* should this also have STR set? */
204 case '\n': /* {EOL} */
206 case '\r': /* assume \n is coming */
207 case ' ': /* {WS}+ */
210 case '#': /* #.* strip comments */
211 while ((c
= input()) != '\n' && c
!= 0)
218 if (peek() == '\n') {
220 } else if (peek() == '\r') {
221 input(); input(); /* \n */
239 input(); yylval
.i
= NE
; RET(NE
);
240 } else if (peek() == '~') {
241 input(); yylval
.i
= NOTMATCH
; RET(MATCHOP
);
249 input(); yylval
.i
= LE
; RET(LE
);
251 yylval
.i
= LT
; RET(LT
);
255 input(); yylval
.i
= EQ
; RET(EQ
);
257 yylval
.i
= ASSIGN
; RET(ASGNOP
);
261 input(); yylval
.i
= GE
; RET(GE
);
262 } else if (peek() == '>') {
263 input(); yylval
.i
= APPEND
; RET(APPEND
);
265 yylval
.i
= GT
; RET(GT
);
269 input(); yylval
.i
= INCR
; RET(INCR
);
270 } else if (peek() == '=') {
271 input(); yylval
.i
= ADDEQ
; RET(ASGNOP
);
276 input(); yylval
.i
= DECR
; RET(DECR
);
277 } else if (peek() == '=') {
278 input(); yylval
.i
= SUBEQ
; RET(ASGNOP
);
282 if (peek() == '=') { /* *= */
283 input(); yylval
.i
= MULTEQ
; RET(ASGNOP
);
284 } else if (peek() == '*') { /* ** or **= */
285 input(); /* eat 2nd * */
287 input(); yylval
.i
= POWEQ
; RET(ASGNOP
);
297 input(); yylval
.i
= MODEQ
; RET(ASGNOP
);
302 input(); yylval
.i
= POWEQ
; RET(ASGNOP
);
307 /* BUG: awkward, if not wrong */
308 c
= gettok(&buf
, &bufsize
);
310 if (strcmp(buf
, "NF") == 0) { /* very special */
315 if (c
== '(' || c
== '[' || (infunc
&& isarg(buf
) >= 0)) {
319 yylval
.cp
= setsymtab(buf
, "", 0.0, STR
|NUM
, symtab
);
321 } else if (c
== 0) { /* */
322 SYNTAX( "unexpected end of input after $" );
353 return string(); /* BUG: should be like tran.c ? */
365 static char *buf
= 0;
366 static int bufsz
= 500;
368 if (buf
== 0 && (buf
= (char *) malloc(bufsz
)) == NULL
)
369 FATAL("out of space for strings");
370 for (bp
= buf
; (c
= input()) != '"'; ) {
371 if (!adjbuf(&buf
, &bufsz
, bp
-buf
+2, 500, &bp
, 0))
372 FATAL("out of space for string %.10s...", buf
);
377 SYNTAX( "non-terminated string %.10s...", buf
);
379 if (c
== 0) /* hopeless */
380 FATAL( "giving up" );
385 case '"': *bp
++ = '"'; break;
386 case 'n': *bp
++ = '\n'; break;
387 case 't': *bp
++ = '\t'; break;
388 case 'f': *bp
++ = '\f'; break;
389 case 'r': *bp
++ = '\r'; break;
390 case 'b': *bp
++ = '\b'; break;
391 case 'v': *bp
++ = '\v'; break;
392 case 'a': *bp
++ = '\007'; break;
393 case '\\': *bp
++ = '\\'; break;
395 case '0': case '1': case '2': /* octal: \d \dd \ddd */
396 case '3': case '4': case '5': case '6': case '7':
398 if ((c
= peek()) >= '0' && c
< '8') {
399 n
= 8 * n
+ input() - '0';
400 if ((c
= peek()) >= '0' && c
< '8')
401 n
= 8 * n
+ input() - '0';
406 case 'x': /* hex \x0-9a-fA-F + */
407 { char xbuf
[100], *px
;
408 for (px
= xbuf
; (c
= input()) != 0 && px
-xbuf
< 100-2; ) {
410 || (c
>= 'a' && c
<= 'f')
411 || (c
>= 'A' && c
<= 'F'))
418 sscanf(xbuf
, "%x", &n
);
435 *bp
++ = ' '; *bp
++ = 0;
436 yylval
.cp
= setsymtab(buf
, s
, 0.0, CON
|STR
|DONTFREE
, symtab
);
441 int binsearch(char *w
, Keyword
*kp
, int n
)
443 int cond
, low
, mid
, high
;
447 while (low
<= high
) {
448 mid
= (low
+ high
) / 2;
449 if ((cond
= strcmp(w
, kp
[mid
].word
)) < 0)
464 n
= binsearch(w
, keywords
, sizeof(keywords
)/sizeof(keywords
[0]));
466 if (n
!= -1) { /* found in table */
468 switch (kp
->type
) { /* special handling */
471 SYNTAX( "system is unsafe" );
475 SYNTAX( "illegal nested function" );
479 SYNTAX( "return not in function" );
482 yylval
.cp
= setsymtab("NF", "", 0.0, NUM
, symtab
);
488 c
= peek(); /* look for '(' */
489 if (c
!= '(' && infunc
&& (n
=isarg(w
)) >= 0) {
493 yylval
.cp
= setsymtab(w
, "", 0.0, STR
|NUM
|DONTFREE
, symtab
);
502 void startreg(void) /* next call to yylex will return a regular expression */
510 static char *buf
= 0;
511 static int bufsz
= 500;
514 if (buf
== 0 && (buf
= (char *) malloc(bufsz
)) == NULL
)
515 FATAL("out of space for rex expr");
517 for ( ; (c
= input()) != '/' && c
!= 0; ) {
518 if (!adjbuf(&buf
, &bufsz
, bp
-buf
+3, 500, &bp
, 0))
519 FATAL("out of space for reg expr %.10s...", buf
);
521 SYNTAX( "newline in regular expression %.10s...", buf
);
524 } else if (c
== '\\') {
533 SYNTAX("non-terminated regular expression %.10s...", buf
);
534 yylval
.s
= tostring(buf
);
539 /* low-level lexical stuff, sort of inherited from lex */
543 char yysbuf
[100]; /* pushback buffer */
544 char *yysptr
= yysbuf
;
547 int input(void) /* get next lexical input character */
550 extern char *lexprog
;
553 c
= (uschar
)*--yysptr
;
554 else if (lexprog
!= NULL
) { /* awk '...' */
555 if ((c
= (uschar
)*lexprog
) != 0)
557 } else /* awk -f ... */
563 if (ep
>= ebuf
+ sizeof ebuf
)
568 void unput(int c
) /* put lexical character back on input */
572 if (yysptr
>= yysbuf
+ sizeof(yysbuf
))
573 FATAL("pushed back too much: %.20s...", yysbuf
);
576 ep
= ebuf
+ sizeof(ebuf
) - 1;
579 void unputstr(const char *s
) /* put a string back on input */
583 for (i
= strlen(s
)-1; i
>= 0; i
--)