xref: /freebsd/contrib/one-true-awk/lex.c (revision 2e454f23faa1040e80182e324d1562560faeb957)
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