xref: /plan9/sys/src/cmd/awk/lex.c (revision 76f6a3b860b80e94688a646002aae821e49bdb30)
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 {
417dd7cddfSDavid du Colombier 	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 },
90*76f6a3b8SDavid du Colombier 	{ "while",	WHILE,		WHILE },
917dd7cddfSDavid du Colombier };
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier #define DEBUG
947dd7cddfSDavid du Colombier #ifdef	DEBUG
957dd7cddfSDavid du Colombier #define	RET(x)	{ if(dbg)printf("lex %s\n", tokname(x)); return(x); }
967dd7cddfSDavid du Colombier #else
977dd7cddfSDavid du Colombier #define	RET(x)	return(x)
987dd7cddfSDavid du Colombier #endif
997dd7cddfSDavid du Colombier 
peek(void)1007dd7cddfSDavid du Colombier int peek(void)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier 	int c = input();
1037dd7cddfSDavid du Colombier 	unput(c);
1047dd7cddfSDavid du Colombier 	return c;
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier 
gettok(char ** pbuf,int * psz)1077dd7cddfSDavid du Colombier int gettok(char **pbuf, int *psz)	/* get next input token */
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	int c;
1107dd7cddfSDavid du Colombier 	char *buf = *pbuf;
1117dd7cddfSDavid du Colombier 	int sz = *psz;
1127dd7cddfSDavid du Colombier 	char *bp = buf;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	c = input();
1157dd7cddfSDavid du Colombier 	if (c == 0)
1167dd7cddfSDavid du Colombier 		return 0;
1177dd7cddfSDavid du Colombier 	buf[0] = c;
1187dd7cddfSDavid du Colombier 	buf[1] = 0;
1197dd7cddfSDavid du Colombier 	if (!isalnum(c) && c != '.' && c != '_')
1207dd7cddfSDavid du Colombier 		return c;
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	*bp++ = c;
1237dd7cddfSDavid du Colombier 	if (isalpha(c) || c == '_') {	/* it's a varname */
1247dd7cddfSDavid du Colombier 		for ( ; (c = input()) != 0; ) {
1257dd7cddfSDavid du Colombier 			if (bp-buf >= sz)
1267dd7cddfSDavid du Colombier 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
1277dd7cddfSDavid du Colombier 					FATAL( "out of space for name %.10s...", buf );
1287dd7cddfSDavid du Colombier 			if (isalnum(c) || c == '_')
1297dd7cddfSDavid du Colombier 				*bp++ = c;
1307dd7cddfSDavid du Colombier 			else {
1317dd7cddfSDavid du Colombier 				*bp = 0;
1327dd7cddfSDavid du Colombier 				unput(c);
1337dd7cddfSDavid du Colombier 				break;
1347dd7cddfSDavid du Colombier 			}
1357dd7cddfSDavid du Colombier 		}
1367dd7cddfSDavid du Colombier 	} else {	/* it's a number */
1377dd7cddfSDavid du Colombier 		char *rem;
1387dd7cddfSDavid du Colombier 		/* read input until can't be a number */
1397dd7cddfSDavid du Colombier 		for ( ; (c = input()) != 0; ) {
1407dd7cddfSDavid du Colombier 			if (bp-buf >= sz)
1417dd7cddfSDavid du Colombier 				if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0))
1427dd7cddfSDavid du Colombier 					FATAL( "out of space for number %.10s...", buf );
1437dd7cddfSDavid du Colombier 			if (isdigit(c) || c == 'e' || c == 'E'
1447dd7cddfSDavid du Colombier 			  || c == '.' || c == '+' || c == '-')
1457dd7cddfSDavid du Colombier 				*bp++ = c;
1467dd7cddfSDavid du Colombier 			else {
1477dd7cddfSDavid du Colombier 				unput(c);
1487dd7cddfSDavid du Colombier 				break;
1497dd7cddfSDavid du Colombier 			}
1507dd7cddfSDavid du Colombier 		}
1517dd7cddfSDavid du Colombier 		*bp = 0;
1527dd7cddfSDavid du Colombier 		strtod(buf, &rem);	/* parse the number */
1537dd7cddfSDavid du Colombier 		unputstr(rem);		/* put rest back for later */
1547dd7cddfSDavid du Colombier 		rem[0] = 0;
1557dd7cddfSDavid du Colombier 	}
1567dd7cddfSDavid du Colombier 	*pbuf = buf;
1577dd7cddfSDavid du Colombier 	*psz = sz;
1587dd7cddfSDavid du Colombier 	return buf[0];
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier int	word(char *);
1627dd7cddfSDavid du Colombier int	string(void);
1637dd7cddfSDavid du Colombier int	regexpr(void);
1647dd7cddfSDavid du Colombier int	sc	= 0;	/* 1 => return a } right now */
1657dd7cddfSDavid du Colombier int	reg	= 0;	/* 1 => return a REGEXPR now */
1667dd7cddfSDavid du Colombier 
yylex(void)1677dd7cddfSDavid du Colombier int yylex(void)
1687dd7cddfSDavid du Colombier {
1697dd7cddfSDavid du Colombier 	int c;
1707dd7cddfSDavid du Colombier 	static char *buf = 0;
1717dd7cddfSDavid du Colombier 	static int bufsize = 500;
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL)
1747dd7cddfSDavid du Colombier 		FATAL( "out of space in yylex" );
1757dd7cddfSDavid du Colombier 	if (sc) {
1767dd7cddfSDavid du Colombier 		sc = 0;
1777dd7cddfSDavid du Colombier 		RET('}');
1787dd7cddfSDavid du Colombier 	}
1797dd7cddfSDavid du Colombier 	if (reg) {
1807dd7cddfSDavid du Colombier 		reg = 0;
1817dd7cddfSDavid du Colombier 		return regexpr();
1827dd7cddfSDavid du Colombier 	}
1837dd7cddfSDavid du Colombier 	for (;;) {
1847dd7cddfSDavid du Colombier 		c = gettok(&buf, &bufsize);
1857dd7cddfSDavid du Colombier 		if (c == 0)
1867dd7cddfSDavid du Colombier 			return 0;
1877dd7cddfSDavid du Colombier 		if (isalpha(c) || c == '_')
1887dd7cddfSDavid du Colombier 			return word(buf);
1897dd7cddfSDavid du Colombier 		if (isdigit(c) || c == '.') {
1907dd7cddfSDavid du Colombier 			yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
1917dd7cddfSDavid du Colombier 			/* should this also have STR set? */
1927dd7cddfSDavid du Colombier 			RET(NUMBER);
1937dd7cddfSDavid du Colombier 		}
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 		yylval.i = c;
1967dd7cddfSDavid du Colombier 		switch (c) {
1977dd7cddfSDavid du Colombier 		case '\n':	/* {EOL} */
1987dd7cddfSDavid du Colombier 			RET(NL);
1997dd7cddfSDavid du Colombier 		case '\r':	/* assume \n is coming */
2007dd7cddfSDavid du Colombier 		case ' ':	/* {WS}+ */
2017dd7cddfSDavid du Colombier 		case '\t':
2027dd7cddfSDavid du Colombier 			break;
2037dd7cddfSDavid du Colombier 		case '#':	/* #.* strip comments */
2047dd7cddfSDavid du Colombier 			while ((c = input()) != '\n' && c != 0)
2057dd7cddfSDavid du Colombier 				;
2067dd7cddfSDavid du Colombier 			unput(c);
2077dd7cddfSDavid du Colombier 			break;
2087dd7cddfSDavid du Colombier 		case ';':
2097dd7cddfSDavid du Colombier 			RET(';');
2107dd7cddfSDavid du Colombier 		case '\\':
2117dd7cddfSDavid du Colombier 			if (peek() == '\n') {
2127dd7cddfSDavid du Colombier 				input();
2137dd7cddfSDavid du Colombier 			} else if (peek() == '\r') {
2147dd7cddfSDavid du Colombier 				input(); input();	/* \n */
2157dd7cddfSDavid du Colombier 				lineno++;
2167dd7cddfSDavid du Colombier 			} else {
2177dd7cddfSDavid du Colombier 				RET(c);
2187dd7cddfSDavid du Colombier 			}
2197dd7cddfSDavid du Colombier 			break;
2207dd7cddfSDavid du Colombier 		case '&':
2217dd7cddfSDavid du Colombier 			if (peek() == '&') {
2227dd7cddfSDavid du Colombier 				input(); RET(AND);
2237dd7cddfSDavid du Colombier 			} else
2247dd7cddfSDavid du Colombier 				RET('&');
2257dd7cddfSDavid du Colombier 		case '|':
2267dd7cddfSDavid du Colombier 			if (peek() == '|') {
2277dd7cddfSDavid du Colombier 				input(); RET(BOR);
2287dd7cddfSDavid du Colombier 			} else
2297dd7cddfSDavid du Colombier 				RET('|');
2307dd7cddfSDavid du Colombier 		case '!':
2317dd7cddfSDavid du Colombier 			if (peek() == '=') {
2327dd7cddfSDavid du Colombier 				input(); yylval.i = NE; RET(NE);
2337dd7cddfSDavid du Colombier 			} else if (peek() == '~') {
2347dd7cddfSDavid du Colombier 				input(); yylval.i = NOTMATCH; RET(MATCHOP);
2357dd7cddfSDavid du Colombier 			} else
2367dd7cddfSDavid du Colombier 				RET(NOT);
2377dd7cddfSDavid du Colombier 		case '~':
2387dd7cddfSDavid du Colombier 			yylval.i = MATCH;
2397dd7cddfSDavid du Colombier 			RET(MATCHOP);
2407dd7cddfSDavid du Colombier 		case '<':
2417dd7cddfSDavid du Colombier 			if (peek() == '=') {
2427dd7cddfSDavid du Colombier 				input(); yylval.i = LE; RET(LE);
2437dd7cddfSDavid du Colombier 			} else {
2447dd7cddfSDavid du Colombier 				yylval.i = LT; RET(LT);
2457dd7cddfSDavid du Colombier 			}
2467dd7cddfSDavid du Colombier 		case '=':
2477dd7cddfSDavid du Colombier 			if (peek() == '=') {
2487dd7cddfSDavid du Colombier 				input(); yylval.i = EQ; RET(EQ);
2497dd7cddfSDavid du Colombier 			} else {
2507dd7cddfSDavid du Colombier 				yylval.i = ASSIGN; RET(ASGNOP);
2517dd7cddfSDavid du Colombier 			}
2527dd7cddfSDavid du Colombier 		case '>':
2537dd7cddfSDavid du Colombier 			if (peek() == '=') {
2547dd7cddfSDavid du Colombier 				input(); yylval.i = GE; RET(GE);
2557dd7cddfSDavid du Colombier 			} else if (peek() == '>') {
2567dd7cddfSDavid du Colombier 				input(); yylval.i = APPEND; RET(APPEND);
2577dd7cddfSDavid du Colombier 			} else {
2587dd7cddfSDavid du Colombier 				yylval.i = GT; RET(GT);
2597dd7cddfSDavid du Colombier 			}
2607dd7cddfSDavid du Colombier 		case '+':
2617dd7cddfSDavid du Colombier 			if (peek() == '+') {
2627dd7cddfSDavid du Colombier 				input(); yylval.i = INCR; RET(INCR);
2637dd7cddfSDavid du Colombier 			} else if (peek() == '=') {
2647dd7cddfSDavid du Colombier 				input(); yylval.i = ADDEQ; RET(ASGNOP);
2657dd7cddfSDavid du Colombier 			} else
2667dd7cddfSDavid du Colombier 				RET('+');
2677dd7cddfSDavid du Colombier 		case '-':
2687dd7cddfSDavid du Colombier 			if (peek() == '-') {
2697dd7cddfSDavid du Colombier 				input(); yylval.i = DECR; RET(DECR);
2707dd7cddfSDavid du Colombier 			} else if (peek() == '=') {
2717dd7cddfSDavid du Colombier 				input(); yylval.i = SUBEQ; RET(ASGNOP);
2727dd7cddfSDavid du Colombier 			} else
2737dd7cddfSDavid du Colombier 				RET('-');
2747dd7cddfSDavid du Colombier 		case '*':
2757dd7cddfSDavid du Colombier 			if (peek() == '=') {	/* *= */
2767dd7cddfSDavid du Colombier 				input(); yylval.i = MULTEQ; RET(ASGNOP);
2777dd7cddfSDavid du Colombier 			} else if (peek() == '*') {	/* ** or **= */
2787dd7cddfSDavid du Colombier 				input();	/* eat 2nd * */
2797dd7cddfSDavid du Colombier 				if (peek() == '=') {
2807dd7cddfSDavid du Colombier 					input(); yylval.i = POWEQ; RET(ASGNOP);
2817dd7cddfSDavid du Colombier 				} else {
2827dd7cddfSDavid du Colombier 					RET(POWER);
2837dd7cddfSDavid du Colombier 				}
2847dd7cddfSDavid du Colombier 			} else
2857dd7cddfSDavid du Colombier 				RET('*');
2867dd7cddfSDavid du Colombier 		case '/':
2877dd7cddfSDavid du Colombier 			RET('/');
2887dd7cddfSDavid du Colombier 		case '%':
2897dd7cddfSDavid du Colombier 			if (peek() == '=') {
2907dd7cddfSDavid du Colombier 				input(); yylval.i = MODEQ; RET(ASGNOP);
2917dd7cddfSDavid du Colombier 			} else
2927dd7cddfSDavid du Colombier 				RET('%');
2937dd7cddfSDavid du Colombier 		case '^':
2947dd7cddfSDavid du Colombier 			if (peek() == '=') {
2957dd7cddfSDavid du Colombier 				input(); yylval.i = POWEQ; RET(ASGNOP);
2967dd7cddfSDavid du Colombier 			} else
2977dd7cddfSDavid du Colombier 				RET(POWER);
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 		case '$':
3007dd7cddfSDavid du Colombier 			/* BUG: awkward, if not wrong */
3017dd7cddfSDavid du Colombier 			c = gettok(&buf, &bufsize);
3027dd7cddfSDavid du Colombier 			if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
3037dd7cddfSDavid du Colombier 				unputstr(buf);
3047dd7cddfSDavid du Colombier 				RET(INDIRECT);
3057dd7cddfSDavid du Colombier 			} else if (isalpha(c)) {
3067dd7cddfSDavid du Colombier 				if (strcmp(buf, "NF") == 0) {	/* very special */
3077dd7cddfSDavid du Colombier 					unputstr("(NF)");
3087dd7cddfSDavid du Colombier 					RET(INDIRECT);
3097dd7cddfSDavid du Colombier 				}
3107dd7cddfSDavid du Colombier 				yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
3117dd7cddfSDavid du Colombier 				RET(IVAR);
3127dd7cddfSDavid du Colombier 			} else {
3137dd7cddfSDavid du Colombier 				unputstr(buf);
3147dd7cddfSDavid du Colombier 				RET(INDIRECT);
3157dd7cddfSDavid du Colombier 			}
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier 		case '}':
3187dd7cddfSDavid du Colombier 			if (--bracecnt < 0)
3197dd7cddfSDavid du Colombier 				SYNTAX( "extra }" );
3207dd7cddfSDavid du Colombier 			sc = 1;
3217dd7cddfSDavid du Colombier 			RET(';');
3227dd7cddfSDavid du Colombier 		case ']':
3237dd7cddfSDavid du Colombier 			if (--brackcnt < 0)
3247dd7cddfSDavid du Colombier 				SYNTAX( "extra ]" );
3257dd7cddfSDavid du Colombier 			RET(']');
3267dd7cddfSDavid du Colombier 		case ')':
3277dd7cddfSDavid du Colombier 			if (--parencnt < 0)
3287dd7cddfSDavid du Colombier 				SYNTAX( "extra )" );
3297dd7cddfSDavid du Colombier 			RET(')');
3307dd7cddfSDavid du Colombier 		case '{':
3317dd7cddfSDavid du Colombier 			bracecnt++;
3327dd7cddfSDavid du Colombier 			RET('{');
3337dd7cddfSDavid du Colombier 		case '[':
3347dd7cddfSDavid du Colombier 			brackcnt++;
3357dd7cddfSDavid du Colombier 			RET('[');
3367dd7cddfSDavid du Colombier 		case '(':
3377dd7cddfSDavid du Colombier 			parencnt++;
3387dd7cddfSDavid du Colombier 			RET('(');
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 		case '"':
3417dd7cddfSDavid du Colombier 			return string();	/* BUG: should be like tran.c ? */
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier 		default:
3447dd7cddfSDavid du Colombier 			RET(c);
3457dd7cddfSDavid du Colombier 		}
3467dd7cddfSDavid du Colombier 	}
3477dd7cddfSDavid du Colombier }
3487dd7cddfSDavid du Colombier 
string(void)3497dd7cddfSDavid du Colombier int string(void)
3507dd7cddfSDavid du Colombier {
3517dd7cddfSDavid du Colombier 	int c, n;
3527dd7cddfSDavid du Colombier 	char *s, *bp;
3537dd7cddfSDavid du Colombier 	static char *buf = 0;
3547dd7cddfSDavid du Colombier 	static int bufsz = 500;
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier 	if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
3577dd7cddfSDavid du Colombier 		FATAL("out of space for strings");
3587dd7cddfSDavid du Colombier 	for (bp = buf; (c = input()) != '"'; ) {
3597dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0))
3607dd7cddfSDavid du Colombier 			FATAL("out of space for string %.10s...", buf);
3617dd7cddfSDavid du Colombier 		switch (c) {
3627dd7cddfSDavid du Colombier 		case '\n':
3637dd7cddfSDavid du Colombier 		case '\r':
3647dd7cddfSDavid du Colombier 		case 0:
3657dd7cddfSDavid du Colombier 			SYNTAX( "non-terminated string %.10s...", buf );
3667dd7cddfSDavid du Colombier 			lineno++;
3677dd7cddfSDavid du Colombier 			break;
3687dd7cddfSDavid du Colombier 		case '\\':
3697dd7cddfSDavid du Colombier 			c = input();
3707dd7cddfSDavid du Colombier 			switch (c) {
3717dd7cddfSDavid du Colombier 			case '"': *bp++ = '"'; break;
3727dd7cddfSDavid du Colombier 			case 'n': *bp++ = '\n'; break;
3737dd7cddfSDavid du Colombier 			case 't': *bp++ = '\t'; break;
3747dd7cddfSDavid du Colombier 			case 'f': *bp++ = '\f'; break;
3757dd7cddfSDavid du Colombier 			case 'r': *bp++ = '\r'; break;
3767dd7cddfSDavid du Colombier 			case 'b': *bp++ = '\b'; break;
3777dd7cddfSDavid du Colombier 			case 'v': *bp++ = '\v'; break;
3787dd7cddfSDavid du Colombier 			case 'a': *bp++ = '\007'; break;
3797dd7cddfSDavid du Colombier 			case '\\': *bp++ = '\\'; break;
3807dd7cddfSDavid du Colombier 
3817dd7cddfSDavid du Colombier 			case '0': case '1': case '2': /* octal: \d \dd \ddd */
3827dd7cddfSDavid du Colombier 			case '3': case '4': case '5': case '6': case '7':
3837dd7cddfSDavid du Colombier 				n = c - '0';
3847dd7cddfSDavid du Colombier 				if ((c = peek()) >= '0' && c < '8') {
3857dd7cddfSDavid du Colombier 					n = 8 * n + input() - '0';
3867dd7cddfSDavid du Colombier 					if ((c = peek()) >= '0' && c < '8')
3877dd7cddfSDavid du Colombier 						n = 8 * n + input() - '0';
3887dd7cddfSDavid du Colombier 				}
3897dd7cddfSDavid du Colombier 				*bp++ = n;
3907dd7cddfSDavid du Colombier 				break;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 			case 'x':	/* hex  \x0-9a-fA-F + */
3937dd7cddfSDavid du Colombier 			    {	char xbuf[100], *px;
3947dd7cddfSDavid du Colombier 				for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
3957dd7cddfSDavid du Colombier 					if (isdigit(c)
3967dd7cddfSDavid du Colombier 					 || (c >= 'a' && c <= 'f')
3977dd7cddfSDavid du Colombier 					 || (c >= 'A' && c <= 'F'))
3987dd7cddfSDavid du Colombier 						*px++ = c;
3997dd7cddfSDavid du Colombier 					else
4007dd7cddfSDavid du Colombier 						break;
4017dd7cddfSDavid du Colombier 				}
4027dd7cddfSDavid du Colombier 				*px = 0;
4037dd7cddfSDavid du Colombier 				unput(c);
4047dd7cddfSDavid du Colombier 	  			sscanf(xbuf, "%x", &n);
4057dd7cddfSDavid du Colombier 				*bp++ = n;
4067dd7cddfSDavid du Colombier 				break;
4077dd7cddfSDavid du Colombier 			    }
4087dd7cddfSDavid du Colombier 
4097dd7cddfSDavid du Colombier 			default:
4107dd7cddfSDavid du Colombier 				*bp++ = c;
4117dd7cddfSDavid du Colombier 				break;
4127dd7cddfSDavid du Colombier 			}
4137dd7cddfSDavid du Colombier 			break;
4147dd7cddfSDavid du Colombier 		default:
4157dd7cddfSDavid du Colombier 			*bp++ = c;
4167dd7cddfSDavid du Colombier 			break;
4177dd7cddfSDavid du Colombier 		}
4187dd7cddfSDavid du Colombier 	}
4197dd7cddfSDavid du Colombier 	*bp = 0;
4207dd7cddfSDavid du Colombier 	s = tostring(buf);
4217dd7cddfSDavid du Colombier 	*bp++ = ' '; *bp++ = 0;
4227dd7cddfSDavid du Colombier 	yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
4237dd7cddfSDavid du Colombier 	RET(STRING);
4247dd7cddfSDavid du Colombier }
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 
binsearch(char * w,Keyword * kp,int n)4277dd7cddfSDavid du Colombier int binsearch(char *w, Keyword *kp, int n)
4287dd7cddfSDavid du Colombier {
4297dd7cddfSDavid du Colombier 	int cond, low, mid, high;
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier 	low = 0;
4327dd7cddfSDavid du Colombier 	high = n - 1;
4337dd7cddfSDavid du Colombier 	while (low <= high) {
4347dd7cddfSDavid du Colombier 		mid = (low + high) / 2;
4357dd7cddfSDavid du Colombier 		if ((cond = strcmp(w, kp[mid].word)) < 0)
4367dd7cddfSDavid du Colombier 			high = mid - 1;
4377dd7cddfSDavid du Colombier 		else if (cond > 0)
4387dd7cddfSDavid du Colombier 			low = mid + 1;
4397dd7cddfSDavid du Colombier 		else
4407dd7cddfSDavid du Colombier 			return mid;
4417dd7cddfSDavid du Colombier 	}
4427dd7cddfSDavid du Colombier 	return -1;
4437dd7cddfSDavid du Colombier }
4447dd7cddfSDavid du Colombier 
word(char * w)4457dd7cddfSDavid du Colombier int word(char *w)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier 	Keyword *kp;
4487dd7cddfSDavid du Colombier 	int c, n;
4497dd7cddfSDavid du Colombier 
4507dd7cddfSDavid du Colombier 	n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
4517dd7cddfSDavid du Colombier 	kp = keywords + n;
4527dd7cddfSDavid du Colombier 	if (n != -1) {	/* found in table */
4537dd7cddfSDavid du Colombier 		yylval.i = kp->sub;
4547dd7cddfSDavid du Colombier 		switch (kp->type) {	/* special handling */
4557dd7cddfSDavid du Colombier 		case FSYSTEM:
4567dd7cddfSDavid du Colombier 			if (safe)
4577dd7cddfSDavid du Colombier 				SYNTAX( "system is unsafe" );
4587dd7cddfSDavid du Colombier 			RET(kp->type);
4597dd7cddfSDavid du Colombier 		case FUNC:
4607dd7cddfSDavid du Colombier 			if (infunc)
4617dd7cddfSDavid du Colombier 				SYNTAX( "illegal nested function" );
4627dd7cddfSDavid du Colombier 			RET(kp->type);
4637dd7cddfSDavid du Colombier 		case RETURN:
4647dd7cddfSDavid du Colombier 			if (!infunc)
4657dd7cddfSDavid du Colombier 				SYNTAX( "return not in function" );
4667dd7cddfSDavid du Colombier 			RET(kp->type);
4677dd7cddfSDavid du Colombier 		case VARNF:
4687dd7cddfSDavid du Colombier 			yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
4697dd7cddfSDavid du Colombier 			RET(VARNF);
4707dd7cddfSDavid du Colombier 		default:
4717dd7cddfSDavid du Colombier 			RET(kp->type);
4727dd7cddfSDavid du Colombier 		}
4737dd7cddfSDavid du Colombier 	}
4747dd7cddfSDavid du Colombier 	c = peek();	/* look for '(' */
4757dd7cddfSDavid du Colombier 	if (c != '(' && infunc && (n=isarg(w)) >= 0) {
4767dd7cddfSDavid du Colombier 		yylval.i = n;
4777dd7cddfSDavid du Colombier 		RET(ARG);
4787dd7cddfSDavid du Colombier 	} else {
4797dd7cddfSDavid du Colombier 		yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
4807dd7cddfSDavid du Colombier 		if (c == '(') {
4817dd7cddfSDavid du Colombier 			RET(CALL);
4827dd7cddfSDavid du Colombier 		} else {
4837dd7cddfSDavid du Colombier 			RET(VAR);
4847dd7cddfSDavid du Colombier 		}
4857dd7cddfSDavid du Colombier 	}
4867dd7cddfSDavid du Colombier }
4877dd7cddfSDavid du Colombier 
startreg(void)4887dd7cddfSDavid du Colombier void startreg(void)	/* next call to yyles will return a regular expression */
4897dd7cddfSDavid du Colombier {
4907dd7cddfSDavid du Colombier 	reg = 1;
4917dd7cddfSDavid du Colombier }
4927dd7cddfSDavid du Colombier 
regexpr(void)4937dd7cddfSDavid du Colombier int regexpr(void)
4947dd7cddfSDavid du Colombier {
4957dd7cddfSDavid du Colombier 	int c;
4967dd7cddfSDavid du Colombier 	static char *buf = 0;
4977dd7cddfSDavid du Colombier 	static int bufsz = 500;
4987dd7cddfSDavid du Colombier 	char *bp;
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL)
5017dd7cddfSDavid du Colombier 		FATAL("out of space for rex expr");
5027dd7cddfSDavid du Colombier 	bp = buf;
5037dd7cddfSDavid du Colombier 	for ( ; (c = input()) != '/' && c != 0; ) {
5047dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0))
5057dd7cddfSDavid du Colombier 			FATAL("out of space for reg expr %.10s...", buf);
5067dd7cddfSDavid du Colombier 		if (c == '\n') {
5077dd7cddfSDavid du Colombier 			SYNTAX( "newline in regular expression %.10s...", buf );
5087dd7cddfSDavid du Colombier 			unput('\n');
5097dd7cddfSDavid du Colombier 			break;
5107dd7cddfSDavid du Colombier 		} else if (c == '\\') {
5117dd7cddfSDavid du Colombier 			*bp++ = '\\';
5127dd7cddfSDavid du Colombier 			*bp++ = input();
5137dd7cddfSDavid du Colombier 		} else {
5147dd7cddfSDavid du Colombier 			*bp++ = c;
5157dd7cddfSDavid du Colombier 		}
5167dd7cddfSDavid du Colombier 	}
5177dd7cddfSDavid du Colombier 	*bp = 0;
5187dd7cddfSDavid du Colombier 	yylval.s = tostring(buf);
5197dd7cddfSDavid du Colombier 	unput('/');
5207dd7cddfSDavid du Colombier 	RET(REGEXPR);
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier /* low-level lexical stuff, sort of inherited from lex */
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier char	ebuf[300];
5267dd7cddfSDavid du Colombier char	*ep = ebuf;
5277dd7cddfSDavid du Colombier char	yysbuf[100];	/* pushback buffer */
5287dd7cddfSDavid du Colombier char	*yysptr = yysbuf;
5297dd7cddfSDavid du Colombier FILE	*yyin = 0;
5307dd7cddfSDavid du Colombier 
input(void)5317dd7cddfSDavid du Colombier int input(void)	/* get next lexical input character */
5327dd7cddfSDavid du Colombier {
5337dd7cddfSDavid du Colombier 	int c;
5347dd7cddfSDavid du Colombier 	extern char *lexprog;
5357dd7cddfSDavid du Colombier 
5367dd7cddfSDavid du Colombier 	if (yysptr > yysbuf)
5377dd7cddfSDavid du Colombier 		c = *--yysptr;
5387dd7cddfSDavid du Colombier 	else if (lexprog != NULL) {	/* awk '...' */
5397dd7cddfSDavid du Colombier 		if ((c = *lexprog) != 0)
5407dd7cddfSDavid du Colombier 			lexprog++;
5417dd7cddfSDavid du Colombier 	} else				/* awk -f ... */
5427dd7cddfSDavid du Colombier 		c = pgetc();
5437dd7cddfSDavid du Colombier 	if (c == '\n')
5447dd7cddfSDavid du Colombier 		lineno++;
5457dd7cddfSDavid du Colombier 	else if (c == EOF)
5467dd7cddfSDavid du Colombier 		c = 0;
5477dd7cddfSDavid du Colombier 	if (ep >= ebuf + sizeof ebuf)
5487dd7cddfSDavid du Colombier 		ep = ebuf;
5497dd7cddfSDavid du Colombier 	return *ep++ = c;
5507dd7cddfSDavid du Colombier }
5517dd7cddfSDavid du Colombier 
unput(int c)5527dd7cddfSDavid du Colombier void unput(int c)	/* put lexical character back on input */
5537dd7cddfSDavid du Colombier {
5547dd7cddfSDavid du Colombier 	if (c == '\n')
5557dd7cddfSDavid du Colombier 		lineno--;
5567dd7cddfSDavid du Colombier 	if (yysptr >= yysbuf + sizeof(yysbuf))
5577dd7cddfSDavid du Colombier 		FATAL("pushed back too much: %.20s...", yysbuf);
5587dd7cddfSDavid du Colombier 	*yysptr++ = c;
5597dd7cddfSDavid du Colombier 	if (--ep < ebuf)
5607dd7cddfSDavid du Colombier 		ep = ebuf + sizeof(ebuf) - 1;
5617dd7cddfSDavid du Colombier }
5627dd7cddfSDavid du Colombier 
unputstr(char * s)5637dd7cddfSDavid du Colombier void unputstr(char *s)	/* put a string back on input */
5647dd7cddfSDavid du Colombier {
5657dd7cddfSDavid du Colombier 	int i;
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier 	for (i = strlen(s)-1; i >= 0; i--)
5687dd7cddfSDavid du Colombier 		unput(s[i]);
5697dd7cddfSDavid du Colombier }
570