12a55deb1SDavid E. O'Brien /**************************************************************** 22a55deb1SDavid E. O'Brien Copyright (C) Lucent Technologies 1997 32a55deb1SDavid E. O'Brien All Rights Reserved 42a55deb1SDavid E. O'Brien 52a55deb1SDavid E. O'Brien Permission to use, copy, modify, and distribute this software and 62a55deb1SDavid E. O'Brien its documentation for any purpose and without fee is hereby 72a55deb1SDavid E. O'Brien granted, provided that the above copyright notice appear in all 82a55deb1SDavid E. O'Brien copies and that both that the copyright notice and this 92a55deb1SDavid E. O'Brien permission notice and warranty disclaimer appear in supporting 102a55deb1SDavid E. O'Brien documentation, and that the name Lucent Technologies or any of 112a55deb1SDavid E. O'Brien its entities not be used in advertising or publicity pertaining 122a55deb1SDavid E. O'Brien to distribution of the software without specific, written prior 132a55deb1SDavid E. O'Brien permission. 142a55deb1SDavid E. O'Brien 152a55deb1SDavid E. O'Brien LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 162a55deb1SDavid E. O'Brien INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 172a55deb1SDavid E. O'Brien IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 182a55deb1SDavid E. O'Brien SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 192a55deb1SDavid E. O'Brien WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 202a55deb1SDavid E. O'Brien IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 212a55deb1SDavid E. O'Brien ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 222a55deb1SDavid E. O'Brien THIS SOFTWARE. 232a55deb1SDavid E. O'Brien ****************************************************************/ 242a55deb1SDavid E. O'Brien 252a55deb1SDavid E. O'Brien #include <stdio.h> 262a55deb1SDavid E. O'Brien #include <stdlib.h> 272a55deb1SDavid E. O'Brien #include <string.h> 282a55deb1SDavid E. O'Brien #include <ctype.h> 292a55deb1SDavid E. O'Brien #include "awk.h" 302a55deb1SDavid E. O'Brien #include "ytab.h" 312a55deb1SDavid E. O'Brien 322a55deb1SDavid E. O'Brien extern YYSTYPE yylval; 332a55deb1SDavid E. O'Brien extern int infunc; 342a55deb1SDavid E. O'Brien 352a55deb1SDavid E. O'Brien int lineno = 1; 362a55deb1SDavid E. O'Brien int bracecnt = 0; 372a55deb1SDavid E. O'Brien int brackcnt = 0; 382a55deb1SDavid E. O'Brien int parencnt = 0; 392a55deb1SDavid E. O'Brien 402a55deb1SDavid E. O'Brien typedef struct Keyword { 41813da98dSDavid E. O'Brien const char *word; 422a55deb1SDavid E. O'Brien int sub; 432a55deb1SDavid E. O'Brien int type; 442a55deb1SDavid E. O'Brien } Keyword; 452a55deb1SDavid E. O'Brien 462a55deb1SDavid E. O'Brien Keyword keywords[] ={ /* keep sorted: binary searched */ 472a55deb1SDavid E. O'Brien { "BEGIN", XBEGIN, XBEGIN }, 482a55deb1SDavid E. O'Brien { "END", XEND, XEND }, 492a55deb1SDavid E. O'Brien { "NF", VARNF, VARNF }, 502a55deb1SDavid E. O'Brien { "atan2", FATAN, BLTIN }, 512a55deb1SDavid E. O'Brien { "break", BREAK, BREAK }, 522a55deb1SDavid E. O'Brien { "close", CLOSE, CLOSE }, 532a55deb1SDavid E. O'Brien { "continue", CONTINUE, CONTINUE }, 542a55deb1SDavid E. O'Brien { "cos", FCOS, BLTIN }, 552a55deb1SDavid E. O'Brien { "delete", DELETE, DELETE }, 562a55deb1SDavid E. O'Brien { "do", DO, DO }, 572a55deb1SDavid E. O'Brien { "else", ELSE, ELSE }, 582a55deb1SDavid E. O'Brien { "exit", EXIT, EXIT }, 592a55deb1SDavid E. O'Brien { "exp", FEXP, BLTIN }, 602a55deb1SDavid E. O'Brien { "fflush", FFLUSH, BLTIN }, 612a55deb1SDavid E. O'Brien { "for", FOR, FOR }, 622a55deb1SDavid E. O'Brien { "func", FUNC, FUNC }, 632a55deb1SDavid E. O'Brien { "function", FUNC, FUNC }, 642a55deb1SDavid E. O'Brien { "getline", GETLINE, GETLINE }, 652a55deb1SDavid E. O'Brien { "gsub", GSUB, GSUB }, 662a55deb1SDavid E. O'Brien { "if", IF, IF }, 672a55deb1SDavid E. O'Brien { "in", IN, IN }, 682a55deb1SDavid E. O'Brien { "index", INDEX, INDEX }, 692a55deb1SDavid E. O'Brien { "int", FINT, BLTIN }, 702a55deb1SDavid E. O'Brien { "length", FLENGTH, BLTIN }, 712a55deb1SDavid E. O'Brien { "log", FLOG, BLTIN }, 722a55deb1SDavid E. O'Brien { "match", MATCHFCN, MATCHFCN }, 732a55deb1SDavid E. O'Brien { "next", NEXT, NEXT }, 742a55deb1SDavid E. O'Brien { "nextfile", NEXTFILE, NEXTFILE }, 752a55deb1SDavid E. O'Brien { "print", PRINT, PRINT }, 762a55deb1SDavid E. O'Brien { "printf", PRINTF, PRINTF }, 772a55deb1SDavid E. O'Brien { "rand", FRAND, BLTIN }, 782a55deb1SDavid E. O'Brien { "return", RETURN, RETURN }, 792a55deb1SDavid E. O'Brien { "sin", FSIN, BLTIN }, 802a55deb1SDavid E. O'Brien { "split", SPLIT, SPLIT }, 812a55deb1SDavid E. O'Brien { "sprintf", SPRINTF, SPRINTF }, 822a55deb1SDavid E. O'Brien { "sqrt", FSQRT, BLTIN }, 832a55deb1SDavid E. O'Brien { "srand", FSRAND, BLTIN }, 842a55deb1SDavid E. O'Brien { "sub", SUB, SUB }, 852a55deb1SDavid E. O'Brien { "substr", SUBSTR, SUBSTR }, 862a55deb1SDavid E. O'Brien { "system", FSYSTEM, BLTIN }, 872a55deb1SDavid E. O'Brien { "tolower", FTOLOWER, BLTIN }, 882a55deb1SDavid E. O'Brien { "toupper", FTOUPPER, BLTIN }, 892a55deb1SDavid E. O'Brien { "while", WHILE, WHILE }, 902a55deb1SDavid E. O'Brien }; 912a55deb1SDavid E. O'Brien 922a55deb1SDavid E. O'Brien #define DEBUG 932a55deb1SDavid E. O'Brien #ifdef DEBUG 942a55deb1SDavid E. O'Brien #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); } 952a55deb1SDavid E. O'Brien #else 962a55deb1SDavid E. O'Brien #define RET(x) return(x) 972a55deb1SDavid E. O'Brien #endif 982a55deb1SDavid E. O'Brien 992a55deb1SDavid E. O'Brien int peek(void) 1002a55deb1SDavid E. O'Brien { 1012a55deb1SDavid E. O'Brien int c = input(); 1022a55deb1SDavid E. O'Brien unput(c); 1032a55deb1SDavid E. O'Brien return c; 1042a55deb1SDavid E. O'Brien } 1052a55deb1SDavid E. O'Brien 1062a55deb1SDavid E. O'Brien int gettok(char **pbuf, int *psz) /* get next input token */ 1072a55deb1SDavid E. O'Brien { 108007c6572SDag-Erling Smørgrav int c, retc; 1092a55deb1SDavid E. O'Brien char *buf = *pbuf; 1102a55deb1SDavid E. O'Brien int sz = *psz; 1112a55deb1SDavid E. O'Brien char *bp = buf; 1122a55deb1SDavid E. O'Brien 1132a55deb1SDavid E. O'Brien c = input(); 1142a55deb1SDavid E. O'Brien if (c == 0) 1152a55deb1SDavid E. O'Brien return 0; 1162a55deb1SDavid E. O'Brien buf[0] = c; 1172a55deb1SDavid E. O'Brien buf[1] = 0; 1182a55deb1SDavid E. O'Brien if (!isalnum(c) && c != '.' && c != '_') 1192a55deb1SDavid E. O'Brien return c; 1202a55deb1SDavid E. O'Brien 1212a55deb1SDavid E. O'Brien *bp++ = c; 1222a55deb1SDavid E. O'Brien if (isalpha(c) || c == '_') { /* it's a varname */ 1232a55deb1SDavid E. O'Brien for ( ; (c = input()) != 0; ) { 1242a55deb1SDavid E. O'Brien if (bp-buf >= sz) 1252a55deb1SDavid E. O'Brien if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) 1262a55deb1SDavid E. O'Brien FATAL( "out of space for name %.10s...", buf ); 1272a55deb1SDavid E. O'Brien if (isalnum(c) || c == '_') 1282a55deb1SDavid E. O'Brien *bp++ = c; 1292a55deb1SDavid E. O'Brien else { 1302a55deb1SDavid E. O'Brien *bp = 0; 1312a55deb1SDavid E. O'Brien unput(c); 1322a55deb1SDavid E. O'Brien break; 1332a55deb1SDavid E. O'Brien } 1342a55deb1SDavid E. O'Brien } 1352a55deb1SDavid E. O'Brien *bp = 0; 136007c6572SDag-Erling Smørgrav retc = 'a'; /* alphanumeric */ 1372a55deb1SDavid E. O'Brien } else { /* it's a number */ 1382a55deb1SDavid E. O'Brien char *rem; 1392a55deb1SDavid E. O'Brien /* read input until can't be a number */ 1402a55deb1SDavid E. O'Brien for ( ; (c = input()) != 0; ) { 1412a55deb1SDavid E. O'Brien if (bp-buf >= sz) 1422a55deb1SDavid E. O'Brien if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) 1432a55deb1SDavid E. O'Brien FATAL( "out of space for number %.10s...", buf ); 1442a55deb1SDavid E. O'Brien if (isdigit(c) || c == 'e' || c == 'E' 1452a55deb1SDavid E. O'Brien || c == '.' || c == '+' || c == '-') 1462a55deb1SDavid E. O'Brien *bp++ = c; 1472a55deb1SDavid E. O'Brien else { 1482a55deb1SDavid E. O'Brien unput(c); 1492a55deb1SDavid E. O'Brien break; 1502a55deb1SDavid E. O'Brien } 1512a55deb1SDavid E. O'Brien } 1522a55deb1SDavid E. O'Brien *bp = 0; 1532a55deb1SDavid E. O'Brien strtod(buf, &rem); /* parse the number */ 1542a55deb1SDavid E. O'Brien unputstr(rem); /* put rest back for later */ 155007c6572SDag-Erling Smørgrav if (rem == buf) { /* it wasn't a valid number at all */ 156007c6572SDag-Erling Smørgrav buf[1] = 0; /* so return one character as token */ 157007c6572SDag-Erling Smørgrav retc = buf[0]; /* character is its own type */ 158007c6572SDag-Erling Smørgrav } else { /* some prefix was a number */ 159007c6572SDag-Erling Smørgrav rem[0] = 0; /* so truncate where failure started */ 160007c6572SDag-Erling Smørgrav retc = '0'; /* number */ 161007c6572SDag-Erling Smørgrav } 1622a55deb1SDavid E. O'Brien } 1632a55deb1SDavid E. O'Brien *pbuf = buf; 1642a55deb1SDavid E. O'Brien *psz = sz; 165007c6572SDag-Erling Smørgrav return retc; 1662a55deb1SDavid E. O'Brien } 1672a55deb1SDavid E. O'Brien 1682a55deb1SDavid E. O'Brien int word(char *); 1692a55deb1SDavid E. O'Brien int string(void); 1702a55deb1SDavid E. O'Brien int regexpr(void); 1712a55deb1SDavid E. O'Brien int sc = 0; /* 1 => return a } right now */ 1722a55deb1SDavid E. O'Brien int reg = 0; /* 1 => return a REGEXPR now */ 1732a55deb1SDavid E. O'Brien 1742a55deb1SDavid E. O'Brien int yylex(void) 1752a55deb1SDavid E. O'Brien { 1762a55deb1SDavid E. O'Brien int c; 1772a55deb1SDavid E. O'Brien static char *buf = 0; 1782a55deb1SDavid E. O'Brien static int bufsize = 500; 1792a55deb1SDavid E. O'Brien 1802a55deb1SDavid E. O'Brien if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL) 1812a55deb1SDavid E. O'Brien FATAL( "out of space in yylex" ); 1822a55deb1SDavid E. O'Brien if (sc) { 1832a55deb1SDavid E. O'Brien sc = 0; 1842a55deb1SDavid E. O'Brien RET('}'); 1852a55deb1SDavid E. O'Brien } 1862a55deb1SDavid E. O'Brien if (reg) { 1872a55deb1SDavid E. O'Brien reg = 0; 1882a55deb1SDavid E. O'Brien return regexpr(); 1892a55deb1SDavid E. O'Brien } 1902a55deb1SDavid E. O'Brien for (;;) { 1912a55deb1SDavid E. O'Brien c = gettok(&buf, &bufsize); 1922a55deb1SDavid E. O'Brien if (c == 0) 1932a55deb1SDavid E. O'Brien return 0; 1942a55deb1SDavid E. O'Brien if (isalpha(c) || c == '_') 1952a55deb1SDavid E. O'Brien return word(buf); 196007c6572SDag-Erling Smørgrav if (isdigit(c)) { 1972a55deb1SDavid E. O'Brien yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab); 1982a55deb1SDavid E. O'Brien /* should this also have STR set? */ 1992a55deb1SDavid E. O'Brien RET(NUMBER); 2002a55deb1SDavid E. O'Brien } 2012a55deb1SDavid E. O'Brien 2022a55deb1SDavid E. O'Brien yylval.i = c; 2032a55deb1SDavid E. O'Brien switch (c) { 2042a55deb1SDavid E. O'Brien case '\n': /* {EOL} */ 2052a55deb1SDavid E. O'Brien RET(NL); 2062a55deb1SDavid E. O'Brien case '\r': /* assume \n is coming */ 2072a55deb1SDavid E. O'Brien case ' ': /* {WS}+ */ 2082a55deb1SDavid E. O'Brien case '\t': 2092a55deb1SDavid E. O'Brien break; 2102a55deb1SDavid E. O'Brien case '#': /* #.* strip comments */ 2112a55deb1SDavid E. O'Brien while ((c = input()) != '\n' && c != 0) 2122a55deb1SDavid E. O'Brien ; 2132a55deb1SDavid E. O'Brien unput(c); 2142a55deb1SDavid E. O'Brien break; 2152a55deb1SDavid E. O'Brien case ';': 2162a55deb1SDavid E. O'Brien RET(';'); 2172a55deb1SDavid E. O'Brien case '\\': 2182a55deb1SDavid E. O'Brien if (peek() == '\n') { 2192a55deb1SDavid E. O'Brien input(); 2202a55deb1SDavid E. O'Brien } else if (peek() == '\r') { 2212a55deb1SDavid E. O'Brien input(); input(); /* \n */ 2222a55deb1SDavid E. O'Brien lineno++; 2232a55deb1SDavid E. O'Brien } else { 2242a55deb1SDavid E. O'Brien RET(c); 2252a55deb1SDavid E. O'Brien } 2262a55deb1SDavid E. O'Brien break; 2272a55deb1SDavid E. O'Brien case '&': 2282a55deb1SDavid E. O'Brien if (peek() == '&') { 2292a55deb1SDavid E. O'Brien input(); RET(AND); 2302a55deb1SDavid E. O'Brien } else 2312a55deb1SDavid E. O'Brien RET('&'); 2322a55deb1SDavid E. O'Brien case '|': 2332a55deb1SDavid E. O'Brien if (peek() == '|') { 2342a55deb1SDavid E. O'Brien input(); RET(BOR); 2352a55deb1SDavid E. O'Brien } else 2362a55deb1SDavid E. O'Brien RET('|'); 2372a55deb1SDavid E. O'Brien case '!': 2382a55deb1SDavid E. O'Brien if (peek() == '=') { 2392a55deb1SDavid E. O'Brien input(); yylval.i = NE; RET(NE); 2402a55deb1SDavid E. O'Brien } else if (peek() == '~') { 2412a55deb1SDavid E. O'Brien input(); yylval.i = NOTMATCH; RET(MATCHOP); 2422a55deb1SDavid E. O'Brien } else 2432a55deb1SDavid E. O'Brien RET(NOT); 2442a55deb1SDavid E. O'Brien case '~': 2452a55deb1SDavid E. O'Brien yylval.i = MATCH; 2462a55deb1SDavid E. O'Brien RET(MATCHOP); 2472a55deb1SDavid E. O'Brien case '<': 2482a55deb1SDavid E. O'Brien if (peek() == '=') { 2492a55deb1SDavid E. O'Brien input(); yylval.i = LE; RET(LE); 2502a55deb1SDavid E. O'Brien } else { 2512a55deb1SDavid E. O'Brien yylval.i = LT; RET(LT); 2522a55deb1SDavid E. O'Brien } 2532a55deb1SDavid E. O'Brien case '=': 2542a55deb1SDavid E. O'Brien if (peek() == '=') { 2552a55deb1SDavid E. O'Brien input(); yylval.i = EQ; RET(EQ); 2562a55deb1SDavid E. O'Brien } else { 2572a55deb1SDavid E. O'Brien yylval.i = ASSIGN; RET(ASGNOP); 2582a55deb1SDavid E. O'Brien } 2592a55deb1SDavid E. O'Brien case '>': 2602a55deb1SDavid E. O'Brien if (peek() == '=') { 2612a55deb1SDavid E. O'Brien input(); yylval.i = GE; RET(GE); 2622a55deb1SDavid E. O'Brien } else if (peek() == '>') { 2632a55deb1SDavid E. O'Brien input(); yylval.i = APPEND; RET(APPEND); 2642a55deb1SDavid E. O'Brien } else { 2652a55deb1SDavid E. O'Brien yylval.i = GT; RET(GT); 2662a55deb1SDavid E. O'Brien } 2672a55deb1SDavid E. O'Brien case '+': 2682a55deb1SDavid E. O'Brien if (peek() == '+') { 2692a55deb1SDavid E. O'Brien input(); yylval.i = INCR; RET(INCR); 2702a55deb1SDavid E. O'Brien } else if (peek() == '=') { 2712a55deb1SDavid E. O'Brien input(); yylval.i = ADDEQ; RET(ASGNOP); 2722a55deb1SDavid E. O'Brien } else 2732a55deb1SDavid E. O'Brien RET('+'); 2742a55deb1SDavid E. O'Brien case '-': 2752a55deb1SDavid E. O'Brien if (peek() == '-') { 2762a55deb1SDavid E. O'Brien input(); yylval.i = DECR; RET(DECR); 2772a55deb1SDavid E. O'Brien } else if (peek() == '=') { 2782a55deb1SDavid E. O'Brien input(); yylval.i = SUBEQ; RET(ASGNOP); 2792a55deb1SDavid E. O'Brien } else 2802a55deb1SDavid E. O'Brien RET('-'); 2812a55deb1SDavid E. O'Brien case '*': 2822a55deb1SDavid E. O'Brien if (peek() == '=') { /* *= */ 2832a55deb1SDavid E. O'Brien input(); yylval.i = MULTEQ; RET(ASGNOP); 2842a55deb1SDavid E. O'Brien } else if (peek() == '*') { /* ** or **= */ 2852a55deb1SDavid E. O'Brien input(); /* eat 2nd * */ 2862a55deb1SDavid E. O'Brien if (peek() == '=') { 2872a55deb1SDavid E. O'Brien input(); yylval.i = POWEQ; RET(ASGNOP); 2882a55deb1SDavid E. O'Brien } else { 2892a55deb1SDavid E. O'Brien RET(POWER); 2902a55deb1SDavid E. O'Brien } 2912a55deb1SDavid E. O'Brien } else 2922a55deb1SDavid E. O'Brien RET('*'); 2932a55deb1SDavid E. O'Brien case '/': 2942a55deb1SDavid E. O'Brien RET('/'); 2952a55deb1SDavid E. O'Brien case '%': 2962a55deb1SDavid E. O'Brien if (peek() == '=') { 2972a55deb1SDavid E. O'Brien input(); yylval.i = MODEQ; RET(ASGNOP); 2982a55deb1SDavid E. O'Brien } else 2992a55deb1SDavid E. O'Brien RET('%'); 3002a55deb1SDavid E. O'Brien case '^': 3012a55deb1SDavid E. O'Brien if (peek() == '=') { 3022a55deb1SDavid E. O'Brien input(); yylval.i = POWEQ; RET(ASGNOP); 3032a55deb1SDavid E. O'Brien } else 3042a55deb1SDavid E. O'Brien RET(POWER); 3052a55deb1SDavid E. O'Brien 3062a55deb1SDavid E. O'Brien case '$': 3072a55deb1SDavid E. O'Brien /* BUG: awkward, if not wrong */ 3082a55deb1SDavid E. O'Brien c = gettok(&buf, &bufsize); 3092a55deb1SDavid E. O'Brien if (isalpha(c)) { 3102a55deb1SDavid E. O'Brien if (strcmp(buf, "NF") == 0) { /* very special */ 3112a55deb1SDavid E. O'Brien unputstr("(NF)"); 3122a55deb1SDavid E. O'Brien RET(INDIRECT); 3132a55deb1SDavid E. O'Brien } 3142a55deb1SDavid E. O'Brien c = peek(); 3152a55deb1SDavid E. O'Brien if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) { 3162a55deb1SDavid E. O'Brien unputstr(buf); 3172a55deb1SDavid E. O'Brien RET(INDIRECT); 3182a55deb1SDavid E. O'Brien } 3192a55deb1SDavid E. O'Brien yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab); 3202a55deb1SDavid E. O'Brien RET(IVAR); 321007c6572SDag-Erling Smørgrav } else if (c == 0) { /* */ 322007c6572SDag-Erling Smørgrav SYNTAX( "unexpected end of input after $" ); 323007c6572SDag-Erling Smørgrav RET(';'); 3242a55deb1SDavid E. O'Brien } else { 3252a55deb1SDavid E. O'Brien unputstr(buf); 3262a55deb1SDavid E. O'Brien RET(INDIRECT); 3272a55deb1SDavid E. O'Brien } 3282a55deb1SDavid E. O'Brien 3292a55deb1SDavid E. O'Brien case '}': 3302a55deb1SDavid E. O'Brien if (--bracecnt < 0) 3312a55deb1SDavid E. O'Brien SYNTAX( "extra }" ); 3322a55deb1SDavid E. O'Brien sc = 1; 3332a55deb1SDavid E. O'Brien RET(';'); 3342a55deb1SDavid E. O'Brien case ']': 3352a55deb1SDavid E. O'Brien if (--brackcnt < 0) 3362a55deb1SDavid E. O'Brien SYNTAX( "extra ]" ); 3372a55deb1SDavid E. O'Brien RET(']'); 3382a55deb1SDavid E. O'Brien case ')': 3392a55deb1SDavid E. O'Brien if (--parencnt < 0) 3402a55deb1SDavid E. O'Brien SYNTAX( "extra )" ); 3412a55deb1SDavid E. O'Brien RET(')'); 3422a55deb1SDavid E. O'Brien case '{': 3432a55deb1SDavid E. O'Brien bracecnt++; 3442a55deb1SDavid E. O'Brien RET('{'); 3452a55deb1SDavid E. O'Brien case '[': 3462a55deb1SDavid E. O'Brien brackcnt++; 3472a55deb1SDavid E. O'Brien RET('['); 3482a55deb1SDavid E. O'Brien case '(': 3492a55deb1SDavid E. O'Brien parencnt++; 3502a55deb1SDavid E. O'Brien RET('('); 3512a55deb1SDavid E. O'Brien 3522a55deb1SDavid E. O'Brien case '"': 3532a55deb1SDavid E. O'Brien return string(); /* BUG: should be like tran.c ? */ 3542a55deb1SDavid E. O'Brien 3552a55deb1SDavid E. O'Brien default: 3562a55deb1SDavid E. O'Brien RET(c); 3572a55deb1SDavid E. O'Brien } 3582a55deb1SDavid E. O'Brien } 3592a55deb1SDavid E. O'Brien } 3602a55deb1SDavid E. O'Brien 3612a55deb1SDavid E. O'Brien int string(void) 3622a55deb1SDavid E. O'Brien { 3632a55deb1SDavid E. O'Brien int c, n; 3642a55deb1SDavid E. O'Brien char *s, *bp; 3652a55deb1SDavid E. O'Brien static char *buf = 0; 3662a55deb1SDavid E. O'Brien static int bufsz = 500; 3672a55deb1SDavid E. O'Brien 3682a55deb1SDavid E. O'Brien if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) 3692a55deb1SDavid E. O'Brien FATAL("out of space for strings"); 3702a55deb1SDavid E. O'Brien for (bp = buf; (c = input()) != '"'; ) { 3712a55deb1SDavid E. O'Brien if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0)) 3722a55deb1SDavid E. O'Brien FATAL("out of space for string %.10s...", buf); 3732a55deb1SDavid E. O'Brien switch (c) { 3742a55deb1SDavid E. O'Brien case '\n': 3752a55deb1SDavid E. O'Brien case '\r': 3762a55deb1SDavid E. O'Brien case 0: 3772a55deb1SDavid E. O'Brien SYNTAX( "non-terminated string %.10s...", buf ); 3782a55deb1SDavid E. O'Brien lineno++; 379007c6572SDag-Erling Smørgrav if (c == 0) /* hopeless */ 380007c6572SDag-Erling Smørgrav FATAL( "giving up" ); 3812a55deb1SDavid E. O'Brien break; 3822a55deb1SDavid E. O'Brien case '\\': 3832a55deb1SDavid E. O'Brien c = input(); 3842a55deb1SDavid E. O'Brien switch (c) { 3852a55deb1SDavid E. O'Brien case '"': *bp++ = '"'; break; 3862a55deb1SDavid E. O'Brien case 'n': *bp++ = '\n'; break; 3872a55deb1SDavid E. O'Brien case 't': *bp++ = '\t'; break; 3882a55deb1SDavid E. O'Brien case 'f': *bp++ = '\f'; break; 3892a55deb1SDavid E. O'Brien case 'r': *bp++ = '\r'; break; 3902a55deb1SDavid E. O'Brien case 'b': *bp++ = '\b'; break; 3912a55deb1SDavid E. O'Brien case 'v': *bp++ = '\v'; break; 3922a55deb1SDavid E. O'Brien case 'a': *bp++ = '\007'; break; 3932a55deb1SDavid E. O'Brien case '\\': *bp++ = '\\'; break; 3942a55deb1SDavid E. O'Brien 3952a55deb1SDavid E. O'Brien case '0': case '1': case '2': /* octal: \d \dd \ddd */ 3962a55deb1SDavid E. O'Brien case '3': case '4': case '5': case '6': case '7': 3972a55deb1SDavid E. O'Brien n = c - '0'; 3982a55deb1SDavid E. O'Brien if ((c = peek()) >= '0' && c < '8') { 3992a55deb1SDavid E. O'Brien n = 8 * n + input() - '0'; 4002a55deb1SDavid E. O'Brien if ((c = peek()) >= '0' && c < '8') 4012a55deb1SDavid E. O'Brien n = 8 * n + input() - '0'; 4022a55deb1SDavid E. O'Brien } 4032a55deb1SDavid E. O'Brien *bp++ = n; 4042a55deb1SDavid E. O'Brien break; 4052a55deb1SDavid E. O'Brien 4062a55deb1SDavid E. O'Brien case 'x': /* hex \x0-9a-fA-F + */ 4072a55deb1SDavid E. O'Brien { char xbuf[100], *px; 4082a55deb1SDavid E. O'Brien for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) { 4092a55deb1SDavid E. O'Brien if (isdigit(c) 4102a55deb1SDavid E. O'Brien || (c >= 'a' && c <= 'f') 4112a55deb1SDavid E. O'Brien || (c >= 'A' && c <= 'F')) 4122a55deb1SDavid E. O'Brien *px++ = c; 4132a55deb1SDavid E. O'Brien else 4142a55deb1SDavid E. O'Brien break; 4152a55deb1SDavid E. O'Brien } 4162a55deb1SDavid E. O'Brien *px = 0; 4172a55deb1SDavid E. O'Brien unput(c); 4182a55deb1SDavid E. O'Brien sscanf(xbuf, "%x", &n); 4192a55deb1SDavid E. O'Brien *bp++ = n; 4202a55deb1SDavid E. O'Brien break; 4212a55deb1SDavid E. O'Brien } 4222a55deb1SDavid E. O'Brien 4232a55deb1SDavid E. O'Brien default: 4242a55deb1SDavid E. O'Brien *bp++ = c; 4252a55deb1SDavid E. O'Brien break; 4262a55deb1SDavid E. O'Brien } 4272a55deb1SDavid E. O'Brien break; 4282a55deb1SDavid E. O'Brien default: 4292a55deb1SDavid E. O'Brien *bp++ = c; 4302a55deb1SDavid E. O'Brien break; 4312a55deb1SDavid E. O'Brien } 4322a55deb1SDavid E. O'Brien } 4332a55deb1SDavid E. O'Brien *bp = 0; 4342a55deb1SDavid E. O'Brien s = tostring(buf); 4352a55deb1SDavid E. O'Brien *bp++ = ' '; *bp++ = 0; 4362a55deb1SDavid E. O'Brien yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab); 4372a55deb1SDavid E. O'Brien RET(STRING); 4382a55deb1SDavid E. O'Brien } 4392a55deb1SDavid E. O'Brien 4402a55deb1SDavid E. O'Brien 4412a55deb1SDavid E. O'Brien int binsearch(char *w, Keyword *kp, int n) 4422a55deb1SDavid E. O'Brien { 4432a55deb1SDavid E. O'Brien int cond, low, mid, high; 4442a55deb1SDavid E. O'Brien 4452a55deb1SDavid E. O'Brien low = 0; 4462a55deb1SDavid E. O'Brien high = n - 1; 4472a55deb1SDavid E. O'Brien while (low <= high) { 4482a55deb1SDavid E. O'Brien mid = (low + high) / 2; 4492a55deb1SDavid E. O'Brien if ((cond = strcmp(w, kp[mid].word)) < 0) 4502a55deb1SDavid E. O'Brien high = mid - 1; 4512a55deb1SDavid E. O'Brien else if (cond > 0) 4522a55deb1SDavid E. O'Brien low = mid + 1; 4532a55deb1SDavid E. O'Brien else 4542a55deb1SDavid E. O'Brien return mid; 4552a55deb1SDavid E. O'Brien } 4562a55deb1SDavid E. O'Brien return -1; 4572a55deb1SDavid E. O'Brien } 4582a55deb1SDavid E. O'Brien 4592a55deb1SDavid E. O'Brien int word(char *w) 4602a55deb1SDavid E. O'Brien { 4612a55deb1SDavid E. O'Brien Keyword *kp; 4622a55deb1SDavid E. O'Brien int c, n; 4632a55deb1SDavid E. O'Brien 4642a55deb1SDavid E. O'Brien n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0])); 4652a55deb1SDavid E. O'Brien kp = keywords + n; 4662a55deb1SDavid E. O'Brien if (n != -1) { /* found in table */ 4672a55deb1SDavid E. O'Brien yylval.i = kp->sub; 4682a55deb1SDavid E. O'Brien switch (kp->type) { /* special handling */ 4692a55deb1SDavid E. O'Brien case FSYSTEM: 4702a55deb1SDavid E. O'Brien if (safe) 4712a55deb1SDavid E. O'Brien SYNTAX( "system is unsafe" ); 4722a55deb1SDavid E. O'Brien RET(kp->type); 4732a55deb1SDavid E. O'Brien case FUNC: 4742a55deb1SDavid E. O'Brien if (infunc) 4752a55deb1SDavid E. O'Brien SYNTAX( "illegal nested function" ); 4762a55deb1SDavid E. O'Brien RET(kp->type); 4772a55deb1SDavid E. O'Brien case RETURN: 4782a55deb1SDavid E. O'Brien if (!infunc) 4792a55deb1SDavid E. O'Brien SYNTAX( "return not in function" ); 4802a55deb1SDavid E. O'Brien RET(kp->type); 4812a55deb1SDavid E. O'Brien case VARNF: 4822a55deb1SDavid E. O'Brien yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab); 4832a55deb1SDavid E. O'Brien RET(VARNF); 4842a55deb1SDavid E. O'Brien default: 4852a55deb1SDavid E. O'Brien RET(kp->type); 4862a55deb1SDavid E. O'Brien } 4872a55deb1SDavid E. O'Brien } 4882a55deb1SDavid E. O'Brien c = peek(); /* look for '(' */ 4892a55deb1SDavid E. O'Brien if (c != '(' && infunc && (n=isarg(w)) >= 0) { 4902a55deb1SDavid E. O'Brien yylval.i = n; 4912a55deb1SDavid E. O'Brien RET(ARG); 4922a55deb1SDavid E. O'Brien } else { 4932a55deb1SDavid E. O'Brien yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab); 4942a55deb1SDavid E. O'Brien if (c == '(') { 4952a55deb1SDavid E. O'Brien RET(CALL); 4962a55deb1SDavid E. O'Brien } else { 4972a55deb1SDavid E. O'Brien RET(VAR); 4982a55deb1SDavid E. O'Brien } 4992a55deb1SDavid E. O'Brien } 5002a55deb1SDavid E. O'Brien } 5012a55deb1SDavid E. O'Brien 502813da98dSDavid E. O'Brien void startreg(void) /* next call to yylex will return a regular expression */ 5032a55deb1SDavid E. O'Brien { 5042a55deb1SDavid E. O'Brien reg = 1; 5052a55deb1SDavid E. O'Brien } 5062a55deb1SDavid E. O'Brien 5072a55deb1SDavid E. O'Brien int regexpr(void) 5082a55deb1SDavid E. O'Brien { 5092a55deb1SDavid E. O'Brien int c; 5102a55deb1SDavid E. O'Brien static char *buf = 0; 5112a55deb1SDavid E. O'Brien static int bufsz = 500; 5122a55deb1SDavid E. O'Brien char *bp; 5132a55deb1SDavid E. O'Brien 5142a55deb1SDavid E. O'Brien if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) 5152a55deb1SDavid E. O'Brien FATAL("out of space for rex expr"); 5162a55deb1SDavid E. O'Brien bp = buf; 5172a55deb1SDavid E. O'Brien for ( ; (c = input()) != '/' && c != 0; ) { 5182a55deb1SDavid E. O'Brien if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0)) 5192a55deb1SDavid E. O'Brien FATAL("out of space for reg expr %.10s...", buf); 5202a55deb1SDavid E. O'Brien if (c == '\n') { 5212a55deb1SDavid E. O'Brien SYNTAX( "newline in regular expression %.10s...", buf ); 5222a55deb1SDavid E. O'Brien unput('\n'); 5232a55deb1SDavid E. O'Brien break; 5242a55deb1SDavid E. O'Brien } else if (c == '\\') { 5252a55deb1SDavid E. O'Brien *bp++ = '\\'; 5262a55deb1SDavid E. O'Brien *bp++ = input(); 5272a55deb1SDavid E. O'Brien } else { 5282a55deb1SDavid E. O'Brien *bp++ = c; 5292a55deb1SDavid E. O'Brien } 5302a55deb1SDavid E. O'Brien } 5312a55deb1SDavid E. O'Brien *bp = 0; 53288b8d487SRuslan Ermilov if (c == 0) 53388b8d487SRuslan Ermilov SYNTAX("non-terminated regular expression %.10s...", buf); 5342a55deb1SDavid E. O'Brien yylval.s = tostring(buf); 5352a55deb1SDavid E. O'Brien unput('/'); 5362a55deb1SDavid E. O'Brien RET(REGEXPR); 5372a55deb1SDavid E. O'Brien } 5382a55deb1SDavid E. O'Brien 5392a55deb1SDavid E. O'Brien /* low-level lexical stuff, sort of inherited from lex */ 5402a55deb1SDavid E. O'Brien 5412a55deb1SDavid E. O'Brien char ebuf[300]; 5422a55deb1SDavid E. O'Brien char *ep = ebuf; 5432a55deb1SDavid E. O'Brien char yysbuf[100]; /* pushback buffer */ 5442a55deb1SDavid E. O'Brien char *yysptr = yysbuf; 5452a55deb1SDavid E. O'Brien FILE *yyin = 0; 5462a55deb1SDavid E. O'Brien 5472a55deb1SDavid E. O'Brien int input(void) /* get next lexical input character */ 5482a55deb1SDavid E. O'Brien { 5492a55deb1SDavid E. O'Brien int c; 5502a55deb1SDavid E. O'Brien extern char *lexprog; 5512a55deb1SDavid E. O'Brien 5522a55deb1SDavid E. O'Brien if (yysptr > yysbuf) 5532e454f23SRuslan Ermilov c = (uschar)*--yysptr; 5542a55deb1SDavid E. O'Brien else if (lexprog != NULL) { /* awk '...' */ 5552e454f23SRuslan Ermilov if ((c = (uschar)*lexprog) != 0) 5562a55deb1SDavid E. O'Brien lexprog++; 5572a55deb1SDavid E. O'Brien } else /* awk -f ... */ 5582a55deb1SDavid E. O'Brien c = pgetc(); 5592a55deb1SDavid E. O'Brien if (c == '\n') 5602a55deb1SDavid E. O'Brien lineno++; 5612a55deb1SDavid E. O'Brien else if (c == EOF) 5622a55deb1SDavid E. O'Brien c = 0; 5632a55deb1SDavid E. O'Brien if (ep >= ebuf + sizeof ebuf) 5642a55deb1SDavid E. O'Brien ep = ebuf; 5652a55deb1SDavid E. O'Brien return *ep++ = c; 5662a55deb1SDavid E. O'Brien } 5672a55deb1SDavid E. O'Brien 5682a55deb1SDavid E. O'Brien void unput(int c) /* put lexical character back on input */ 5692a55deb1SDavid E. O'Brien { 5702a55deb1SDavid E. O'Brien if (c == '\n') 5712a55deb1SDavid E. O'Brien lineno--; 5722a55deb1SDavid E. O'Brien if (yysptr >= yysbuf + sizeof(yysbuf)) 5732a55deb1SDavid E. O'Brien FATAL("pushed back too much: %.20s...", yysbuf); 5742a55deb1SDavid E. O'Brien *yysptr++ = c; 5752a55deb1SDavid E. O'Brien if (--ep < ebuf) 5762a55deb1SDavid E. O'Brien ep = ebuf + sizeof(ebuf) - 1; 5772a55deb1SDavid E. O'Brien } 5782a55deb1SDavid E. O'Brien 579813da98dSDavid E. O'Brien void unputstr(const char *s) /* put a string back on input */ 5802a55deb1SDavid E. O'Brien { 5812a55deb1SDavid E. O'Brien int i; 5822a55deb1SDavid E. O'Brien 5832a55deb1SDavid E. O'Brien for (i = strlen(s)-1; i >= 0; i--) 5842a55deb1SDavid E. O'Brien unput(s[i]); 5852a55deb1SDavid E. O'Brien } 586