xref: /netbsd/external/historical/nawk/dist/lex.c (revision e66db18e)
135f471cbSchristos /****************************************************************
235f471cbSchristos Copyright (C) Lucent Technologies 1997
335f471cbSchristos All Rights Reserved
435f471cbSchristos 
535f471cbSchristos Permission to use, copy, modify, and distribute this software and
635f471cbSchristos its documentation for any purpose and without fee is hereby
735f471cbSchristos granted, provided that the above copyright notice appear in all
835f471cbSchristos copies and that both that the copyright notice and this
935f471cbSchristos permission notice and warranty disclaimer appear in supporting
1035f471cbSchristos documentation, and that the name Lucent Technologies or any of
1135f471cbSchristos its entities not be used in advertising or publicity pertaining
1235f471cbSchristos to distribution of the software without specific, written prior
1335f471cbSchristos permission.
1435f471cbSchristos 
1535f471cbSchristos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1635f471cbSchristos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1735f471cbSchristos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1835f471cbSchristos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1935f471cbSchristos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2035f471cbSchristos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2135f471cbSchristos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2235f471cbSchristos THIS SOFTWARE.
2335f471cbSchristos ****************************************************************/
2435f471cbSchristos 
255642d004Schristos #if HAVE_NBTOOL_CONFIG_H
265642d004Schristos #include "nbtool_config.h"
275642d004Schristos #endif
285642d004Schristos 
2935f471cbSchristos #include <stdio.h>
3035f471cbSchristos #include <stdlib.h>
3135f471cbSchristos #include <string.h>
3235f471cbSchristos #include <ctype.h>
3335f471cbSchristos #include "awk.h"
345642d004Schristos #include "awkgram.h"
3535f471cbSchristos 
3635f471cbSchristos extern YYSTYPE	yylval;
3735f471cbSchristos extern int	infunc;
3835f471cbSchristos 
3935f471cbSchristos int	lineno	= 1;
4035f471cbSchristos int	bracecnt = 0;
4135f471cbSchristos int	brackcnt  = 0;
4235f471cbSchristos int	parencnt = 0;
4335f471cbSchristos 
4435f471cbSchristos typedef struct Keyword {
4535f471cbSchristos 	const char *word;
4635f471cbSchristos 	int	sub;
4735f471cbSchristos 	int	type;
4835f471cbSchristos } Keyword;
4935f471cbSchristos 
505642d004Schristos const Keyword keywords[] = {	/* keep sorted: binary searched */
5135f471cbSchristos 	{ "BEGIN",	XBEGIN,		XBEGIN },
5235f471cbSchristos 	{ "END",	XEND,		XEND },
5335f471cbSchristos 	{ "NF",		VARNF,		VARNF },
548eaba782Schristos 	{ "and",	FAND,		BLTIN },
5535f471cbSchristos 	{ "atan2",	FATAN,		BLTIN },
5635f471cbSchristos 	{ "break",	BREAK,		BREAK },
5735f471cbSchristos 	{ "close",	CLOSE,		CLOSE },
588eaba782Schristos 	{ "compl",	FCOMPL,		BLTIN },
5935f471cbSchristos 	{ "continue",	CONTINUE,	CONTINUE },
6035f471cbSchristos 	{ "cos",	FCOS,		BLTIN },
6135f471cbSchristos 	{ "delete",	DELETE,		DELETE },
6235f471cbSchristos 	{ "do",		DO,		DO },
6335f471cbSchristos 	{ "else",	ELSE,		ELSE },
6435f471cbSchristos 	{ "exit",	EXIT,		EXIT },
6535f471cbSchristos 	{ "exp",	FEXP,		BLTIN },
6635f471cbSchristos 	{ "fflush",	FFLUSH,		BLTIN },
6735f471cbSchristos 	{ "for",	FOR,		FOR },
6835f471cbSchristos 	{ "func",	FUNC,		FUNC },
6935f471cbSchristos 	{ "function",	FUNC,		FUNC },
705642d004Schristos 	{ "gensub",	GENSUB,		GENSUB },
7135f471cbSchristos 	{ "getline",	GETLINE,	GETLINE },
7235f471cbSchristos 	{ "gsub",	GSUB,		GSUB },
7335f471cbSchristos 	{ "if",		IF,		IF },
7435f471cbSchristos 	{ "in",		IN,		IN },
7535f471cbSchristos 	{ "index",	INDEX,		INDEX },
7635f471cbSchristos 	{ "int",	FINT,		BLTIN },
7735f471cbSchristos 	{ "length",	FLENGTH,	BLTIN },
7835f471cbSchristos 	{ "log",	FLOG,		BLTIN },
798eaba782Schristos 	{ "lshift",	FLSHIFT,	BLTIN },
8035f471cbSchristos 	{ "match",	MATCHFCN,	MATCHFCN },
8135f471cbSchristos 	{ "next",	NEXT,		NEXT },
8235f471cbSchristos 	{ "nextfile",	NEXTFILE,	NEXTFILE },
838eaba782Schristos 	{ "or",		FFOR,		BLTIN },
8435f471cbSchristos 	{ "print",	PRINT,		PRINT },
8535f471cbSchristos 	{ "printf",	PRINTF,		PRINTF },
8635f471cbSchristos 	{ "rand",	FRAND,		BLTIN },
8735f471cbSchristos 	{ "return",	RETURN,		RETURN },
888eaba782Schristos 	{ "rshift",	FRSHIFT,	BLTIN },
8935f471cbSchristos 	{ "sin",	FSIN,		BLTIN },
9035f471cbSchristos 	{ "split",	SPLIT,		SPLIT },
9135f471cbSchristos 	{ "sprintf",	SPRINTF,	SPRINTF },
9235f471cbSchristos 	{ "sqrt",	FSQRT,		BLTIN },
9335f471cbSchristos 	{ "srand",	FSRAND,		BLTIN },
945642d004Schristos 	{ "strftime",	FSTRFTIME,	BLTIN },
9535f471cbSchristos 	{ "sub",	SUB,		SUB },
9635f471cbSchristos 	{ "substr",	SUBSTR,		SUBSTR },
9735f471cbSchristos 	{ "system",	FSYSTEM,	BLTIN },
985642d004Schristos 	{ "systime",	FSYSTIME,	BLTIN },
9935f471cbSchristos 	{ "tolower",	FTOLOWER,	BLTIN },
10035f471cbSchristos 	{ "toupper",	FTOUPPER,	BLTIN },
10135f471cbSchristos 	{ "while",	WHILE,		WHILE },
1028eaba782Schristos 	{ "xor",	FXOR,		BLTIN },
10335f471cbSchristos };
10435f471cbSchristos 
10535f471cbSchristos #define	RET(x)	{ if(dbg)printf("lex %s\n", tokname(x)); return(x); }
10635f471cbSchristos 
peek(void)1078eaba782Schristos static int peek(void)
10835f471cbSchristos {
10935f471cbSchristos 	int c = input();
11035f471cbSchristos 	unput(c);
11135f471cbSchristos 	return c;
11235f471cbSchristos }
11335f471cbSchristos 
gettok(char ** pbuf,int * psz)1148eaba782Schristos static int gettok(char **pbuf, int *psz)	/* get next input token */
11535f471cbSchristos {
11635f471cbSchristos 	int c, retc;
1178eaba782Schristos 	char *buf = *pbuf;
11835f471cbSchristos 	int sz = *psz;
1198eaba782Schristos 	char *bp = buf;
12035f471cbSchristos 
12135f471cbSchristos 	c = input();
12235f471cbSchristos 	if (c == 0)
12335f471cbSchristos 		return 0;
12435f471cbSchristos 	buf[0] = c;
12535f471cbSchristos 	buf[1] = 0;
12635f471cbSchristos 	if (!isalnum(c) && c != '.' && c != '_')
12735f471cbSchristos 		return c;
12835f471cbSchristos 
12935f471cbSchristos 	*bp++ = c;
13035f471cbSchristos 	if (isalpha(c) || c == '_') {	/* it's a varname */
13135f471cbSchristos 		for ( ; (c = input()) != 0; ) {
13235f471cbSchristos 			if (bp-buf >= sz)
13335f471cbSchristos 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
13435f471cbSchristos 					FATAL( "out of space for name %.10s...", buf );
13535f471cbSchristos 			if (isalnum(c) || c == '_')
13635f471cbSchristos 				*bp++ = c;
13735f471cbSchristos 			else {
13835f471cbSchristos 				*bp = 0;
13935f471cbSchristos 				unput(c);
14035f471cbSchristos 				break;
14135f471cbSchristos 			}
14235f471cbSchristos 		}
14335f471cbSchristos 		*bp = 0;
14435f471cbSchristos 		retc = 'a';	/* alphanumeric */
14535f471cbSchristos 	} else {	/* maybe it's a number, but could be . */
14635f471cbSchristos 		char *rem;
14735f471cbSchristos 		/* read input until can't be a number */
14835f471cbSchristos 		for ( ; (c = input()) != 0; ) {
14935f471cbSchristos 			if (bp-buf >= sz)
15035f471cbSchristos 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
15135f471cbSchristos 					FATAL( "out of space for number %.10s...", buf );
15235f471cbSchristos 			if (isdigit(c) || c == 'e' || c == 'E'
15335f471cbSchristos 			  || c == '.' || c == '+' || c == '-')
15435f471cbSchristos 				*bp++ = c;
15535f471cbSchristos 			else {
15635f471cbSchristos 				unput(c);
15735f471cbSchristos 				break;
15835f471cbSchristos 			}
15935f471cbSchristos 		}
16035f471cbSchristos 		*bp = 0;
16135f471cbSchristos 		strtod(buf, &rem);	/* parse the number */
1628eaba782Schristos 		if (rem == buf) {	/* it wasn't a valid number at all */
16335f471cbSchristos 			buf[1] = 0;	/* return one character as token */
16435f471cbSchristos 			retc = buf[0];	/* character is its own type */
16535f471cbSchristos 			unputstr(rem+1); /* put rest back for later */
16635f471cbSchristos 		} else {	/* some prefix was a number */
16735f471cbSchristos 			unputstr(rem);	/* put rest back for later */
16835f471cbSchristos 			rem[0] = 0;	/* truncate buf after number part */
16935f471cbSchristos 			retc = '0';	/* type is number */
17035f471cbSchristos 		}
17135f471cbSchristos 	}
17235f471cbSchristos 	*pbuf = buf;
17335f471cbSchristos 	*psz = sz;
17435f471cbSchristos 	return retc;
17535f471cbSchristos }
17635f471cbSchristos 
17735f471cbSchristos int	word(char *);
17835f471cbSchristos int	string(void);
17935f471cbSchristos int	regexpr(void);
1808eaba782Schristos bool	sc	= false;	/* true => return a } right now */
1818eaba782Schristos bool	reg	= false;	/* true => return a REGEXPR now */
18235f471cbSchristos 
yylex(void)18335f471cbSchristos int yylex(void)
18435f471cbSchristos {
18535f471cbSchristos 	int c;
1868eaba782Schristos 	static char *buf = NULL;
18735f471cbSchristos 	static int bufsize = 5; /* BUG: setting this small causes core dump! */
18835f471cbSchristos 
1898eaba782Schristos 	if (buf == NULL && (buf = malloc(bufsize)) == NULL)
19035f471cbSchristos 		FATAL( "out of space in yylex" );
19135f471cbSchristos 	if (sc) {
1928eaba782Schristos 		sc = false;
19335f471cbSchristos 		RET('}');
19435f471cbSchristos 	}
19535f471cbSchristos 	if (reg) {
1968eaba782Schristos 		reg = false;
19735f471cbSchristos 		return regexpr();
19835f471cbSchristos 	}
19935f471cbSchristos 	for (;;) {
20035f471cbSchristos 		c = gettok(&buf, &bufsize);
20135f471cbSchristos 		if (c == 0)
20235f471cbSchristos 			return 0;
20335f471cbSchristos 		if (isalpha(c) || c == '_')
20435f471cbSchristos 			return word(buf);
20535f471cbSchristos 		if (isdigit(c)) {
2068eaba782Schristos 			char *cp = tostring(buf);
2078eaba782Schristos 			yylval.cp = setsymtab(buf, cp, atof(buf), CON|NUM, symtab);
2088eaba782Schristos 			free(cp);
20935f471cbSchristos 			/* should this also have STR set? */
21035f471cbSchristos 			RET(NUMBER);
21135f471cbSchristos 		}
21235f471cbSchristos 
21335f471cbSchristos 		yylval.i = c;
21435f471cbSchristos 		switch (c) {
21535f471cbSchristos 		case '\n':	/* {EOL} */
2168eaba782Schristos 			lineno++;
21735f471cbSchristos 			RET(NL);
21835f471cbSchristos 		case '\r':	/* assume \n is coming */
21935f471cbSchristos 		case ' ':	/* {WS}+ */
22035f471cbSchristos 		case '\t':
22135f471cbSchristos 			break;
22235f471cbSchristos 		case '#':	/* #.* strip comments */
22335f471cbSchristos 			while ((c = input()) != '\n' && c != 0)
22435f471cbSchristos 				;
22535f471cbSchristos 			unput(c);
2268eaba782Schristos 			/*
2278eaba782Schristos 			 * Next line is a hack, itcompensates for
2288eaba782Schristos 			 * unput's treatment of \n.
2298eaba782Schristos 			 */
2308eaba782Schristos 			lineno++;
23135f471cbSchristos 			break;
23235f471cbSchristos 		case ';':
23335f471cbSchristos 			RET(';');
23435f471cbSchristos 		case '\\':
23535f471cbSchristos 			if (peek() == '\n') {
23635f471cbSchristos 				input();
2378eaba782Schristos 				lineno++;
23835f471cbSchristos 			} else if (peek() == '\r') {
23935f471cbSchristos 				input(); input();	/* \n */
24035f471cbSchristos 				lineno++;
24135f471cbSchristos 			} else {
24235f471cbSchristos 				RET(c);
24335f471cbSchristos 			}
24435f471cbSchristos 			break;
24535f471cbSchristos 		case '&':
24635f471cbSchristos 			if (peek() == '&') {
24735f471cbSchristos 				input(); RET(AND);
24835f471cbSchristos 			} else
24935f471cbSchristos 				RET('&');
25035f471cbSchristos 		case '|':
25135f471cbSchristos 			if (peek() == '|') {
25235f471cbSchristos 				input(); RET(BOR);
25335f471cbSchristos 			} else
25435f471cbSchristos 				RET('|');
25535f471cbSchristos 		case '!':
25635f471cbSchristos 			if (peek() == '=') {
25735f471cbSchristos 				input(); yylval.i = NE; RET(NE);
25835f471cbSchristos 			} else if (peek() == '~') {
25935f471cbSchristos 				input(); yylval.i = NOTMATCH; RET(MATCHOP);
26035f471cbSchristos 			} else
26135f471cbSchristos 				RET(NOT);
26235f471cbSchristos 		case '~':
26335f471cbSchristos 			yylval.i = MATCH;
26435f471cbSchristos 			RET(MATCHOP);
26535f471cbSchristos 		case '<':
26635f471cbSchristos 			if (peek() == '=') {
26735f471cbSchristos 				input(); yylval.i = LE; RET(LE);
26835f471cbSchristos 			} else {
26935f471cbSchristos 				yylval.i = LT; RET(LT);
27035f471cbSchristos 			}
27135f471cbSchristos 		case '=':
27235f471cbSchristos 			if (peek() == '=') {
27335f471cbSchristos 				input(); yylval.i = EQ; RET(EQ);
27435f471cbSchristos 			} else {
27535f471cbSchristos 				yylval.i = ASSIGN; RET(ASGNOP);
27635f471cbSchristos 			}
27735f471cbSchristos 		case '>':
27835f471cbSchristos 			if (peek() == '=') {
27935f471cbSchristos 				input(); yylval.i = GE; RET(GE);
28035f471cbSchristos 			} else if (peek() == '>') {
28135f471cbSchristos 				input(); yylval.i = APPEND; RET(APPEND);
28235f471cbSchristos 			} else {
28335f471cbSchristos 				yylval.i = GT; RET(GT);
28435f471cbSchristos 			}
28535f471cbSchristos 		case '+':
28635f471cbSchristos 			if (peek() == '+') {
28735f471cbSchristos 				input(); yylval.i = INCR; RET(INCR);
28835f471cbSchristos 			} else if (peek() == '=') {
28935f471cbSchristos 				input(); yylval.i = ADDEQ; RET(ASGNOP);
29035f471cbSchristos 			} else
29135f471cbSchristos 				RET('+');
29235f471cbSchristos 		case '-':
29335f471cbSchristos 			if (peek() == '-') {
29435f471cbSchristos 				input(); yylval.i = DECR; RET(DECR);
29535f471cbSchristos 			} else if (peek() == '=') {
29635f471cbSchristos 				input(); yylval.i = SUBEQ; RET(ASGNOP);
29735f471cbSchristos 			} else
29835f471cbSchristos 				RET('-');
29935f471cbSchristos 		case '*':
30035f471cbSchristos 			if (peek() == '=') {	/* *= */
30135f471cbSchristos 				input(); yylval.i = MULTEQ; RET(ASGNOP);
30235f471cbSchristos 			} else if (peek() == '*') {	/* ** or **= */
30335f471cbSchristos 				input();	/* eat 2nd * */
30435f471cbSchristos 				if (peek() == '=') {
30535f471cbSchristos 					input(); yylval.i = POWEQ; RET(ASGNOP);
30635f471cbSchristos 				} else {
30735f471cbSchristos 					RET(POWER);
30835f471cbSchristos 				}
30935f471cbSchristos 			} else
31035f471cbSchristos 				RET('*');
31135f471cbSchristos 		case '/':
31235f471cbSchristos 			RET('/');
31335f471cbSchristos 		case '%':
31435f471cbSchristos 			if (peek() == '=') {
31535f471cbSchristos 				input(); yylval.i = MODEQ; RET(ASGNOP);
31635f471cbSchristos 			} else
31735f471cbSchristos 				RET('%');
31835f471cbSchristos 		case '^':
31935f471cbSchristos 			if (peek() == '=') {
32035f471cbSchristos 				input(); yylval.i = POWEQ; RET(ASGNOP);
32135f471cbSchristos 			} else
32235f471cbSchristos 				RET(POWER);
32335f471cbSchristos 
32435f471cbSchristos 		case '$':
32535f471cbSchristos 			/* BUG: awkward, if not wrong */
32635f471cbSchristos 			c = gettok(&buf, &bufsize);
32735f471cbSchristos 			if (isalpha(c)) {
32835f471cbSchristos 				if (strcmp(buf, "NF") == 0) {	/* very special */
32935f471cbSchristos 					unputstr("(NF)");
33035f471cbSchristos 					RET(INDIRECT);
33135f471cbSchristos 				}
33235f471cbSchristos 				c = peek();
33335f471cbSchristos 				if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
33435f471cbSchristos 					unputstr(buf);
33535f471cbSchristos 					RET(INDIRECT);
33635f471cbSchristos 				}
33735f471cbSchristos 				yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
33835f471cbSchristos 				RET(IVAR);
33935f471cbSchristos 			} else if (c == 0) {	/*  */
34035f471cbSchristos 				SYNTAX( "unexpected end of input after $" );
34135f471cbSchristos 				RET(';');
34235f471cbSchristos 			} else {
34335f471cbSchristos 				unputstr(buf);
34435f471cbSchristos 				RET(INDIRECT);
34535f471cbSchristos 			}
34635f471cbSchristos 
34735f471cbSchristos 		case '}':
34835f471cbSchristos 			if (--bracecnt < 0)
34935f471cbSchristos 				SYNTAX( "extra }" );
3508eaba782Schristos 			sc = true;
35135f471cbSchristos 			RET(';');
35235f471cbSchristos 		case ']':
35335f471cbSchristos 			if (--brackcnt < 0)
35435f471cbSchristos 				SYNTAX( "extra ]" );
35535f471cbSchristos 			RET(']');
35635f471cbSchristos 		case ')':
35735f471cbSchristos 			if (--parencnt < 0)
35835f471cbSchristos 				SYNTAX( "extra )" );
35935f471cbSchristos 			RET(')');
36035f471cbSchristos 		case '{':
36135f471cbSchristos 			bracecnt++;
36235f471cbSchristos 			RET('{');
36335f471cbSchristos 		case '[':
36435f471cbSchristos 			brackcnt++;
36535f471cbSchristos 			RET('[');
36635f471cbSchristos 		case '(':
36735f471cbSchristos 			parencnt++;
36835f471cbSchristos 			RET('(');
36935f471cbSchristos 
37035f471cbSchristos 		case '"':
37135f471cbSchristos 			return string();	/* BUG: should be like tran.c ? */
37235f471cbSchristos 
37335f471cbSchristos 		default:
37435f471cbSchristos 			RET(c);
37535f471cbSchristos 		}
37635f471cbSchristos 	}
37735f471cbSchristos }
37835f471cbSchristos 
string(void)37935f471cbSchristos int string(void)
38035f471cbSchristos {
38135f471cbSchristos 	int c, n;
3828eaba782Schristos 	char *s, *bp;
3838eaba782Schristos 	static char *buf = NULL;
38435f471cbSchristos 	static int bufsz = 500;
38535f471cbSchristos 
3868eaba782Schristos 	if (buf == NULL && (buf = malloc(bufsz)) == NULL)
38735f471cbSchristos 		FATAL("out of space for strings");
38835f471cbSchristos 	for (bp = buf; (c = input()) != '"'; ) {
38935f471cbSchristos 		if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
39035f471cbSchristos 			FATAL("out of space for string %.10s...", buf);
39135f471cbSchristos 		switch (c) {
39235f471cbSchristos 		case '\n':
39335f471cbSchristos 		case '\r':
39435f471cbSchristos 		case 0:
3958eaba782Schristos 			*bp = '\0';
39635f471cbSchristos 			SYNTAX( "non-terminated string %.10s...", buf );
39735f471cbSchristos 			if (c == 0)	/* hopeless */
39835f471cbSchristos 				FATAL( "giving up" );
3998eaba782Schristos 			lineno++;
40035f471cbSchristos 			break;
40135f471cbSchristos 		case '\\':
40235f471cbSchristos 			c = input();
40335f471cbSchristos 			switch (c) {
404*e66db18eSchristos 			case '\n': break;
40535f471cbSchristos 			case '"': *bp++ = '"'; break;
40635f471cbSchristos 			case 'n': *bp++ = '\n'; break;
40735f471cbSchristos 			case 't': *bp++ = '\t'; break;
40835f471cbSchristos 			case 'f': *bp++ = '\f'; break;
40935f471cbSchristos 			case 'r': *bp++ = '\r'; break;
41035f471cbSchristos 			case 'b': *bp++ = '\b'; break;
41135f471cbSchristos 			case 'v': *bp++ = '\v'; break;
4128eaba782Schristos 			case 'a': *bp++ = '\a'; break;
41335f471cbSchristos 			case '\\': *bp++ = '\\'; break;
41435f471cbSchristos 
41535f471cbSchristos 			case '0': case '1': case '2': /* octal: \d \dd \ddd */
41635f471cbSchristos 			case '3': case '4': case '5': case '6': case '7':
41735f471cbSchristos 				n = c - '0';
41835f471cbSchristos 				if ((c = peek()) >= '0' && c < '8') {
41935f471cbSchristos 					n = 8 * n + input() - '0';
42035f471cbSchristos 					if ((c = peek()) >= '0' && c < '8')
42135f471cbSchristos 						n = 8 * n + input() - '0';
42235f471cbSchristos 				}
42335f471cbSchristos 				*bp++ = n;
42435f471cbSchristos 				break;
42535f471cbSchristos 
42635f471cbSchristos 			case 'x':	/* hex  \x0-9a-fA-F + */
42735f471cbSchristos 			    {	char xbuf[100], *px;
42835f471cbSchristos 				for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
42935f471cbSchristos 					if (isdigit(c)
43035f471cbSchristos 					 || (c >= 'a' && c <= 'f')
43135f471cbSchristos 					 || (c >= 'A' && c <= 'F'))
43235f471cbSchristos 						*px++ = c;
43335f471cbSchristos 					else
43435f471cbSchristos 						break;
43535f471cbSchristos 				}
43635f471cbSchristos 				*px = 0;
43735f471cbSchristos 				unput(c);
4388eaba782Schristos 	  			sscanf(xbuf, "%x", (unsigned int *) &n);
43935f471cbSchristos 				*bp++ = n;
44035f471cbSchristos 				break;
44135f471cbSchristos 			    }
44235f471cbSchristos 
44335f471cbSchristos 			default:
44435f471cbSchristos 				*bp++ = c;
44535f471cbSchristos 				break;
44635f471cbSchristos 			}
44735f471cbSchristos 			break;
44835f471cbSchristos 		default:
44935f471cbSchristos 			*bp++ = c;
45035f471cbSchristos 			break;
45135f471cbSchristos 		}
45235f471cbSchristos 	}
45335f471cbSchristos 	*bp = 0;
45435f471cbSchristos 	s = tostring(buf);
4558eaba782Schristos 	*bp++ = ' '; *bp++ = '\0';
45635f471cbSchristos 	yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
4578eaba782Schristos 	free(s);
45835f471cbSchristos 	RET(STRING);
45935f471cbSchristos }
46035f471cbSchristos 
46135f471cbSchristos 
binsearch(char * w,const Keyword * kp,int n)4628eaba782Schristos static int binsearch(char *w, const Keyword *kp, int n)
46335f471cbSchristos {
46435f471cbSchristos 	int cond, low, mid, high;
46535f471cbSchristos 
46635f471cbSchristos 	low = 0;
46735f471cbSchristos 	high = n - 1;
46835f471cbSchristos 	while (low <= high) {
46935f471cbSchristos 		mid = (low + high) / 2;
47035f471cbSchristos 		if ((cond = strcmp(w, kp[mid].word)) < 0)
47135f471cbSchristos 			high = mid - 1;
47235f471cbSchristos 		else if (cond > 0)
47335f471cbSchristos 			low = mid + 1;
47435f471cbSchristos 		else
47535f471cbSchristos 			return mid;
47635f471cbSchristos 	}
47735f471cbSchristos 	return -1;
47835f471cbSchristos }
47935f471cbSchristos 
word(char * w)48035f471cbSchristos int word(char *w)
48135f471cbSchristos {
4825642d004Schristos 	const Keyword *kp;
48335f471cbSchristos 	int c, n;
48435f471cbSchristos 
48535f471cbSchristos 	n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
48635f471cbSchristos 	if (n != -1) {	/* found in table */
48708f0f4e6Skamil 		kp = keywords + n;
48835f471cbSchristos 		yylval.i = kp->sub;
48935f471cbSchristos 		switch (kp->type) {	/* special handling */
49035f471cbSchristos 		case BLTIN:
49135f471cbSchristos 			if (kp->sub == FSYSTEM && safe)
49235f471cbSchristos 				SYNTAX( "system is unsafe" );
49335f471cbSchristos 			RET(kp->type);
49435f471cbSchristos 		case FUNC:
49535f471cbSchristos 			if (infunc)
49635f471cbSchristos 				SYNTAX( "illegal nested function" );
49735f471cbSchristos 			RET(kp->type);
49835f471cbSchristos 		case RETURN:
49935f471cbSchristos 			if (!infunc)
50035f471cbSchristos 				SYNTAX( "return not in function" );
50135f471cbSchristos 			RET(kp->type);
50235f471cbSchristos 		case VARNF:
50335f471cbSchristos 			yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
50435f471cbSchristos 			RET(VARNF);
50535f471cbSchristos 		default:
50635f471cbSchristos 			RET(kp->type);
50735f471cbSchristos 		}
50835f471cbSchristos 	}
50935f471cbSchristos 	c = peek();	/* look for '(' */
51035f471cbSchristos 	if (c != '(' && infunc && (n=isarg(w)) >= 0) {
51135f471cbSchristos 		yylval.i = n;
51235f471cbSchristos 		RET(ARG);
51335f471cbSchristos 	} else {
51435f471cbSchristos 		yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
51535f471cbSchristos 		if (c == '(') {
51635f471cbSchristos 			RET(CALL);
51735f471cbSchristos 		} else {
51835f471cbSchristos 			RET(VAR);
51935f471cbSchristos 		}
52035f471cbSchristos 	}
52135f471cbSchristos }
52235f471cbSchristos 
startreg(void)52335f471cbSchristos void startreg(void)	/* next call to yylex will return a regular expression */
52435f471cbSchristos {
5258eaba782Schristos 	reg = true;
52635f471cbSchristos }
52735f471cbSchristos 
regexpr(void)52835f471cbSchristos int regexpr(void)
52935f471cbSchristos {
53035f471cbSchristos 	int c;
5318eaba782Schristos 	static char *buf = NULL;
53235f471cbSchristos 	static int bufsz = 500;
5338eaba782Schristos 	char *bp;
53435f471cbSchristos 
5358eaba782Schristos 	if (buf == NULL && (buf = malloc(bufsz)) == NULL)
53635f471cbSchristos 		FATAL("out of space for rex expr");
53735f471cbSchristos 	bp = buf;
53835f471cbSchristos 	for ( ; (c = input()) != '/' && c != 0; ) {
53935f471cbSchristos 		if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
54035f471cbSchristos 			FATAL("out of space for reg expr %.10s...", buf);
54135f471cbSchristos 		if (c == '\n') {
5428eaba782Schristos 			*bp = '\0';
54335f471cbSchristos 			SYNTAX( "newline in regular expression %.10s...", buf );
54435f471cbSchristos 			unput('\n');
54535f471cbSchristos 			break;
54635f471cbSchristos 		} else if (c == '\\') {
54735f471cbSchristos 			*bp++ = '\\';
54835f471cbSchristos 			*bp++ = input();
54935f471cbSchristos 		} else {
55035f471cbSchristos 			*bp++ = c;
55135f471cbSchristos 		}
55235f471cbSchristos 	}
55335f471cbSchristos 	*bp = 0;
55435f471cbSchristos 	if (c == 0)
55535f471cbSchristos 		SYNTAX("non-terminated regular expression %.10s...", buf);
55635f471cbSchristos 	yylval.s = tostring(buf);
55735f471cbSchristos 	unput('/');
55835f471cbSchristos 	RET(REGEXPR);
55935f471cbSchristos }
56035f471cbSchristos 
56135f471cbSchristos /* low-level lexical stuff, sort of inherited from lex */
56235f471cbSchristos 
56335f471cbSchristos char	ebuf[300];
56435f471cbSchristos char	*ep = ebuf;
56535f471cbSchristos char	yysbuf[100];	/* pushback buffer */
56635f471cbSchristos char	*yysptr = yysbuf;
5678eaba782Schristos FILE	*yyin = NULL;
56835f471cbSchristos 
input(void)56935f471cbSchristos int input(void)	/* get next lexical input character */
57035f471cbSchristos {
57135f471cbSchristos 	int c;
57235f471cbSchristos 	extern char *lexprog;
57335f471cbSchristos 
57435f471cbSchristos 	if (yysptr > yysbuf)
57535f471cbSchristos 		c = (uschar)*--yysptr;
57635f471cbSchristos 	else if (lexprog != NULL) {	/* awk '...' */
57735f471cbSchristos 		if ((c = (uschar)*lexprog) != 0)
57835f471cbSchristos 			lexprog++;
57935f471cbSchristos 	} else				/* awk -f ... */
58035f471cbSchristos 		c = pgetc();
5818eaba782Schristos 	if (c == EOF)
58235f471cbSchristos 		c = 0;
58335f471cbSchristos 	if (ep >= ebuf + sizeof ebuf)
58435f471cbSchristos 		ep = ebuf;
5858eaba782Schristos 	*ep = c;
5868eaba782Schristos 	if (c != 0) {
5878eaba782Schristos 		ep++;
5888eaba782Schristos 	}
5898eaba782Schristos 	return (c);
59035f471cbSchristos }
59135f471cbSchristos 
unput(int c)59235f471cbSchristos void unput(int c)	/* put lexical character back on input */
59335f471cbSchristos {
59435f471cbSchristos 	if (c == '\n')
59535f471cbSchristos 		lineno--;
59635f471cbSchristos 	if (yysptr >= yysbuf + sizeof(yysbuf))
59735f471cbSchristos 		FATAL("pushed back too much: %.20s...", yysbuf);
59835f471cbSchristos 	*yysptr++ = c;
59935f471cbSchristos 	if (--ep < ebuf)
60035f471cbSchristos 		ep = ebuf + sizeof(ebuf) - 1;
60135f471cbSchristos }
60235f471cbSchristos 
unputstr(const char * s)60335f471cbSchristos void unputstr(const char *s)	/* put a string back on input */
60435f471cbSchristos {
60535f471cbSchristos 	int i;
60635f471cbSchristos 
60735f471cbSchristos 	for (i = strlen(s)-1; i >= 0; i--)
60835f471cbSchristos 		unput(s[i]);
60935f471cbSchristos }
610