xref: /plan9-contrib/sys/src/cmd/awk/lex.c (revision a2c41696452f8a895ad2951a6355034fbc3034ed)
17dd7cddfSDavid du Colombier /****************************************************************
27dd7cddfSDavid du Colombier Copyright (C) Lucent Technologies 1997
37dd7cddfSDavid du Colombier All Rights Reserved
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier Permission to use, copy, modify, and distribute this software and
67dd7cddfSDavid du Colombier its documentation for any purpose and without fee is hereby
77dd7cddfSDavid du Colombier granted, provided that the above copyright notice appear in all
87dd7cddfSDavid du Colombier copies and that both that the copyright notice and this
97dd7cddfSDavid du Colombier permission notice and warranty disclaimer appear in supporting
107dd7cddfSDavid du Colombier documentation, and that the name Lucent Technologies or any of
117dd7cddfSDavid du Colombier its entities not be used in advertising or publicity pertaining
127dd7cddfSDavid du Colombier to distribution of the software without specific, written prior
137dd7cddfSDavid du Colombier permission.
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
167dd7cddfSDavid du Colombier INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
177dd7cddfSDavid du Colombier IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
187dd7cddfSDavid du Colombier SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
197dd7cddfSDavid du Colombier WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
207dd7cddfSDavid du Colombier IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
217dd7cddfSDavid du Colombier ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
227dd7cddfSDavid du Colombier THIS SOFTWARE.
237dd7cddfSDavid du Colombier ****************************************************************/
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier #include <stdio.h>
267dd7cddfSDavid du Colombier #include <stdlib.h>
277dd7cddfSDavid du Colombier #include <string.h>
287dd7cddfSDavid du Colombier #include <ctype.h>
297dd7cddfSDavid du Colombier #include "awk.h"
307dd7cddfSDavid du Colombier #include "y.tab.h"
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier extern YYSTYPE	yylval;
337dd7cddfSDavid du Colombier extern int	infunc;
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier int	lineno	= 1;
367dd7cddfSDavid du Colombier int	bracecnt = 0;
377dd7cddfSDavid du Colombier int	brackcnt  = 0;
387dd7cddfSDavid du Colombier int	parencnt = 0;
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier typedef struct Keyword {
41*a2c41696SDavid du Colombier 	const char *word;
427dd7cddfSDavid du Colombier 	int	sub;
437dd7cddfSDavid du Colombier 	int	type;
447dd7cddfSDavid du Colombier } Keyword;
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier Keyword keywords[] ={	/* keep sorted: binary searched */
477dd7cddfSDavid du Colombier 	{ "BEGIN",	XBEGIN,		XBEGIN },
487dd7cddfSDavid du Colombier 	{ "END",	XEND,		XEND },
497dd7cddfSDavid du Colombier 	{ "NF",		VARNF,		VARNF },
507dd7cddfSDavid du Colombier 	{ "atan2",	FATAN,		BLTIN },
517dd7cddfSDavid du Colombier 	{ "break",	BREAK,		BREAK },
527dd7cddfSDavid du Colombier 	{ "close",	CLOSE,		CLOSE },
537dd7cddfSDavid du Colombier 	{ "continue",	CONTINUE,	CONTINUE },
547dd7cddfSDavid du Colombier 	{ "cos",	FCOS,		BLTIN },
557dd7cddfSDavid du Colombier 	{ "delete",	DELETE,		DELETE },
567dd7cddfSDavid du Colombier 	{ "do",		DO,		DO },
577dd7cddfSDavid du Colombier 	{ "else",	ELSE,		ELSE },
587dd7cddfSDavid du Colombier 	{ "exit",	EXIT,		EXIT },
597dd7cddfSDavid du Colombier 	{ "exp",	FEXP,		BLTIN },
607dd7cddfSDavid du Colombier 	{ "fflush",	FFLUSH,		BLTIN },
617dd7cddfSDavid du Colombier 	{ "for",	FOR,		FOR },
627dd7cddfSDavid du Colombier 	{ "func",	FUNC,		FUNC },
637dd7cddfSDavid du Colombier 	{ "function",	FUNC,		FUNC },
647dd7cddfSDavid du Colombier 	{ "getline",	GETLINE,	GETLINE },
657dd7cddfSDavid du Colombier 	{ "gsub",	GSUB,		GSUB },
667dd7cddfSDavid du Colombier 	{ "if",		IF,		IF },
677dd7cddfSDavid du Colombier 	{ "in",		IN,		IN },
687dd7cddfSDavid du Colombier 	{ "index",	INDEX,		INDEX },
697dd7cddfSDavid du Colombier 	{ "int",	FINT,		BLTIN },
707dd7cddfSDavid du Colombier 	{ "length",	FLENGTH,	BLTIN },
717dd7cddfSDavid du Colombier 	{ "log",	FLOG,		BLTIN },
727dd7cddfSDavid du Colombier 	{ "match",	MATCHFCN,	MATCHFCN },
737dd7cddfSDavid du Colombier 	{ "next",	NEXT,		NEXT },
747dd7cddfSDavid du Colombier 	{ "nextfile",	NEXTFILE,	NEXTFILE },
757dd7cddfSDavid du Colombier 	{ "print",	PRINT,		PRINT },
767dd7cddfSDavid du Colombier 	{ "printf",	PRINTF,		PRINTF },
777dd7cddfSDavid du Colombier 	{ "rand",	FRAND,		BLTIN },
787dd7cddfSDavid du Colombier 	{ "return",	RETURN,		RETURN },
797dd7cddfSDavid du Colombier 	{ "sin",	FSIN,		BLTIN },
807dd7cddfSDavid du Colombier 	{ "split",	SPLIT,		SPLIT },
817dd7cddfSDavid du Colombier 	{ "sprintf",	SPRINTF,	SPRINTF },
827dd7cddfSDavid du Colombier 	{ "sqrt",	FSQRT,		BLTIN },
837dd7cddfSDavid du Colombier 	{ "srand",	FSRAND,		BLTIN },
847dd7cddfSDavid du Colombier 	{ "sub",	SUB,		SUB },
857dd7cddfSDavid du Colombier 	{ "substr",	SUBSTR,		SUBSTR },
867dd7cddfSDavid du Colombier 	{ "system",	FSYSTEM,	BLTIN },
877dd7cddfSDavid du Colombier 	{ "tolower",	FTOLOWER,	BLTIN },
887dd7cddfSDavid du Colombier 	{ "toupper",	FTOUPPER,	BLTIN },
897dd7cddfSDavid du Colombier 	{ "utf",	FUTF,		BLTIN },
9076f6a3b8SDavid du Colombier 	{ "while",	WHILE,		WHILE },
917dd7cddfSDavid du Colombier };
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier #define	RET(x)	{ if(dbg)printf("lex %s\n", tokname(x)); return(x); }
947dd7cddfSDavid du Colombier 
peek(void)957dd7cddfSDavid du Colombier int peek(void)
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier 	int c = input();
987dd7cddfSDavid du Colombier 	unput(c);
997dd7cddfSDavid du Colombier 	return c;
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier 
gettok(char ** pbuf,int * psz)1027dd7cddfSDavid du Colombier int gettok(char **pbuf, int *psz)	/* get next input token */
1037dd7cddfSDavid du Colombier {
104*a2c41696SDavid du Colombier 	int c, retc;
1057dd7cddfSDavid du Colombier 	char *buf = *pbuf;
1067dd7cddfSDavid du Colombier 	int sz = *psz;
1077dd7cddfSDavid du Colombier 	char *bp = buf;
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	c = input();
1107dd7cddfSDavid du Colombier 	if (c == 0)
1117dd7cddfSDavid du Colombier 		return 0;
1127dd7cddfSDavid du Colombier 	buf[0] = c;
1137dd7cddfSDavid du Colombier 	buf[1] = 0;
1147dd7cddfSDavid du Colombier 	if (!isalnum(c) && c != '.' && c != '_')
1157dd7cddfSDavid du Colombier 		return c;
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier 	*bp++ = c;
1187dd7cddfSDavid du Colombier 	if (isalpha(c) || c == '_') {	/* it's a varname */
1197dd7cddfSDavid du Colombier 		for ( ; (c = input()) != 0; ) {
1207dd7cddfSDavid du Colombier 			if (bp-buf >= sz)
121*a2c41696SDavid du Colombier 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
1227dd7cddfSDavid du Colombier 					FATAL( "out of space for name %.10s...", buf );
1237dd7cddfSDavid du Colombier 			if (isalnum(c) || c == '_')
1247dd7cddfSDavid du Colombier 				*bp++ = c;
1257dd7cddfSDavid du Colombier 			else {
1267dd7cddfSDavid du Colombier 				*bp = 0;
1277dd7cddfSDavid du Colombier 				unput(c);
1287dd7cddfSDavid du Colombier 				break;
1297dd7cddfSDavid du Colombier 			}
1307dd7cddfSDavid du Colombier 		}
131*a2c41696SDavid du Colombier 		*bp = 0;
132*a2c41696SDavid du Colombier 		retc = 'a';	/* alphanumeric */
133*a2c41696SDavid du Colombier 	} else {	/* maybe it's a number, but could be . */
1347dd7cddfSDavid du Colombier 		char *rem;
1357dd7cddfSDavid du Colombier 		/* read input until can't be a number */
1367dd7cddfSDavid du Colombier 		for ( ; (c = input()) != 0; ) {
1377dd7cddfSDavid du Colombier 			if (bp-buf >= sz)
138*a2c41696SDavid du Colombier 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
1397dd7cddfSDavid du Colombier 					FATAL( "out of space for number %.10s...", buf );
1407dd7cddfSDavid du Colombier 			if (isdigit(c) || c == 'e' || c == 'E'
1417dd7cddfSDavid du Colombier 			  || c == '.' || c == '+' || c == '-')
1427dd7cddfSDavid du Colombier 				*bp++ = c;
1437dd7cddfSDavid du Colombier 			else {
1447dd7cddfSDavid du Colombier 				unput(c);
1457dd7cddfSDavid du Colombier 				break;
1467dd7cddfSDavid du Colombier 			}
1477dd7cddfSDavid du Colombier 		}
1487dd7cddfSDavid du Colombier 		*bp = 0;
1497dd7cddfSDavid du Colombier 		strtod(buf, &rem);	/* parse the number */
150*a2c41696SDavid du Colombier 		if (rem == buf) {	/* it wasn't a valid number at all */
151*a2c41696SDavid du Colombier 			buf[1] = 0;	/* return one character as token */
152*a2c41696SDavid du Colombier 			retc = buf[0];	/* character is its own type */
153*a2c41696SDavid du Colombier 			unputstr(rem+1); /* put rest back for later */
154*a2c41696SDavid du Colombier 		} else {	/* some prefix was a number */
1557dd7cddfSDavid du Colombier 			unputstr(rem);	/* put rest back for later */
156*a2c41696SDavid du Colombier 			rem[0] = 0;	/* truncate buf after number part */
157*a2c41696SDavid du Colombier 			retc = '0';	/* type is number */
158*a2c41696SDavid du Colombier 		}
1597dd7cddfSDavid du Colombier 	}
1607dd7cddfSDavid du Colombier 	*pbuf = buf;
1617dd7cddfSDavid du Colombier 	*psz = sz;
162*a2c41696SDavid du Colombier 	return retc;
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier int	word(char *);
1667dd7cddfSDavid du Colombier int	string(void);
1677dd7cddfSDavid du Colombier int	regexpr(void);
1687dd7cddfSDavid du Colombier int	sc	= 0;	/* 1 => return a } right now */
1697dd7cddfSDavid du Colombier int	reg	= 0;	/* 1 => return a REGEXPR now */
1707dd7cddfSDavid du Colombier 
yylex(void)1717dd7cddfSDavid du Colombier int yylex(void)
1727dd7cddfSDavid du Colombier {
1737dd7cddfSDavid du Colombier 	int c;
1747dd7cddfSDavid du Colombier 	static char *buf = 0;
175*a2c41696SDavid du Colombier 	static int bufsize = 5; /* BUG: setting this small causes core dump! */
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier 	if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
1787dd7cddfSDavid du Colombier 		FATAL( "out of space in yylex" );
1797dd7cddfSDavid du Colombier 	if (sc) {
1807dd7cddfSDavid du Colombier 		sc = 0;
1817dd7cddfSDavid du Colombier 		RET('}');
1827dd7cddfSDavid du Colombier 	}
1837dd7cddfSDavid du Colombier 	if (reg) {
1847dd7cddfSDavid du Colombier 		reg = 0;
1857dd7cddfSDavid du Colombier 		return regexpr();
1867dd7cddfSDavid du Colombier 	}
1877dd7cddfSDavid du Colombier 	for (;;) {
1887dd7cddfSDavid du Colombier 		c = gettok(&buf, &bufsize);
1897dd7cddfSDavid du Colombier 		if (c == 0)
1907dd7cddfSDavid du Colombier 			return 0;
1917dd7cddfSDavid du Colombier 		if (isalpha(c) || c == '_')
1927dd7cddfSDavid du Colombier 			return word(buf);
193*a2c41696SDavid du Colombier 		if (isdigit(c)) {
1947dd7cddfSDavid du Colombier 			yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
1957dd7cddfSDavid du Colombier 			/* should this also have STR set? */
1967dd7cddfSDavid du Colombier 			RET(NUMBER);
1977dd7cddfSDavid du Colombier 		}
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 		yylval.i = c;
2007dd7cddfSDavid du Colombier 		switch (c) {
2017dd7cddfSDavid du Colombier 		case '\n':	/* {EOL} */
2027dd7cddfSDavid du Colombier 			RET(NL);
2037dd7cddfSDavid du Colombier 		case '\r':	/* assume \n is coming */
2047dd7cddfSDavid du Colombier 		case ' ':	/* {WS}+ */
2057dd7cddfSDavid du Colombier 		case '\t':
2067dd7cddfSDavid du Colombier 			break;
2077dd7cddfSDavid du Colombier 		case '#':	/* #.* strip comments */
2087dd7cddfSDavid du Colombier 			while ((c = input()) != '\n' && c != 0)
2097dd7cddfSDavid du Colombier 				;
2107dd7cddfSDavid du Colombier 			unput(c);
2117dd7cddfSDavid du Colombier 			break;
2127dd7cddfSDavid du Colombier 		case ';':
2137dd7cddfSDavid du Colombier 			RET(';');
2147dd7cddfSDavid du Colombier 		case '\\':
2157dd7cddfSDavid du Colombier 			if (peek() == '\n') {
2167dd7cddfSDavid du Colombier 				input();
2177dd7cddfSDavid du Colombier 			} else if (peek() == '\r') {
2187dd7cddfSDavid du Colombier 				input(); input();	/* \n */
2197dd7cddfSDavid du Colombier 				lineno++;
2207dd7cddfSDavid du Colombier 			} else {
2217dd7cddfSDavid du Colombier 				RET(c);
2227dd7cddfSDavid du Colombier 			}
2237dd7cddfSDavid du Colombier 			break;
2247dd7cddfSDavid du Colombier 		case '&':
2257dd7cddfSDavid du Colombier 			if (peek() == '&') {
2267dd7cddfSDavid du Colombier 				input(); RET(AND);
2277dd7cddfSDavid du Colombier 			} else
2287dd7cddfSDavid du Colombier 				RET('&');
2297dd7cddfSDavid du Colombier 		case '|':
2307dd7cddfSDavid du Colombier 			if (peek() == '|') {
2317dd7cddfSDavid du Colombier 				input(); RET(BOR);
2327dd7cddfSDavid du Colombier 			} else
2337dd7cddfSDavid du Colombier 				RET('|');
2347dd7cddfSDavid du Colombier 		case '!':
2357dd7cddfSDavid du Colombier 			if (peek() == '=') {
2367dd7cddfSDavid du Colombier 				input(); yylval.i = NE; RET(NE);
2377dd7cddfSDavid du Colombier 			} else if (peek() == '~') {
2387dd7cddfSDavid du Colombier 				input(); yylval.i = NOTMATCH; RET(MATCHOP);
2397dd7cddfSDavid du Colombier 			} else
2407dd7cddfSDavid du Colombier 				RET(NOT);
2417dd7cddfSDavid du Colombier 		case '~':
2427dd7cddfSDavid du Colombier 			yylval.i = MATCH;
2437dd7cddfSDavid du Colombier 			RET(MATCHOP);
2447dd7cddfSDavid du Colombier 		case '<':
2457dd7cddfSDavid du Colombier 			if (peek() == '=') {
2467dd7cddfSDavid du Colombier 				input(); yylval.i = LE; RET(LE);
2477dd7cddfSDavid du Colombier 			} else {
2487dd7cddfSDavid du Colombier 				yylval.i = LT; RET(LT);
2497dd7cddfSDavid du Colombier 			}
2507dd7cddfSDavid du Colombier 		case '=':
2517dd7cddfSDavid du Colombier 			if (peek() == '=') {
2527dd7cddfSDavid du Colombier 				input(); yylval.i = EQ; RET(EQ);
2537dd7cddfSDavid du Colombier 			} else {
2547dd7cddfSDavid du Colombier 				yylval.i = ASSIGN; RET(ASGNOP);
2557dd7cddfSDavid du Colombier 			}
2567dd7cddfSDavid du Colombier 		case '>':
2577dd7cddfSDavid du Colombier 			if (peek() == '=') {
2587dd7cddfSDavid du Colombier 				input(); yylval.i = GE; RET(GE);
2597dd7cddfSDavid du Colombier 			} else if (peek() == '>') {
2607dd7cddfSDavid du Colombier 				input(); yylval.i = APPEND; RET(APPEND);
2617dd7cddfSDavid du Colombier 			} else {
2627dd7cddfSDavid du Colombier 				yylval.i = GT; RET(GT);
2637dd7cddfSDavid du Colombier 			}
2647dd7cddfSDavid du Colombier 		case '+':
2657dd7cddfSDavid du Colombier 			if (peek() == '+') {
2667dd7cddfSDavid du Colombier 				input(); yylval.i = INCR; RET(INCR);
2677dd7cddfSDavid du Colombier 			} else if (peek() == '=') {
2687dd7cddfSDavid du Colombier 				input(); yylval.i = ADDEQ; RET(ASGNOP);
2697dd7cddfSDavid du Colombier 			} else
2707dd7cddfSDavid du Colombier 				RET('+');
2717dd7cddfSDavid du Colombier 		case '-':
2727dd7cddfSDavid du Colombier 			if (peek() == '-') {
2737dd7cddfSDavid du Colombier 				input(); yylval.i = DECR; RET(DECR);
2747dd7cddfSDavid du Colombier 			} else if (peek() == '=') {
2757dd7cddfSDavid du Colombier 				input(); yylval.i = SUBEQ; RET(ASGNOP);
2767dd7cddfSDavid du Colombier 			} else
2777dd7cddfSDavid du Colombier 				RET('-');
2787dd7cddfSDavid du Colombier 		case '*':
2797dd7cddfSDavid du Colombier 			if (peek() == '=') {	/* *= */
2807dd7cddfSDavid du Colombier 				input(); yylval.i = MULTEQ; RET(ASGNOP);
2817dd7cddfSDavid du Colombier 			} else if (peek() == '*') {	/* ** or **= */
2827dd7cddfSDavid du Colombier 				input();	/* eat 2nd * */
2837dd7cddfSDavid du Colombier 				if (peek() == '=') {
2847dd7cddfSDavid du Colombier 					input(); yylval.i = POWEQ; RET(ASGNOP);
2857dd7cddfSDavid du Colombier 				} else {
2867dd7cddfSDavid du Colombier 					RET(POWER);
2877dd7cddfSDavid du Colombier 				}
2887dd7cddfSDavid du Colombier 			} else
2897dd7cddfSDavid du Colombier 				RET('*');
2907dd7cddfSDavid du Colombier 		case '/':
2917dd7cddfSDavid du Colombier 			RET('/');
2927dd7cddfSDavid du Colombier 		case '%':
2937dd7cddfSDavid du Colombier 			if (peek() == '=') {
2947dd7cddfSDavid du Colombier 				input(); yylval.i = MODEQ; RET(ASGNOP);
2957dd7cddfSDavid du Colombier 			} else
2967dd7cddfSDavid du Colombier 				RET('%');
2977dd7cddfSDavid du Colombier 		case '^':
2987dd7cddfSDavid du Colombier 			if (peek() == '=') {
2997dd7cddfSDavid du Colombier 				input(); yylval.i = POWEQ; RET(ASGNOP);
3007dd7cddfSDavid du Colombier 			} else
3017dd7cddfSDavid du Colombier 				RET(POWER);
3027dd7cddfSDavid du Colombier 
3037dd7cddfSDavid du Colombier 		case '$':
3047dd7cddfSDavid du Colombier 			/* BUG: awkward, if not wrong */
3057dd7cddfSDavid du Colombier 			c = gettok(&buf, &bufsize);
306*a2c41696SDavid du Colombier 			if (isalpha(c)) {
3077dd7cddfSDavid du Colombier 				if (strcmp(buf, "NF") == 0) {	/* very special */
3087dd7cddfSDavid du Colombier 					unputstr("(NF)");
3097dd7cddfSDavid du Colombier 					RET(INDIRECT);
3107dd7cddfSDavid du Colombier 				}
311*a2c41696SDavid du Colombier 				c = peek();
312*a2c41696SDavid du Colombier 				if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
313*a2c41696SDavid du Colombier 					unputstr(buf);
314*a2c41696SDavid du Colombier 					RET(INDIRECT);
315*a2c41696SDavid du Colombier 				}
3167dd7cddfSDavid du Colombier 				yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
3177dd7cddfSDavid du Colombier 				RET(IVAR);
318*a2c41696SDavid du Colombier 			} else if (c == 0) {	/*  */
319*a2c41696SDavid du Colombier 				SYNTAX( "unexpected end of input after $" );
320*a2c41696SDavid du Colombier 				RET(';');
3217dd7cddfSDavid du Colombier 			} else {
3227dd7cddfSDavid du Colombier 				unputstr(buf);
3237dd7cddfSDavid du Colombier 				RET(INDIRECT);
3247dd7cddfSDavid du Colombier 			}
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 		case '}':
3277dd7cddfSDavid du Colombier 			if (--bracecnt < 0)
3287dd7cddfSDavid du Colombier 				SYNTAX( "extra }" );
3297dd7cddfSDavid du Colombier 			sc = 1;
3307dd7cddfSDavid du Colombier 			RET(';');
3317dd7cddfSDavid du Colombier 		case ']':
3327dd7cddfSDavid du Colombier 			if (--brackcnt < 0)
3337dd7cddfSDavid du Colombier 				SYNTAX( "extra ]" );
3347dd7cddfSDavid du Colombier 			RET(']');
3357dd7cddfSDavid du Colombier 		case ')':
3367dd7cddfSDavid du Colombier 			if (--parencnt < 0)
3377dd7cddfSDavid du Colombier 				SYNTAX( "extra )" );
3387dd7cddfSDavid du Colombier 			RET(')');
3397dd7cddfSDavid du Colombier 		case '{':
3407dd7cddfSDavid du Colombier 			bracecnt++;
3417dd7cddfSDavid du Colombier 			RET('{');
3427dd7cddfSDavid du Colombier 		case '[':
3437dd7cddfSDavid du Colombier 			brackcnt++;
3447dd7cddfSDavid du Colombier 			RET('[');
3457dd7cddfSDavid du Colombier 		case '(':
3467dd7cddfSDavid du Colombier 			parencnt++;
3477dd7cddfSDavid du Colombier 			RET('(');
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier 		case '"':
3507dd7cddfSDavid du Colombier 			return string();	/* BUG: should be like tran.c ? */
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 		default:
3537dd7cddfSDavid du Colombier 			RET(c);
3547dd7cddfSDavid du Colombier 		}
3557dd7cddfSDavid du Colombier 	}
3567dd7cddfSDavid du Colombier }
3577dd7cddfSDavid du Colombier 
string(void)3587dd7cddfSDavid du Colombier int string(void)
3597dd7cddfSDavid du Colombier {
3607dd7cddfSDavid du Colombier 	int c, n;
3617dd7cddfSDavid du Colombier 	char *s, *bp;
3627dd7cddfSDavid du Colombier 	static char *buf = 0;
3637dd7cddfSDavid du Colombier 	static int bufsz = 500;
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 	if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
3667dd7cddfSDavid du Colombier 		FATAL("out of space for strings");
3677dd7cddfSDavid du Colombier 	for (bp = buf; (c = input()) != '"'; ) {
368*a2c41696SDavid du Colombier 		if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
3697dd7cddfSDavid du Colombier 			FATAL("out of space for string %.10s...", buf);
3707dd7cddfSDavid du Colombier 		switch (c) {
3717dd7cddfSDavid du Colombier 		case '\n':
3727dd7cddfSDavid du Colombier 		case '\r':
3737dd7cddfSDavid du Colombier 		case 0:
3747dd7cddfSDavid du Colombier 			SYNTAX( "non-terminated string %.10s...", buf );
3757dd7cddfSDavid du Colombier 			lineno++;
376*a2c41696SDavid du Colombier 			if (c == 0)	/* hopeless */
377*a2c41696SDavid du Colombier 				FATAL( "giving up" );
3787dd7cddfSDavid du Colombier 			break;
3797dd7cddfSDavid du Colombier 		case '\\':
3807dd7cddfSDavid du Colombier 			c = input();
3817dd7cddfSDavid du Colombier 			switch (c) {
3827dd7cddfSDavid du Colombier 			case '"': *bp++ = '"'; break;
3837dd7cddfSDavid du Colombier 			case 'n': *bp++ = '\n'; break;
3847dd7cddfSDavid du Colombier 			case 't': *bp++ = '\t'; break;
3857dd7cddfSDavid du Colombier 			case 'f': *bp++ = '\f'; break;
3867dd7cddfSDavid du Colombier 			case 'r': *bp++ = '\r'; break;
3877dd7cddfSDavid du Colombier 			case 'b': *bp++ = '\b'; break;
3887dd7cddfSDavid du Colombier 			case 'v': *bp++ = '\v'; break;
3897dd7cddfSDavid du Colombier 			case 'a': *bp++ = '\007'; break;
3907dd7cddfSDavid du Colombier 			case '\\': *bp++ = '\\'; break;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 			case '0': case '1': case '2': /* octal: \d \dd \ddd */
3937dd7cddfSDavid du Colombier 			case '3': case '4': case '5': case '6': case '7':
3947dd7cddfSDavid du Colombier 				n = c - '0';
3957dd7cddfSDavid du Colombier 				if ((c = peek()) >= '0' && c < '8') {
3967dd7cddfSDavid du Colombier 					n = 8 * n + input() - '0';
3977dd7cddfSDavid du Colombier 					if ((c = peek()) >= '0' && c < '8')
3987dd7cddfSDavid du Colombier 						n = 8 * n + input() - '0';
3997dd7cddfSDavid du Colombier 				}
4007dd7cddfSDavid du Colombier 				*bp++ = n;
4017dd7cddfSDavid du Colombier 				break;
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier 			case 'x':	/* hex  \x0-9a-fA-F + */
4047dd7cddfSDavid du Colombier 			    {	char xbuf[100], *px;
4057dd7cddfSDavid du Colombier 				for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
4067dd7cddfSDavid du Colombier 					if (isdigit(c)
4077dd7cddfSDavid du Colombier 					 || (c >= 'a' && c <= 'f')
4087dd7cddfSDavid du Colombier 					 || (c >= 'A' && c <= 'F'))
4097dd7cddfSDavid du Colombier 						*px++ = c;
4107dd7cddfSDavid du Colombier 					else
4117dd7cddfSDavid du Colombier 						break;
4127dd7cddfSDavid du Colombier 				}
4137dd7cddfSDavid du Colombier 				*px = 0;
4147dd7cddfSDavid du Colombier 				unput(c);
415*a2c41696SDavid du Colombier 	  			sscanf(xbuf, "%x", (unsigned int *) &n);
4167dd7cddfSDavid du Colombier 				*bp++ = n;
4177dd7cddfSDavid du Colombier 				break;
4187dd7cddfSDavid du Colombier 			    }
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier 			default:
4217dd7cddfSDavid du Colombier 				*bp++ = c;
4227dd7cddfSDavid du Colombier 				break;
4237dd7cddfSDavid du Colombier 			}
4247dd7cddfSDavid du Colombier 			break;
4257dd7cddfSDavid du Colombier 		default:
4267dd7cddfSDavid du Colombier 			*bp++ = c;
4277dd7cddfSDavid du Colombier 			break;
4287dd7cddfSDavid du Colombier 		}
4297dd7cddfSDavid du Colombier 	}
4307dd7cddfSDavid du Colombier 	*bp = 0;
4317dd7cddfSDavid du Colombier 	s = tostring(buf);
4327dd7cddfSDavid du Colombier 	*bp++ = ' '; *bp++ = 0;
4337dd7cddfSDavid du Colombier 	yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
4347dd7cddfSDavid du Colombier 	RET(STRING);
4357dd7cddfSDavid du Colombier }
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier 
binsearch(char * w,Keyword * kp,int n)4387dd7cddfSDavid du Colombier int binsearch(char *w, Keyword *kp, int n)
4397dd7cddfSDavid du Colombier {
4407dd7cddfSDavid du Colombier 	int cond, low, mid, high;
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier 	low = 0;
4437dd7cddfSDavid du Colombier 	high = n - 1;
4447dd7cddfSDavid du Colombier 	while (low <= high) {
4457dd7cddfSDavid du Colombier 		mid = (low + high) / 2;
4467dd7cddfSDavid du Colombier 		if ((cond = strcmp(w, kp[mid].word)) < 0)
4477dd7cddfSDavid du Colombier 			high = mid - 1;
4487dd7cddfSDavid du Colombier 		else if (cond > 0)
4497dd7cddfSDavid du Colombier 			low = mid + 1;
4507dd7cddfSDavid du Colombier 		else
4517dd7cddfSDavid du Colombier 			return mid;
4527dd7cddfSDavid du Colombier 	}
4537dd7cddfSDavid du Colombier 	return -1;
4547dd7cddfSDavid du Colombier }
4557dd7cddfSDavid du Colombier 
word(char * w)4567dd7cddfSDavid du Colombier int word(char *w)
4577dd7cddfSDavid du Colombier {
4587dd7cddfSDavid du Colombier 	Keyword *kp;
4597dd7cddfSDavid du Colombier 	int c, n;
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier 	n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
462*a2c41696SDavid du Colombier /* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
4637dd7cddfSDavid du Colombier 	kp = keywords + n;
4647dd7cddfSDavid du Colombier 	if (n != -1) {	/* found in table */
4657dd7cddfSDavid du Colombier 		yylval.i = kp->sub;
4667dd7cddfSDavid du Colombier 		switch (kp->type) {	/* special handling */
467*a2c41696SDavid du Colombier 		case BLTIN:
468*a2c41696SDavid du Colombier 			if (kp->sub == FSYSTEM && safe)
4697dd7cddfSDavid du Colombier 				SYNTAX( "system is unsafe" );
4707dd7cddfSDavid du Colombier 			RET(kp->type);
4717dd7cddfSDavid du Colombier 		case FUNC:
4727dd7cddfSDavid du Colombier 			if (infunc)
4737dd7cddfSDavid du Colombier 				SYNTAX( "illegal nested function" );
4747dd7cddfSDavid du Colombier 			RET(kp->type);
4757dd7cddfSDavid du Colombier 		case RETURN:
4767dd7cddfSDavid du Colombier 			if (!infunc)
4777dd7cddfSDavid du Colombier 				SYNTAX( "return not in function" );
4787dd7cddfSDavid du Colombier 			RET(kp->type);
4797dd7cddfSDavid du Colombier 		case VARNF:
4807dd7cddfSDavid du Colombier 			yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
4817dd7cddfSDavid du Colombier 			RET(VARNF);
4827dd7cddfSDavid du Colombier 		default:
4837dd7cddfSDavid du Colombier 			RET(kp->type);
4847dd7cddfSDavid du Colombier 		}
4857dd7cddfSDavid du Colombier 	}
4867dd7cddfSDavid du Colombier 	c = peek();	/* look for '(' */
4877dd7cddfSDavid du Colombier 	if (c != '(' && infunc && (n=isarg(w)) >= 0) {
4887dd7cddfSDavid du Colombier 		yylval.i = n;
4897dd7cddfSDavid du Colombier 		RET(ARG);
4907dd7cddfSDavid du Colombier 	} else {
4917dd7cddfSDavid du Colombier 		yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
4927dd7cddfSDavid du Colombier 		if (c == '(') {
4937dd7cddfSDavid du Colombier 			RET(CALL);
4947dd7cddfSDavid du Colombier 		} else {
4957dd7cddfSDavid du Colombier 			RET(VAR);
4967dd7cddfSDavid du Colombier 		}
4977dd7cddfSDavid du Colombier 	}
4987dd7cddfSDavid du Colombier }
4997dd7cddfSDavid du Colombier 
startreg(void)500*a2c41696SDavid du Colombier void startreg(void)	/* next call to yylex will return a regular expression */
5017dd7cddfSDavid du Colombier {
5027dd7cddfSDavid du Colombier 	reg = 1;
5037dd7cddfSDavid du Colombier }
5047dd7cddfSDavid du Colombier 
regexpr(void)5057dd7cddfSDavid du Colombier int regexpr(void)
5067dd7cddfSDavid du Colombier {
5077dd7cddfSDavid du Colombier 	int c;
5087dd7cddfSDavid du Colombier 	static char *buf = 0;
5097dd7cddfSDavid du Colombier 	static int bufsz = 500;
5107dd7cddfSDavid du Colombier 	char *bp;
5117dd7cddfSDavid du Colombier 
5127dd7cddfSDavid du Colombier 	if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
5137dd7cddfSDavid du Colombier 		FATAL("out of space for rex expr");
5147dd7cddfSDavid du Colombier 	bp = buf;
5157dd7cddfSDavid du Colombier 	for ( ; (c = input()) != '/' && c != 0; ) {
516*a2c41696SDavid du Colombier 		if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
5177dd7cddfSDavid du Colombier 			FATAL("out of space for reg expr %.10s...", buf);
5187dd7cddfSDavid du Colombier 		if (c == '\n') {
5197dd7cddfSDavid du Colombier 			SYNTAX( "newline in regular expression %.10s...", buf );
5207dd7cddfSDavid du Colombier 			unput('\n');
5217dd7cddfSDavid du Colombier 			break;
5227dd7cddfSDavid du Colombier 		} else if (c == '\\') {
5237dd7cddfSDavid du Colombier 			*bp++ = '\\';
5247dd7cddfSDavid du Colombier 			*bp++ = input();
5257dd7cddfSDavid du Colombier 		} else {
5267dd7cddfSDavid du Colombier 			*bp++ = c;
5277dd7cddfSDavid du Colombier 		}
5287dd7cddfSDavid du Colombier 	}
5297dd7cddfSDavid du Colombier 	*bp = 0;
530*a2c41696SDavid du Colombier 	if (c == 0)
531*a2c41696SDavid du Colombier 		SYNTAX("non-terminated regular expression %.10s...", buf);
5327dd7cddfSDavid du Colombier 	yylval.s = tostring(buf);
5337dd7cddfSDavid du Colombier 	unput('/');
5347dd7cddfSDavid du Colombier 	RET(REGEXPR);
5357dd7cddfSDavid du Colombier }
5367dd7cddfSDavid du Colombier 
5377dd7cddfSDavid du Colombier /* low-level lexical stuff, sort of inherited from lex */
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier char	ebuf[300];
5407dd7cddfSDavid du Colombier char	*ep = ebuf;
5417dd7cddfSDavid du Colombier char	yysbuf[100];	/* pushback buffer */
5427dd7cddfSDavid du Colombier char	*yysptr = yysbuf;
5437dd7cddfSDavid du Colombier FILE	*yyin = 0;
5447dd7cddfSDavid du Colombier 
input(void)5457dd7cddfSDavid du Colombier int input(void)	/* get next lexical input character */
5467dd7cddfSDavid du Colombier {
5477dd7cddfSDavid du Colombier 	int c;
5487dd7cddfSDavid du Colombier 	extern char *lexprog;
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier 	if (yysptr > yysbuf)
551*a2c41696SDavid du Colombier 		c = (uschar)*--yysptr;
5527dd7cddfSDavid du Colombier 	else if (lexprog != NULL) {	/* awk '...' */
553*a2c41696SDavid du Colombier 		if ((c = (uschar)*lexprog) != 0)
5547dd7cddfSDavid du Colombier 			lexprog++;
5557dd7cddfSDavid du Colombier 	} else				/* awk -f ... */
5567dd7cddfSDavid du Colombier 		c = pgetc();
5577dd7cddfSDavid du Colombier 	if (c == '\n')
5587dd7cddfSDavid du Colombier 		lineno++;
5597dd7cddfSDavid du Colombier 	else if (c == EOF)
5607dd7cddfSDavid du Colombier 		c = 0;
5617dd7cddfSDavid du Colombier 	if (ep >= ebuf + sizeof ebuf)
5627dd7cddfSDavid du Colombier 		ep = ebuf;
5637dd7cddfSDavid du Colombier 	return *ep++ = c;
5647dd7cddfSDavid du Colombier }
5657dd7cddfSDavid du Colombier 
unput(int c)5667dd7cddfSDavid du Colombier void unput(int c)	/* put lexical character back on input */
5677dd7cddfSDavid du Colombier {
5687dd7cddfSDavid du Colombier 	if (c == '\n')
5697dd7cddfSDavid du Colombier 		lineno--;
5707dd7cddfSDavid du Colombier 	if (yysptr >= yysbuf + sizeof(yysbuf))
5717dd7cddfSDavid du Colombier 		FATAL("pushed back too much: %.20s...", yysbuf);
5727dd7cddfSDavid du Colombier 	*yysptr++ = c;
5737dd7cddfSDavid du Colombier 	if (--ep < ebuf)
5747dd7cddfSDavid du Colombier 		ep = ebuf + sizeof(ebuf) - 1;
5757dd7cddfSDavid du Colombier }
5767dd7cddfSDavid du Colombier 
unputstr(const char * s)577*a2c41696SDavid du Colombier void unputstr(const char *s)	/* put a string back on input */
5787dd7cddfSDavid du Colombier {
5797dd7cddfSDavid du Colombier 	int i;
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier 	for (i = strlen(s)-1; i >= 0; i--)
5827dd7cddfSDavid du Colombier 		unput(s[i]);
5837dd7cddfSDavid du Colombier }
584