Home | History | Annotate | Line # | Download | only in dist
      1  1.1  christos /****************************************************************
      2  1.1  christos Copyright (C) Lucent Technologies 1997
      3  1.1  christos All Rights Reserved
      4  1.1  christos 
      5  1.1  christos Permission to use, copy, modify, and distribute this software and
      6  1.1  christos its documentation for any purpose and without fee is hereby
      7  1.1  christos granted, provided that the above copyright notice appear in all
      8  1.1  christos copies and that both that the copyright notice and this
      9  1.1  christos permission notice and warranty disclaimer appear in supporting
     10  1.1  christos documentation, and that the name Lucent Technologies or any of
     11  1.1  christos its entities not be used in advertising or publicity pertaining
     12  1.1  christos to distribution of the software without specific, written prior
     13  1.1  christos permission.
     14  1.1  christos 
     15  1.1  christos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     16  1.1  christos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
     17  1.1  christos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
     18  1.1  christos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  1.1  christos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
     20  1.1  christos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     21  1.1  christos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     22  1.1  christos THIS SOFTWARE.
     23  1.1  christos ****************************************************************/
     24  1.1  christos 
     25  1.2  christos #if HAVE_NBTOOL_CONFIG_H
     26  1.2  christos #include "nbtool_config.h"
     27  1.2  christos #endif
     28  1.2  christos 
     29  1.1  christos #include <stdio.h>
     30  1.1  christos #include <stdlib.h>
     31  1.1  christos #include <string.h>
     32  1.1  christos #include <ctype.h>
     33  1.1  christos #include "awk.h"
     34  1.2  christos #include "awkgram.h"
     35  1.1  christos 
     36  1.1  christos extern YYSTYPE	yylval;
     37  1.8  christos extern bool	infunc;
     38  1.1  christos 
     39  1.1  christos int	lineno	= 1;
     40  1.1  christos int	bracecnt = 0;
     41  1.1  christos int	brackcnt  = 0;
     42  1.1  christos int	parencnt = 0;
     43  1.1  christos 
     44  1.1  christos typedef struct Keyword {
     45  1.1  christos 	const char *word;
     46  1.1  christos 	int	sub;
     47  1.1  christos 	int	type;
     48  1.1  christos } Keyword;
     49  1.1  christos 
     50  1.6  christos const Keyword keywords[] = {	/* keep sorted: binary searched */
     51  1.1  christos 	{ "BEGIN",	XBEGIN,		XBEGIN },
     52  1.1  christos 	{ "END",	XEND,		XEND },
     53  1.1  christos 	{ "NF",		VARNF,		VARNF },
     54  1.6  christos 	{ "and",	FAND,		BLTIN },
     55  1.1  christos 	{ "atan2",	FATAN,		BLTIN },
     56  1.1  christos 	{ "break",	BREAK,		BREAK },
     57  1.1  christos 	{ "close",	CLOSE,		CLOSE },
     58  1.6  christos 	{ "compl",	FCOMPL,		BLTIN },
     59  1.1  christos 	{ "continue",	CONTINUE,	CONTINUE },
     60  1.1  christos 	{ "cos",	FCOS,		BLTIN },
     61  1.1  christos 	{ "delete",	DELETE,		DELETE },
     62  1.1  christos 	{ "do",		DO,		DO },
     63  1.1  christos 	{ "else",	ELSE,		ELSE },
     64  1.1  christos 	{ "exit",	EXIT,		EXIT },
     65  1.1  christos 	{ "exp",	FEXP,		BLTIN },
     66  1.1  christos 	{ "fflush",	FFLUSH,		BLTIN },
     67  1.1  christos 	{ "for",	FOR,		FOR },
     68  1.1  christos 	{ "func",	FUNC,		FUNC },
     69  1.1  christos 	{ "function",	FUNC,		FUNC },
     70  1.2  christos 	{ "gensub",	GENSUB,		GENSUB },
     71  1.1  christos 	{ "getline",	GETLINE,	GETLINE },
     72  1.1  christos 	{ "gsub",	GSUB,		GSUB },
     73  1.1  christos 	{ "if",		IF,		IF },
     74  1.1  christos 	{ "in",		IN,		IN },
     75  1.1  christos 	{ "index",	INDEX,		INDEX },
     76  1.1  christos 	{ "int",	FINT,		BLTIN },
     77  1.1  christos 	{ "length",	FLENGTH,	BLTIN },
     78  1.1  christos 	{ "log",	FLOG,		BLTIN },
     79  1.6  christos 	{ "lshift",	FLSHIFT,	BLTIN },
     80  1.1  christos 	{ "match",	MATCHFCN,	MATCHFCN },
     81  1.8  christos 	{ "mktime",	FMKTIME,	BLTIN },
     82  1.1  christos 	{ "next",	NEXT,		NEXT },
     83  1.1  christos 	{ "nextfile",	NEXTFILE,	NEXTFILE },
     84  1.6  christos 	{ "or",		FFOR,		BLTIN },
     85  1.1  christos 	{ "print",	PRINT,		PRINT },
     86  1.1  christos 	{ "printf",	PRINTF,		PRINTF },
     87  1.1  christos 	{ "rand",	FRAND,		BLTIN },
     88  1.1  christos 	{ "return",	RETURN,		RETURN },
     89  1.6  christos 	{ "rshift",	FRSHIFT,	BLTIN },
     90  1.1  christos 	{ "sin",	FSIN,		BLTIN },
     91  1.1  christos 	{ "split",	SPLIT,		SPLIT },
     92  1.1  christos 	{ "sprintf",	SPRINTF,	SPRINTF },
     93  1.1  christos 	{ "sqrt",	FSQRT,		BLTIN },
     94  1.1  christos 	{ "srand",	FSRAND,		BLTIN },
     95  1.2  christos 	{ "strftime",	FSTRFTIME,	BLTIN },
     96  1.1  christos 	{ "sub",	SUB,		SUB },
     97  1.1  christos 	{ "substr",	SUBSTR,		SUBSTR },
     98  1.1  christos 	{ "system",	FSYSTEM,	BLTIN },
     99  1.2  christos 	{ "systime",	FSYSTIME,	BLTIN },
    100  1.1  christos 	{ "tolower",	FTOLOWER,	BLTIN },
    101  1.1  christos 	{ "toupper",	FTOUPPER,	BLTIN },
    102  1.1  christos 	{ "while",	WHILE,		WHILE },
    103  1.6  christos 	{ "xor",	FXOR,		BLTIN },
    104  1.1  christos };
    105  1.1  christos 
    106  1.1  christos #define	RET(x)	{ if(dbg)printf("lex %s\n", tokname(x)); return(x); }
    107  1.1  christos 
    108  1.6  christos static int peek(void)
    109  1.1  christos {
    110  1.1  christos 	int c = input();
    111  1.1  christos 	unput(c);
    112  1.1  christos 	return c;
    113  1.1  christos }
    114  1.1  christos 
    115  1.6  christos static int gettok(char **pbuf, int *psz)	/* get next input token */
    116  1.1  christos {
    117  1.1  christos 	int c, retc;
    118  1.6  christos 	char *buf = *pbuf;
    119  1.1  christos 	int sz = *psz;
    120  1.6  christos 	char *bp = buf;
    121  1.1  christos 
    122  1.1  christos 	c = input();
    123  1.1  christos 	if (c == 0)
    124  1.1  christos 		return 0;
    125  1.1  christos 	buf[0] = c;
    126  1.1  christos 	buf[1] = 0;
    127  1.1  christos 	if (!isalnum(c) && c != '.' && c != '_')
    128  1.1  christos 		return c;
    129  1.1  christos 
    130  1.1  christos 	*bp++ = c;
    131  1.1  christos 	if (isalpha(c) || c == '_') {	/* it's a varname */
    132  1.1  christos 		for ( ; (c = input()) != 0; ) {
    133  1.1  christos 			if (bp-buf >= sz)
    134  1.1  christos 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
    135  1.1  christos 					FATAL( "out of space for name %.10s...", buf );
    136  1.1  christos 			if (isalnum(c) || c == '_')
    137  1.1  christos 				*bp++ = c;
    138  1.1  christos 			else {
    139  1.1  christos 				*bp = 0;
    140  1.1  christos 				unput(c);
    141  1.1  christos 				break;
    142  1.1  christos 			}
    143  1.1  christos 		}
    144  1.1  christos 		*bp = 0;
    145  1.1  christos 		retc = 'a';	/* alphanumeric */
    146  1.1  christos 	} else {	/* maybe it's a number, but could be . */
    147  1.1  christos 		char *rem;
    148  1.1  christos 		/* read input until can't be a number */
    149  1.1  christos 		for ( ; (c = input()) != 0; ) {
    150  1.1  christos 			if (bp-buf >= sz)
    151  1.1  christos 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
    152  1.1  christos 					FATAL( "out of space for number %.10s...", buf );
    153  1.5  christos 			if (isdigit(c) || c == 'e' || c == 'E'
    154  1.1  christos 			  || c == '.' || c == '+' || c == '-')
    155  1.1  christos 				*bp++ = c;
    156  1.1  christos 			else {
    157  1.1  christos 				unput(c);
    158  1.1  christos 				break;
    159  1.1  christos 			}
    160  1.1  christos 		}
    161  1.1  christos 		*bp = 0;
    162  1.1  christos 		strtod(buf, &rem);	/* parse the number */
    163  1.6  christos 		if (rem == buf) {	/* it wasn't a valid number at all */
    164  1.1  christos 			buf[1] = 0;	/* return one character as token */
    165  1.8  christos 			retc = (uschar)buf[0];	/* character is its own type */
    166  1.1  christos 			unputstr(rem+1); /* put rest back for later */
    167  1.1  christos 		} else {	/* some prefix was a number */
    168  1.1  christos 			unputstr(rem);	/* put rest back for later */
    169  1.1  christos 			rem[0] = 0;	/* truncate buf after number part */
    170  1.1  christos 			retc = '0';	/* type is number */
    171  1.1  christos 		}
    172  1.1  christos 	}
    173  1.1  christos 	*pbuf = buf;
    174  1.1  christos 	*psz = sz;
    175  1.1  christos 	return retc;
    176  1.1  christos }
    177  1.1  christos 
    178  1.1  christos int	word(char *);
    179  1.1  christos int	string(void);
    180  1.1  christos int	regexpr(void);
    181  1.6  christos bool	sc	= false;	/* true => return a } right now */
    182  1.6  christos bool	reg	= false;	/* true => return a REGEXPR now */
    183  1.1  christos 
    184  1.1  christos int yylex(void)
    185  1.1  christos {
    186  1.1  christos 	int c;
    187  1.6  christos 	static char *buf = NULL;
    188  1.1  christos 	static int bufsize = 5; /* BUG: setting this small causes core dump! */
    189  1.1  christos 
    190  1.8  christos 	if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL)
    191  1.1  christos 		FATAL( "out of space in yylex" );
    192  1.1  christos 	if (sc) {
    193  1.6  christos 		sc = false;
    194  1.1  christos 		RET('}');
    195  1.1  christos 	}
    196  1.1  christos 	if (reg) {
    197  1.6  christos 		reg = false;
    198  1.1  christos 		return regexpr();
    199  1.1  christos 	}
    200  1.1  christos 	for (;;) {
    201  1.1  christos 		c = gettok(&buf, &bufsize);
    202  1.1  christos 		if (c == 0)
    203  1.1  christos 			return 0;
    204  1.1  christos 		if (isalpha(c) || c == '_')
    205  1.1  christos 			return word(buf);
    206  1.1  christos 		if (isdigit(c)) {
    207  1.6  christos 			char *cp = tostring(buf);
    208  1.8  christos 			double result;
    209  1.8  christos 
    210  1.8  christos 			if (is_number(cp, & result))
    211  1.8  christos 				yylval.cp = setsymtab(buf, cp, result, CON|NUM, symtab);
    212  1.8  christos 			else
    213  1.8  christos 				yylval.cp = setsymtab(buf, cp, 0.0, STR, symtab);
    214  1.6  christos 			free(cp);
    215  1.1  christos 			/* should this also have STR set? */
    216  1.1  christos 			RET(NUMBER);
    217  1.1  christos 		}
    218  1.5  christos 
    219  1.1  christos 		yylval.i = c;
    220  1.1  christos 		switch (c) {
    221  1.1  christos 		case '\n':	/* {EOL} */
    222  1.6  christos 			lineno++;
    223  1.1  christos 			RET(NL);
    224  1.1  christos 		case '\r':	/* assume \n is coming */
    225  1.1  christos 		case ' ':	/* {WS}+ */
    226  1.1  christos 		case '\t':
    227  1.1  christos 			break;
    228  1.1  christos 		case '#':	/* #.* strip comments */
    229  1.1  christos 			while ((c = input()) != '\n' && c != 0)
    230  1.1  christos 				;
    231  1.1  christos 			unput(c);
    232  1.1  christos 			break;
    233  1.1  christos 		case ';':
    234  1.1  christos 			RET(';');
    235  1.1  christos 		case '\\':
    236  1.1  christos 			if (peek() == '\n') {
    237  1.1  christos 				input();
    238  1.6  christos 				lineno++;
    239  1.1  christos 			} else if (peek() == '\r') {
    240  1.1  christos 				input(); input();	/* \n */
    241  1.1  christos 				lineno++;
    242  1.1  christos 			} else {
    243  1.1  christos 				RET(c);
    244  1.1  christos 			}
    245  1.1  christos 			break;
    246  1.1  christos 		case '&':
    247  1.1  christos 			if (peek() == '&') {
    248  1.1  christos 				input(); RET(AND);
    249  1.5  christos 			} else
    250  1.1  christos 				RET('&');
    251  1.1  christos 		case '|':
    252  1.1  christos 			if (peek() == '|') {
    253  1.1  christos 				input(); RET(BOR);
    254  1.1  christos 			} else
    255  1.1  christos 				RET('|');
    256  1.1  christos 		case '!':
    257  1.1  christos 			if (peek() == '=') {
    258  1.1  christos 				input(); yylval.i = NE; RET(NE);
    259  1.1  christos 			} else if (peek() == '~') {
    260  1.1  christos 				input(); yylval.i = NOTMATCH; RET(MATCHOP);
    261  1.1  christos 			} else
    262  1.1  christos 				RET(NOT);
    263  1.1  christos 		case '~':
    264  1.1  christos 			yylval.i = MATCH;
    265  1.1  christos 			RET(MATCHOP);
    266  1.1  christos 		case '<':
    267  1.1  christos 			if (peek() == '=') {
    268  1.1  christos 				input(); yylval.i = LE; RET(LE);
    269  1.1  christos 			} else {
    270  1.1  christos 				yylval.i = LT; RET(LT);
    271  1.1  christos 			}
    272  1.1  christos 		case '=':
    273  1.1  christos 			if (peek() == '=') {
    274  1.1  christos 				input(); yylval.i = EQ; RET(EQ);
    275  1.1  christos 			} else {
    276  1.1  christos 				yylval.i = ASSIGN; RET(ASGNOP);
    277  1.1  christos 			}
    278  1.1  christos 		case '>':
    279  1.1  christos 			if (peek() == '=') {
    280  1.1  christos 				input(); yylval.i = GE; RET(GE);
    281  1.1  christos 			} else if (peek() == '>') {
    282  1.1  christos 				input(); yylval.i = APPEND; RET(APPEND);
    283  1.1  christos 			} else {
    284  1.1  christos 				yylval.i = GT; RET(GT);
    285  1.1  christos 			}
    286  1.1  christos 		case '+':
    287  1.1  christos 			if (peek() == '+') {
    288  1.1  christos 				input(); yylval.i = INCR; RET(INCR);
    289  1.1  christos 			} else if (peek() == '=') {
    290  1.1  christos 				input(); yylval.i = ADDEQ; RET(ASGNOP);
    291  1.1  christos 			} else
    292  1.1  christos 				RET('+');
    293  1.1  christos 		case '-':
    294  1.1  christos 			if (peek() == '-') {
    295  1.1  christos 				input(); yylval.i = DECR; RET(DECR);
    296  1.1  christos 			} else if (peek() == '=') {
    297  1.1  christos 				input(); yylval.i = SUBEQ; RET(ASGNOP);
    298  1.1  christos 			} else
    299  1.1  christos 				RET('-');
    300  1.1  christos 		case '*':
    301  1.1  christos 			if (peek() == '=') {	/* *= */
    302  1.1  christos 				input(); yylval.i = MULTEQ; RET(ASGNOP);
    303  1.1  christos 			} else if (peek() == '*') {	/* ** or **= */
    304  1.1  christos 				input();	/* eat 2nd * */
    305  1.1  christos 				if (peek() == '=') {
    306  1.1  christos 					input(); yylval.i = POWEQ; RET(ASGNOP);
    307  1.1  christos 				} else {
    308  1.1  christos 					RET(POWER);
    309  1.1  christos 				}
    310  1.1  christos 			} else
    311  1.1  christos 				RET('*');
    312  1.1  christos 		case '/':
    313  1.1  christos 			RET('/');
    314  1.1  christos 		case '%':
    315  1.1  christos 			if (peek() == '=') {
    316  1.1  christos 				input(); yylval.i = MODEQ; RET(ASGNOP);
    317  1.1  christos 			} else
    318  1.1  christos 				RET('%');
    319  1.1  christos 		case '^':
    320  1.1  christos 			if (peek() == '=') {
    321  1.1  christos 				input(); yylval.i = POWEQ; RET(ASGNOP);
    322  1.1  christos 			} else
    323  1.1  christos 				RET(POWER);
    324  1.1  christos 
    325  1.1  christos 		case '$':
    326  1.1  christos 			/* BUG: awkward, if not wrong */
    327  1.1  christos 			c = gettok(&buf, &bufsize);
    328  1.1  christos 			if (isalpha(c)) {
    329  1.1  christos 				if (strcmp(buf, "NF") == 0) {	/* very special */
    330  1.1  christos 					unputstr("(NF)");
    331  1.1  christos 					RET(INDIRECT);
    332  1.1  christos 				}
    333  1.1  christos 				c = peek();
    334  1.1  christos 				if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
    335  1.1  christos 					unputstr(buf);
    336  1.1  christos 					RET(INDIRECT);
    337  1.1  christos 				}
    338  1.1  christos 				yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
    339  1.1  christos 				RET(IVAR);
    340  1.1  christos 			} else if (c == 0) {	/*  */
    341  1.1  christos 				SYNTAX( "unexpected end of input after $" );
    342  1.1  christos 				RET(';');
    343  1.1  christos 			} else {
    344  1.1  christos 				unputstr(buf);
    345  1.1  christos 				RET(INDIRECT);
    346  1.1  christos 			}
    347  1.5  christos 
    348  1.1  christos 		case '}':
    349  1.1  christos 			if (--bracecnt < 0)
    350  1.1  christos 				SYNTAX( "extra }" );
    351  1.6  christos 			sc = true;
    352  1.1  christos 			RET(';');
    353  1.1  christos 		case ']':
    354  1.1  christos 			if (--brackcnt < 0)
    355  1.1  christos 				SYNTAX( "extra ]" );
    356  1.1  christos 			RET(']');
    357  1.1  christos 		case ')':
    358  1.1  christos 			if (--parencnt < 0)
    359  1.1  christos 				SYNTAX( "extra )" );
    360  1.1  christos 			RET(')');
    361  1.1  christos 		case '{':
    362  1.1  christos 			bracecnt++;
    363  1.1  christos 			RET('{');
    364  1.1  christos 		case '[':
    365  1.1  christos 			brackcnt++;
    366  1.1  christos 			RET('[');
    367  1.1  christos 		case '(':
    368  1.1  christos 			parencnt++;
    369  1.1  christos 			RET('(');
    370  1.5  christos 
    371  1.1  christos 		case '"':
    372  1.1  christos 			return string();	/* BUG: should be like tran.c ? */
    373  1.5  christos 
    374  1.1  christos 		default:
    375  1.1  christos 			RET(c);
    376  1.1  christos 		}
    377  1.1  christos 	}
    378  1.1  christos }
    379  1.1  christos 
    380  1.1  christos int string(void)
    381  1.1  christos {
    382  1.1  christos 	int c, n;
    383  1.6  christos 	char *s, *bp;
    384  1.6  christos 	static char *buf = NULL;
    385  1.1  christos 	static int bufsz = 500;
    386  1.1  christos 
    387  1.8  christos 	if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
    388  1.1  christos 		FATAL("out of space for strings");
    389  1.1  christos 	for (bp = buf; (c = input()) != '"'; ) {
    390  1.1  christos 		if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
    391  1.1  christos 			FATAL("out of space for string %.10s...", buf);
    392  1.1  christos 		switch (c) {
    393  1.1  christos 		case '\n':
    394  1.1  christos 		case '\r':
    395  1.1  christos 		case 0:
    396  1.6  christos 			*bp = '\0';
    397  1.1  christos 			SYNTAX( "non-terminated string %.10s...", buf );
    398  1.1  christos 			if (c == 0)	/* hopeless */
    399  1.1  christos 				FATAL( "giving up" );
    400  1.6  christos 			lineno++;
    401  1.1  christos 			break;
    402  1.1  christos 		case '\\':
    403  1.1  christos 			c = input();
    404  1.1  christos 			switch (c) {
    405  1.7  christos 			case '\n': break;
    406  1.1  christos 			case '"': *bp++ = '"'; break;
    407  1.5  christos 			case 'n': *bp++ = '\n'; break;
    408  1.1  christos 			case 't': *bp++ = '\t'; break;
    409  1.1  christos 			case 'f': *bp++ = '\f'; break;
    410  1.1  christos 			case 'r': *bp++ = '\r'; break;
    411  1.1  christos 			case 'b': *bp++ = '\b'; break;
    412  1.1  christos 			case 'v': *bp++ = '\v'; break;
    413  1.6  christos 			case 'a': *bp++ = '\a'; break;
    414  1.1  christos 			case '\\': *bp++ = '\\'; break;
    415  1.1  christos 
    416  1.1  christos 			case '0': case '1': case '2': /* octal: \d \dd \ddd */
    417  1.1  christos 			case '3': case '4': case '5': case '6': case '7':
    418  1.1  christos 				n = c - '0';
    419  1.1  christos 				if ((c = peek()) >= '0' && c < '8') {
    420  1.1  christos 					n = 8 * n + input() - '0';
    421  1.1  christos 					if ((c = peek()) >= '0' && c < '8')
    422  1.1  christos 						n = 8 * n + input() - '0';
    423  1.1  christos 				}
    424  1.1  christos 				*bp++ = n;
    425  1.1  christos 				break;
    426  1.1  christos 
    427  1.8  christos 			case 'x':	/* hex  \x0-9a-fA-F (exactly two) */
    428  1.8  christos 			    {
    429  1.8  christos 				int i;
    430  1.8  christos 
    431  1.8  christos 				if (!isxdigit(peek())) {
    432  1.8  christos 					unput(c);
    433  1.8  christos 					break;
    434  1.8  christos 				}
    435  1.8  christos 				n = 0;
    436  1.8  christos 				for (i = 0; i < 2; i++) {
    437  1.8  christos 					c = input();
    438  1.8  christos 					if (c == 0)
    439  1.8  christos 						break;
    440  1.8  christos 					if (isxdigit(c)) {
    441  1.8  christos 						c = tolower(c);
    442  1.8  christos 						n *= 16;
    443  1.8  christos 						if (isdigit(c))
    444  1.8  christos 							n += (c - '0');
    445  1.8  christos 						else
    446  1.8  christos 							n += 10 + (c - 'a');
    447  1.8  christos 					} else {
    448  1.8  christos 						unput(c);
    449  1.8  christos 						break;
    450  1.8  christos 					}
    451  1.8  christos 				}
    452  1.8  christos 				if (i)
    453  1.8  christos 					*bp++ = n;
    454  1.8  christos 				break;
    455  1.8  christos 			    }
    456  1.8  christos 
    457  1.8  christos 			case 'u':	/* utf  \u0-9a-fA-F (1..8) */
    458  1.8  christos 			    {
    459  1.8  christos 				int i;
    460  1.8  christos 
    461  1.8  christos 				n = 0;
    462  1.8  christos 				for (i = 0; i < 8; i++) {
    463  1.8  christos 					c = input();
    464  1.8  christos 					if (!isxdigit(c) || c == 0)
    465  1.8  christos 						break;
    466  1.8  christos 					c = tolower(c);
    467  1.8  christos 					n *= 16;
    468  1.8  christos 					if (isdigit(c))
    469  1.8  christos 						n += (c - '0');
    470  1.1  christos 					else
    471  1.8  christos 						n += 10 + (c - 'a');
    472  1.1  christos 				}
    473  1.1  christos 				unput(c);
    474  1.8  christos 				bp += runetochar(bp, n);
    475  1.1  christos 				break;
    476  1.1  christos 			    }
    477  1.1  christos 
    478  1.2  christos 			default:
    479  1.1  christos 				*bp++ = c;
    480  1.1  christos 				break;
    481  1.1  christos 			}
    482  1.1  christos 			break;
    483  1.1  christos 		default:
    484  1.1  christos 			*bp++ = c;
    485  1.1  christos 			break;
    486  1.1  christos 		}
    487  1.1  christos 	}
    488  1.5  christos 	*bp = 0;
    489  1.1  christos 	s = tostring(buf);
    490  1.6  christos 	*bp++ = ' '; *bp++ = '\0';
    491  1.1  christos 	yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
    492  1.6  christos 	free(s);
    493  1.1  christos 	RET(STRING);
    494  1.1  christos }
    495  1.1  christos 
    496  1.1  christos 
    497  1.6  christos static int binsearch(char *w, const Keyword *kp, int n)
    498  1.1  christos {
    499  1.1  christos 	int cond, low, mid, high;
    500  1.1  christos 
    501  1.1  christos 	low = 0;
    502  1.1  christos 	high = n - 1;
    503  1.1  christos 	while (low <= high) {
    504  1.1  christos 		mid = (low + high) / 2;
    505  1.1  christos 		if ((cond = strcmp(w, kp[mid].word)) < 0)
    506  1.1  christos 			high = mid - 1;
    507  1.1  christos 		else if (cond > 0)
    508  1.1  christos 			low = mid + 1;
    509  1.1  christos 		else
    510  1.1  christos 			return mid;
    511  1.1  christos 	}
    512  1.1  christos 	return -1;
    513  1.1  christos }
    514  1.1  christos 
    515  1.5  christos int word(char *w)
    516  1.1  christos {
    517  1.2  christos 	const Keyword *kp;
    518  1.1  christos 	int c, n;
    519  1.1  christos 
    520  1.1  christos 	n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
    521  1.1  christos 	if (n != -1) {	/* found in table */
    522  1.4     kamil 		kp = keywords + n;
    523  1.1  christos 		yylval.i = kp->sub;
    524  1.1  christos 		switch (kp->type) {	/* special handling */
    525  1.1  christos 		case BLTIN:
    526  1.1  christos 			if (kp->sub == FSYSTEM && safe)
    527  1.1  christos 				SYNTAX( "system is unsafe" );
    528  1.1  christos 			RET(kp->type);
    529  1.1  christos 		case FUNC:
    530  1.1  christos 			if (infunc)
    531  1.1  christos 				SYNTAX( "illegal nested function" );
    532  1.1  christos 			RET(kp->type);
    533  1.1  christos 		case RETURN:
    534  1.1  christos 			if (!infunc)
    535  1.1  christos 				SYNTAX( "return not in function" );
    536  1.1  christos 			RET(kp->type);
    537  1.1  christos 		case VARNF:
    538  1.1  christos 			yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
    539  1.1  christos 			RET(VARNF);
    540  1.1  christos 		default:
    541  1.1  christos 			RET(kp->type);
    542  1.1  christos 		}
    543  1.1  christos 	}
    544  1.1  christos 	c = peek();	/* look for '(' */
    545  1.1  christos 	if (c != '(' && infunc && (n=isarg(w)) >= 0) {
    546  1.1  christos 		yylval.i = n;
    547  1.1  christos 		RET(ARG);
    548  1.1  christos 	} else {
    549  1.1  christos 		yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
    550  1.1  christos 		if (c == '(') {
    551  1.1  christos 			RET(CALL);
    552  1.1  christos 		} else {
    553  1.1  christos 			RET(VAR);
    554  1.1  christos 		}
    555  1.1  christos 	}
    556  1.1  christos }
    557  1.1  christos 
    558  1.1  christos void startreg(void)	/* next call to yylex will return a regular expression */
    559  1.1  christos {
    560  1.6  christos 	reg = true;
    561  1.1  christos }
    562  1.1  christos 
    563  1.1  christos int regexpr(void)
    564  1.1  christos {
    565  1.1  christos 	int c;
    566  1.6  christos 	static char *buf = NULL;
    567  1.1  christos 	static int bufsz = 500;
    568  1.6  christos 	char *bp;
    569  1.1  christos 
    570  1.8  christos 	if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
    571  1.8  christos 		FATAL("out of space for reg expr");
    572  1.1  christos 	bp = buf;
    573  1.1  christos 	for ( ; (c = input()) != '/' && c != 0; ) {
    574  1.1  christos 		if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
    575  1.1  christos 			FATAL("out of space for reg expr %.10s...", buf);
    576  1.1  christos 		if (c == '\n') {
    577  1.6  christos 			*bp = '\0';
    578  1.5  christos 			SYNTAX( "newline in regular expression %.10s...", buf );
    579  1.1  christos 			unput('\n');
    580  1.1  christos 			break;
    581  1.1  christos 		} else if (c == '\\') {
    582  1.5  christos 			*bp++ = '\\';
    583  1.1  christos 			*bp++ = input();
    584  1.1  christos 		} else {
    585  1.1  christos 			*bp++ = c;
    586  1.1  christos 		}
    587  1.1  christos 	}
    588  1.1  christos 	*bp = 0;
    589  1.1  christos 	if (c == 0)
    590  1.1  christos 		SYNTAX("non-terminated regular expression %.10s...", buf);
    591  1.1  christos 	yylval.s = tostring(buf);
    592  1.1  christos 	unput('/');
    593  1.1  christos 	RET(REGEXPR);
    594  1.1  christos }
    595  1.1  christos 
    596  1.1  christos /* low-level lexical stuff, sort of inherited from lex */
    597  1.1  christos 
    598  1.1  christos char	ebuf[300];
    599  1.1  christos char	*ep = ebuf;
    600  1.1  christos char	yysbuf[100];	/* pushback buffer */
    601  1.1  christos char	*yysptr = yysbuf;
    602  1.6  christos FILE	*yyin = NULL;
    603  1.1  christos 
    604  1.1  christos int input(void)	/* get next lexical input character */
    605  1.1  christos {
    606  1.1  christos 	int c;
    607  1.1  christos 	extern char *lexprog;
    608  1.1  christos 
    609  1.1  christos 	if (yysptr > yysbuf)
    610  1.1  christos 		c = (uschar)*--yysptr;
    611  1.1  christos 	else if (lexprog != NULL) {	/* awk '...' */
    612  1.1  christos 		if ((c = (uschar)*lexprog) != 0)
    613  1.1  christos 			lexprog++;
    614  1.1  christos 	} else				/* awk -f ... */
    615  1.1  christos 		c = pgetc();
    616  1.6  christos 	if (c == EOF)
    617  1.1  christos 		c = 0;
    618  1.1  christos 	if (ep >= ebuf + sizeof ebuf)
    619  1.1  christos 		ep = ebuf;
    620  1.6  christos 	*ep = c;
    621  1.6  christos 	if (c != 0) {
    622  1.6  christos 		ep++;
    623  1.6  christos 	}
    624  1.6  christos 	return (c);
    625  1.1  christos }
    626  1.1  christos 
    627  1.1  christos void unput(int c)	/* put lexical character back on input */
    628  1.1  christos {
    629  1.1  christos 	if (yysptr >= yysbuf + sizeof(yysbuf))
    630  1.1  christos 		FATAL("pushed back too much: %.20s...", yysbuf);
    631  1.1  christos 	*yysptr++ = c;
    632  1.1  christos 	if (--ep < ebuf)
    633  1.1  christos 		ep = ebuf + sizeof(ebuf) - 1;
    634  1.1  christos }
    635  1.1  christos 
    636  1.1  christos void unputstr(const char *s)	/* put a string back on input */
    637  1.1  christos {
    638  1.1  christos 	int i;
    639  1.1  christos 
    640  1.1  christos 	for (i = strlen(s)-1; i >= 0; i--)
    641  1.1  christos 		unput(s[i]);
    642  1.1  christos }
    643