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 ****************************************************************/
25 #if HAVE_NBTOOL_CONFIG_H
26 #include "nbtool_config.h"
36 extern YYSTYPE yylval
;
44 typedef struct Keyword
{
51 int gettok(char **, int *);
52 int binsearch(const char *, const Keyword
*, int);
54 const Keyword keywords
[] ={ /* keep sorted: binary searched */
55 { "BEGIN", XBEGIN
, XBEGIN
},
56 { "END", XEND
, XEND
},
57 { "NF", VARNF
, VARNF
},
58 { "atan2", FATAN
, BLTIN
},
59 { "break", BREAK
, BREAK
},
60 { "close", CLOSE
, CLOSE
},
61 { "continue", CONTINUE
, CONTINUE
},
62 { "cos", FCOS
, BLTIN
},
63 { "delete", DELETE
, DELETE
},
65 { "else", ELSE
, ELSE
},
66 { "exit", EXIT
, EXIT
},
67 { "exp", FEXP
, BLTIN
},
68 { "fflush", FFLUSH
, BLTIN
},
70 { "func", FUNC
, FUNC
},
71 { "function", FUNC
, FUNC
},
72 { "gensub", GENSUB
, GENSUB
},
73 { "getline", GETLINE
, GETLINE
},
74 { "gsub", GSUB
, GSUB
},
77 { "index", INDEX
, INDEX
},
78 { "int", FINT
, BLTIN
},
79 { "length", FLENGTH
, BLTIN
},
80 { "log", FLOG
, BLTIN
},
81 { "match", MATCHFCN
, MATCHFCN
},
82 { "next", NEXT
, NEXT
},
83 { "nextfile", NEXTFILE
, NEXTFILE
},
84 { "print", PRINT
, PRINT
},
85 { "printf", PRINTF
, PRINTF
},
86 { "rand", FRAND
, BLTIN
},
87 { "return", RETURN
, RETURN
},
88 { "sin", FSIN
, BLTIN
},
89 { "split", SPLIT
, SPLIT
},
90 { "sprintf", SPRINTF
, SPRINTF
},
91 { "sqrt", FSQRT
, BLTIN
},
92 { "srand", FSRAND
, BLTIN
},
93 { "strftime", FSTRFTIME
, BLTIN
},
95 { "substr", SUBSTR
, SUBSTR
},
96 { "system", FSYSTEM
, BLTIN
},
97 { "systime", FSYSTIME
, BLTIN
},
98 { "tolower", FTOLOWER
, BLTIN
},
99 { "toupper", FTOUPPER
, BLTIN
},
100 { "while", WHILE
, WHILE
},
103 #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
112 int gettok(char **pbuf
, int *psz
) /* get next input token */
115 uschar
*buf
= (uschar
*) *pbuf
;
124 if (!isalnum(c
) && c
!= '.' && c
!= '_')
128 if (isalpha(c
) || c
== '_') { /* it's a varname */
129 for ( ; (c
= input()) != 0; ) {
131 if (!adjbuf(&buf
, &sz
, bp
-buf
+2, 100, &bp
, "gettok"))
132 FATAL( "out of space for name %.10s...", buf
);
133 if (isalnum(c
) || c
== '_')
142 retc
= 'a'; /* alphanumeric */
143 } else { /* maybe it's a number, but could be . */
145 /* read input until can't be a number */
146 for ( ; (c
= input()) != 0; ) {
148 if (!adjbuf(&buf
, &sz
, bp
-buf
+2, 100, &bp
, "gettok"))
149 FATAL( "out of space for number %.10s...", buf
);
150 if (isdigit(c
) || c
== 'e' || c
== 'E'
151 || c
== '.' || c
== '+' || c
== '-')
159 strtod(buf
, &rem
); /* parse the number */
160 if (rem
== (char *)buf
) { /* it wasn't a valid number at all */
161 buf
[1] = 0; /* return one character as token */
162 retc
= buf
[0]; /* character is its own type */
163 unputstr(rem
+1); /* put rest back for later */
164 } else { /* some prefix was a number */
165 unputstr(rem
); /* put rest back for later */
166 rem
[0] = 0; /* truncate buf after number part */
167 retc
= '0'; /* type is number */
178 int sc
= 0; /* 1 => return a } right now */
179 int reg
= 0; /* 1 => return a REGEXPR now */
184 static char *buf
= 0;
185 static int bufsize
= 5; /* BUG: setting this small causes core dump! */
187 if (buf
== 0 && (buf
= (char *) malloc(bufsize
)) == NULL
)
188 FATAL( "out of space in yylex" );
198 c
= gettok(&buf
, &bufsize
);
201 if (isalpha(c
) || c
== '_')
204 yylval
.cp
= setsymtab(buf
, tostring(buf
), atof(buf
), CON
|NUM
, symtab
);
205 /* should this also have STR set? */
211 case '\n': /* {EOL} */
213 case '\r': /* assume \n is coming */
214 case ' ': /* {WS}+ */
217 case '#': /* #.* strip comments */
218 while ((c
= input()) != '\n' && c
!= 0)
225 if (peek() == '\n') {
227 } else if (peek() == '\r') {
228 input(); input(); /* \n */
246 input(); yylval
.i
= NE
; RET(NE
);
247 } else if (peek() == '~') {
248 input(); yylval
.i
= NOTMATCH
; RET(MATCHOP
);
256 input(); yylval
.i
= LE
; RET(LE
);
258 yylval
.i
= LT
; RET(LT
);
262 input(); yylval
.i
= EQ
; RET(EQ
);
264 yylval
.i
= ASSIGN
; RET(ASGNOP
);
268 input(); yylval
.i
= GE
; RET(GE
);
269 } else if (peek() == '>') {
270 input(); yylval
.i
= APPEND
; RET(APPEND
);
272 yylval
.i
= GT
; RET(GT
);
276 input(); yylval
.i
= INCR
; RET(INCR
);
277 } else if (peek() == '=') {
278 input(); yylval
.i
= ADDEQ
; RET(ASGNOP
);
283 input(); yylval
.i
= DECR
; RET(DECR
);
284 } else if (peek() == '=') {
285 input(); yylval
.i
= SUBEQ
; RET(ASGNOP
);
289 if (peek() == '=') { /* *= */
290 input(); yylval
.i
= MULTEQ
; RET(ASGNOP
);
291 } else if (peek() == '*') { /* ** or **= */
292 input(); /* eat 2nd * */
294 input(); yylval
.i
= POWEQ
; RET(ASGNOP
);
304 input(); yylval
.i
= MODEQ
; RET(ASGNOP
);
309 input(); yylval
.i
= POWEQ
; RET(ASGNOP
);
314 /* BUG: awkward, if not wrong */
315 c
= gettok(&buf
, &bufsize
);
317 if (strcmp(buf
, "NF") == 0) { /* very special */
322 if (c
== '(' || c
== '[' || (infunc
&& isarg(buf
) >= 0)) {
326 yylval
.cp
= setsymtab(buf
, "", 0.0, STR
|NUM
, symtab
);
328 } else if (c
== 0) { /* */
329 SYNTAX( "unexpected end of input after $" );
360 return string(); /* BUG: should be like tran.c ? */
372 static uschar
*buf
= 0;
373 static int bufsz
= 500;
375 if (buf
== 0 && (buf
= (char *) malloc(bufsz
)) == NULL
)
376 FATAL("out of space for strings");
377 for (bp
= buf
; (c
= input()) != '"'; ) {
378 if (!adjbuf(&buf
, &bufsz
, bp
-buf
+2, 500, &bp
, "string"))
379 FATAL("out of space for string %.10s...", buf
);
384 SYNTAX( "non-terminated string %.10s...", buf
);
386 if (c
== 0) /* hopeless */
387 FATAL( "giving up" );
393 case '"': *bp
++ = '"'; break;
394 case 'n': *bp
++ = '\n'; break;
395 case 't': *bp
++ = '\t'; break;
396 case 'f': *bp
++ = '\f'; break;
397 case 'r': *bp
++ = '\r'; break;
398 case 'b': *bp
++ = '\b'; break;
399 case 'v': *bp
++ = '\v'; break;
400 case 'a': *bp
++ = '\007'; break;
401 case '\\': *bp
++ = '\\'; break;
403 case '0': case '1': case '2': /* octal: \d \dd \ddd */
404 case '3': case '4': case '5': case '6': case '7':
406 if ((c
= peek()) >= '0' && c
< '8') {
407 n
= 8 * n
+ input() - '0';
408 if ((c
= peek()) >= '0' && c
< '8')
409 n
= 8 * n
+ input() - '0';
414 case 'x': /* hex \x0-9a-fA-F + */
415 { char xbuf
[100], *px
;
416 for (px
= xbuf
; (c
= input()) != 0 && px
-xbuf
< 100-2; ) {
418 || (c
>= 'a' && c
<= 'f')
419 || (c
>= 'A' && c
<= 'F'))
426 sscanf(xbuf
, "%x", &n
);
432 WARNING("warning: escape sequence `\\%c' "
433 "treated as plain `%c'", c
, c
);
445 *bp
++ = ' '; *bp
++ = 0;
446 yylval
.cp
= setsymtab(buf
, s
, 0.0, CON
|STR
|DONTFREE
, symtab
);
451 int binsearch(const char *w
, const Keyword
*kp
, int n
)
453 int cond
, low
, mid
, high
;
457 while (low
<= high
) {
458 mid
= (low
+ high
) / 2;
459 if ((cond
= strcmp(w
, kp
[mid
].word
)) < 0)
474 n
= binsearch(w
, keywords
, sizeof(keywords
)/sizeof(keywords
[0]));
475 /* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
477 if (n
!= -1) { /* found in table */
479 switch (kp
->type
) { /* special handling */
481 if (kp
->sub
== FSYSTEM
&& safe
)
482 SYNTAX( "system is unsafe" );
486 SYNTAX( "illegal nested function" );
490 SYNTAX( "return not in function" );
493 yylval
.cp
= setsymtab("NF", "", 0.0, NUM
, symtab
);
499 c
= peek(); /* look for '(' */
500 if (c
!= '(' && infunc
&& (n
=isarg(w
)) >= 0) {
504 yylval
.cp
= setsymtab(w
, "", 0.0, STR
|NUM
|DONTFREE
, symtab
);
513 void startreg(void) /* next call to yylex will return a regular expression */
521 static uschar
*buf
= 0;
522 static int bufsz
= 500;
525 if (buf
== 0 && (buf
= (char *) malloc(bufsz
)) == NULL
)
526 FATAL("out of space for rex expr");
528 for ( ; (c
= input()) != '/' && c
!= 0; ) {
529 if (!adjbuf(&buf
, &bufsz
, bp
-buf
+3, 500, &bp
, "regexpr"))
530 FATAL("out of space for reg expr %.10s...", buf
);
532 SYNTAX( "newline in regular expression %.10s...", buf
);
535 } else if (c
== '\\') {
544 SYNTAX("non-terminated regular expression %.10s...", buf
);
545 yylval
.s
= tostring(buf
);
550 /* low-level lexical stuff, sort of inherited from lex */
554 char yysbuf
[100]; /* pushback buffer */
555 char *yysptr
= yysbuf
;
558 int input(void) /* get next lexical input character */
561 extern char *lexprog
;
564 c
= (uschar
)*--yysptr
;
565 else if (lexprog
!= NULL
) { /* awk '...' */
566 if ((c
= (uschar
)*lexprog
) != 0)
568 } else /* awk -f ... */
574 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
--)