xref: /plan9/sys/src/cmd/cpp/lex.c (revision 2a7824990d644563b93ed8d4abf1407c40b2087a)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <stdio.h>
43e12c5d1SDavid du Colombier #include "cpp.h"
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier  * lexical FSM encoding
83e12c5d1SDavid du Colombier  *   when in state state, and one of the characters
93e12c5d1SDavid du Colombier  *   in ch arrives, enter nextstate.
103e12c5d1SDavid du Colombier  *   States >= S_SELF are either final, or at least require special action.
113e12c5d1SDavid du Colombier  *   In 'fsm' there is a line for each state X charset X nextstate.
123e12c5d1SDavid du Colombier  *   List chars that overwrite previous entries later (e.g. C_ALPH
133e12c5d1SDavid du Colombier  *   can be overridden by '_' by a later entry; and C_XX is the
143e12c5d1SDavid du Colombier  *   the universal set, and should always be first.
153e12c5d1SDavid du Colombier  *   States above S_SELF are represented in the big table as negative values.
163e12c5d1SDavid du Colombier  *   S_SELF and S_SELFB encode the resulting token type in the upper bits.
173e12c5d1SDavid du Colombier  *   These actions differ in that S_SELF doesn't have a lookahead char,
183e12c5d1SDavid du Colombier  *   S_SELFB does.
193e12c5d1SDavid du Colombier  *
203e12c5d1SDavid du Colombier  *   The encoding is blown out into a big table for time-efficiency.
213e12c5d1SDavid du Colombier  *   Entries have
223e12c5d1SDavid du Colombier  *      nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits.
233e12c5d1SDavid du Colombier  */
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier #define	MAXSTATE 32
263e12c5d1SDavid du Colombier #define	ACT(tok,act)	((tok<<7)+act)
273e12c5d1SDavid du Colombier #define	QBSBIT	0100
283e12c5d1SDavid du Colombier #define	GETACT(st)	(st>>7)&0x1ff
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier #define	UTF2(c)		((c)>=0xA0 && (c)<0xE0)		/* 2-char UTF seq */
313e12c5d1SDavid du Colombier #define	UTF3(c)		((c)>=0xE0 && (c)<0xF0)		/* 3-char UTF seq */
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier /* character classes */
343e12c5d1SDavid du Colombier #define	C_WS	1
353e12c5d1SDavid du Colombier #define	C_ALPH	2
363e12c5d1SDavid du Colombier #define	C_NUM	3
373e12c5d1SDavid du Colombier #define	C_EOF	4
383e12c5d1SDavid du Colombier #define	C_XX	5
393e12c5d1SDavid du Colombier 
403e12c5d1SDavid du Colombier enum state {
413e12c5d1SDavid du Colombier 	START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4,
423e12c5d1SDavid du Colombier 	CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1,
433e12c5d1SDavid du Colombier 	CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1,
443e12c5d1SDavid du Colombier 	S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR,
453e12c5d1SDavid du Colombier 	S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME
463e12c5d1SDavid du Colombier };
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier struct	fsm {
493e12c5d1SDavid du Colombier 	int	state;		/* if in this state */
503e12c5d1SDavid du Colombier 	uchar	ch[4];		/* and see one of these characters */
513e12c5d1SDavid du Colombier 	int	nextstate;	/* enter this state if +ve */
523e12c5d1SDavid du Colombier };
533e12c5d1SDavid du Colombier 
543e12c5d1SDavid du Colombier /*const*/ struct fsm fsm[] = {
553e12c5d1SDavid du Colombier 	/* start state */
563e12c5d1SDavid du Colombier 	START,	{ C_XX },	ACT(UNCLASS,S_SELF),
577dd7cddfSDavid du Colombier 	START,	{ ' ', '\t', '\v', '\r' },	WS1,
583e12c5d1SDavid du Colombier 	START,	{ C_NUM },	NUM1,
593e12c5d1SDavid du Colombier 	START,	{ '.' },	NUM3,
603e12c5d1SDavid du Colombier 	START,	{ C_ALPH },	ID1,
613e12c5d1SDavid du Colombier 	START,	{ 'L' },	ST1,
623e12c5d1SDavid du Colombier 	START,	{ '"' },	ST2,
633e12c5d1SDavid du Colombier 	START,	{ '\'' },	CC1,
643e12c5d1SDavid du Colombier 	START,	{ '/' },	COM1,
65bd389b36SDavid du Colombier 	START,	{ EOFC },	S_EOF,
663e12c5d1SDavid du Colombier 	START,	{ '\n' },	S_NL,
673e12c5d1SDavid du Colombier 	START,	{ '-' },	MINUS1,
683e12c5d1SDavid du Colombier 	START,	{ '+' },	PLUS1,
693e12c5d1SDavid du Colombier 	START,	{ '<' },	LT1,
703e12c5d1SDavid du Colombier 	START,	{ '>' },	GT1,
713e12c5d1SDavid du Colombier 	START,	{ '=' },	ASG1,
723e12c5d1SDavid du Colombier 	START,	{ '!' },	NOT1,
733e12c5d1SDavid du Colombier 	START,	{ '&' },	AND1,
743e12c5d1SDavid du Colombier 	START,	{ '|' },	OR1,
753e12c5d1SDavid du Colombier 	START,	{ '#' },	SHARP1,
763e12c5d1SDavid du Colombier 	START,	{ '%' },	PCT1,
773e12c5d1SDavid du Colombier 	START,	{ '[' },	ACT(SBRA,S_SELF),
783e12c5d1SDavid du Colombier 	START,	{ ']' },	ACT(SKET,S_SELF),
793e12c5d1SDavid du Colombier 	START,	{ '(' },	ACT(LP,S_SELF),
803e12c5d1SDavid du Colombier 	START,	{ ')' },	ACT(RP,S_SELF),
813e12c5d1SDavid du Colombier 	START,	{ '*' },	STAR1,
823e12c5d1SDavid du Colombier 	START,	{ ',' },	ACT(COMMA,S_SELF),
833e12c5d1SDavid du Colombier 	START,	{ '?' },	ACT(QUEST,S_SELF),
843e12c5d1SDavid du Colombier 	START,	{ ':' },	ACT(COLON,S_SELF),
853e12c5d1SDavid du Colombier 	START,	{ ';' },	ACT(SEMIC,S_SELF),
863e12c5d1SDavid du Colombier 	START,	{ '{' },	ACT(CBRA,S_SELF),
873e12c5d1SDavid du Colombier 	START,	{ '}' },	ACT(CKET,S_SELF),
883e12c5d1SDavid du Colombier 	START,	{ '~' },	ACT(TILDE,S_SELF),
893e12c5d1SDavid du Colombier 	START,	{ '^' },	CIRC1,
903e12c5d1SDavid du Colombier 
913e12c5d1SDavid du Colombier 	/* saw a digit */
923e12c5d1SDavid du Colombier 	NUM1,	{ C_XX },	ACT(NUMBER,S_SELFB),
933e12c5d1SDavid du Colombier 	NUM1,	{ C_NUM, C_ALPH, '.' },	NUM1,
943e12c5d1SDavid du Colombier 	NUM1,	{ 'E', 'e' },	NUM2,
953e12c5d1SDavid du Colombier 	NUM1,	{ '_' },	ACT(NUMBER,S_SELFB),
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier 	/* saw possible start of exponent, digits-e */
983e12c5d1SDavid du Colombier 	NUM2,	{ C_XX },	ACT(NUMBER,S_SELFB),
993e12c5d1SDavid du Colombier 	NUM2,	{ '+', '-' },	NUM1,
1003e12c5d1SDavid du Colombier 	NUM2,	{ C_NUM, C_ALPH },	NUM1,
1013e12c5d1SDavid du Colombier 	NUM2,	{ '_' },	ACT(NUMBER,S_SELFB),
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier 	/* saw a '.', which could be a number or an operator */
1043e12c5d1SDavid du Colombier 	NUM3,	{ C_XX },	ACT(DOT,S_SELFB),
1053e12c5d1SDavid du Colombier 	NUM3,	{ '.' },	DOTS1,
1063e12c5d1SDavid du Colombier 	NUM3,	{ C_NUM },	NUM1,
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier 	DOTS1,	{ C_XX },	ACT(UNCLASS, S_SELFB),
1093e12c5d1SDavid du Colombier 	DOTS1,	{ C_NUM },	NUM1,
1103e12c5d1SDavid du Colombier 	DOTS1,	{ '.' },	ACT(ELLIPS, S_SELF),
1113e12c5d1SDavid du Colombier 
1123e12c5d1SDavid du Colombier 	/* saw a letter or _ */
1133e12c5d1SDavid du Colombier 	ID1,	{ C_XX },	ACT(NAME,S_NAME),
1143e12c5d1SDavid du Colombier 	ID1,	{ C_ALPH, C_NUM },	ID1,
1153e12c5d1SDavid du Colombier 
1163e12c5d1SDavid du Colombier 	/* saw L (start of wide string?) */
1173e12c5d1SDavid du Colombier 	ST1,	{ C_XX },	ACT(NAME,S_NAME),
1183e12c5d1SDavid du Colombier 	ST1,	{ C_ALPH, C_NUM },	ID1,
1193e12c5d1SDavid du Colombier 	ST1,	{ '"' },	ST2,
1203e12c5d1SDavid du Colombier 	ST1,	{ '\'' },	CC1,
1213e12c5d1SDavid du Colombier 
1223e12c5d1SDavid du Colombier 	/* saw " beginning string */
1233e12c5d1SDavid du Colombier 	ST2,	{ C_XX },	ST2,
1243e12c5d1SDavid du Colombier 	ST2,	{ '"' },	ACT(STRING, S_SELF),
1253e12c5d1SDavid du Colombier 	ST2,	{ '\\' },	ST3,
1263e12c5d1SDavid du Colombier 	ST2,	{ '\n' },	S_STNL,
127bd389b36SDavid du Colombier 	ST2,	{ EOFC },	S_EOFSTR,
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier 	/* saw \ in string */
1303e12c5d1SDavid du Colombier 	ST3,	{ C_XX },	ST2,
1313e12c5d1SDavid du Colombier 	ST3,	{ '\n' },	S_STNL,
132bd389b36SDavid du Colombier 	ST3,	{ EOFC },	S_EOFSTR,
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier 	/* saw ' beginning character const */
1353e12c5d1SDavid du Colombier 	CC1,	{ C_XX },	CC1,
1363e12c5d1SDavid du Colombier 	CC1,	{ '\'' },	ACT(CCON, S_SELF),
1373e12c5d1SDavid du Colombier 	CC1,	{ '\\' },	CC2,
1383e12c5d1SDavid du Colombier 	CC1,	{ '\n' },	S_STNL,
139bd389b36SDavid du Colombier 	CC1,	{ EOFC },	S_EOFSTR,
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier 	/* saw \ in ccon */
1423e12c5d1SDavid du Colombier 	CC2,	{ C_XX },	CC1,
1433e12c5d1SDavid du Colombier 	CC2,	{ '\n' },	S_STNL,
144bd389b36SDavid du Colombier 	CC2,	{ EOFC },	S_EOFSTR,
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier 	/* saw /, perhaps start of comment */
1473e12c5d1SDavid du Colombier 	COM1,	{ C_XX },	ACT(SLASH, S_SELFB),
1483e12c5d1SDavid du Colombier 	COM1,	{ '=' },	ACT(ASSLASH, S_SELF),
1493e12c5d1SDavid du Colombier 	COM1,	{ '*' },	COM2,
1503e12c5d1SDavid du Colombier 	COM1,	{ '/' },	COM4,
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier 	/* saw "/*", start of comment */
1533e12c5d1SDavid du Colombier 	COM2,	{ C_XX },	COM2,
1543e12c5d1SDavid du Colombier 	COM2,	{ '\n' },	S_COMNL,
1553e12c5d1SDavid du Colombier 	COM2,	{ '*' },	COM3,
156bd389b36SDavid du Colombier 	COM2,	{ EOFC },	S_EOFCOM,
1573e12c5d1SDavid du Colombier 
1583e12c5d1SDavid du Colombier 	/* saw the * possibly ending a comment */
1593e12c5d1SDavid du Colombier 	COM3,	{ C_XX },	COM2,
1603e12c5d1SDavid du Colombier 	COM3,	{ '\n' },	S_COMNL,
1613e12c5d1SDavid du Colombier 	COM3,	{ '*' },	COM3,
1623e12c5d1SDavid du Colombier 	COM3,	{ '/' },	S_COMMENT,
1637dd7cddfSDavid du Colombier 	COM3,	{ EOFC },	S_EOFCOM,
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier 	/* // comment */
1663e12c5d1SDavid du Colombier 	COM4,	{ C_XX },	COM4,
1673e12c5d1SDavid du Colombier 	COM4,	{ '\n' },	S_NL,
168bd389b36SDavid du Colombier 	COM4,	{ EOFC },	S_EOFCOM,
1693e12c5d1SDavid du Colombier 
1703e12c5d1SDavid du Colombier 	/* saw white space, eat it up */
1713e12c5d1SDavid du Colombier 	WS1,	{ C_XX },	S_WS,
1727dd7cddfSDavid du Colombier 	WS1,	{ ' ', '\t', '\v', '\r'},	WS1,
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 	/* saw -, check --, -=, -> */
1753e12c5d1SDavid du Colombier 	MINUS1,	{ C_XX },	ACT(MINUS, S_SELFB),
1763e12c5d1SDavid du Colombier 	MINUS1,	{ '-' },	ACT(MMINUS, S_SELF),
1773e12c5d1SDavid du Colombier 	MINUS1,	{ '=' },	ACT(ASMINUS,S_SELF),
1783e12c5d1SDavid du Colombier 	MINUS1,	{ '>' },	ACT(ARROW,S_SELF),
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier 	/* saw +, check ++, += */
1813e12c5d1SDavid du Colombier 	PLUS1,	{ C_XX },	ACT(PLUS, S_SELFB),
1823e12c5d1SDavid du Colombier 	PLUS1,	{ '+' },	ACT(PPLUS, S_SELF),
1833e12c5d1SDavid du Colombier 	PLUS1,	{ '=' },	ACT(ASPLUS, S_SELF),
1843e12c5d1SDavid du Colombier 
1853e12c5d1SDavid du Colombier 	/* saw <, check <<, <<=, <= */
1863e12c5d1SDavid du Colombier 	LT1,	{ C_XX },	ACT(LT, S_SELFB),
1873e12c5d1SDavid du Colombier 	LT1,	{ '<' },	LT2,
1883e12c5d1SDavid du Colombier 	LT1,	{ '=' },	ACT(LEQ, S_SELF),
1893e12c5d1SDavid du Colombier 	LT2,	{ C_XX },	ACT(LSH, S_SELFB),
1903e12c5d1SDavid du Colombier 	LT2,	{ '=' },	ACT(ASLSH, S_SELF),
1913e12c5d1SDavid du Colombier 
1923e12c5d1SDavid du Colombier 	/* saw >, check >>, >>=, >= */
1933e12c5d1SDavid du Colombier 	GT1,	{ C_XX },	ACT(GT, S_SELFB),
1943e12c5d1SDavid du Colombier 	GT1,	{ '>' },	GT2,
1953e12c5d1SDavid du Colombier 	GT1,	{ '=' },	ACT(GEQ, S_SELF),
1963e12c5d1SDavid du Colombier 	GT2,	{ C_XX },	ACT(RSH, S_SELFB),
1973e12c5d1SDavid du Colombier 	GT2,	{ '=' },	ACT(ASRSH, S_SELF),
1983e12c5d1SDavid du Colombier 
1993e12c5d1SDavid du Colombier 	/* = */
2003e12c5d1SDavid du Colombier 	ASG1,	{ C_XX },	ACT(ASGN, S_SELFB),
2013e12c5d1SDavid du Colombier 	ASG1,	{ '=' },	ACT(EQ, S_SELF),
2023e12c5d1SDavid du Colombier 
2033e12c5d1SDavid du Colombier 	/* ! */
2043e12c5d1SDavid du Colombier 	NOT1,	{ C_XX },	ACT(NOT, S_SELFB),
2053e12c5d1SDavid du Colombier 	NOT1,	{ '=' },	ACT(NEQ, S_SELF),
2063e12c5d1SDavid du Colombier 
2073e12c5d1SDavid du Colombier 	/* & */
2083e12c5d1SDavid du Colombier 	AND1,	{ C_XX },	ACT(AND, S_SELFB),
2093e12c5d1SDavid du Colombier 	AND1,	{ '&' },	ACT(LAND, S_SELF),
2103e12c5d1SDavid du Colombier 	AND1,	{ '=' },	ACT(ASAND, S_SELF),
2113e12c5d1SDavid du Colombier 
2123e12c5d1SDavid du Colombier 	/* | */
2133e12c5d1SDavid du Colombier 	OR1,	{ C_XX },	ACT(OR, S_SELFB),
2143e12c5d1SDavid du Colombier 	OR1,	{ '|' },	ACT(LOR, S_SELF),
2153e12c5d1SDavid du Colombier 	OR1,	{ '=' },	ACT(ASOR, S_SELF),
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier 	/* # */
2183e12c5d1SDavid du Colombier 	SHARP1,	{ C_XX },	ACT(SHARP, S_SELFB),
2193e12c5d1SDavid du Colombier 	SHARP1,	{ '#' },	ACT(DSHARP, S_SELF),
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier 	/* % */
2223e12c5d1SDavid du Colombier 	PCT1,	{ C_XX },	ACT(PCT, S_SELFB),
2233e12c5d1SDavid du Colombier 	PCT1,	{ '=' },	ACT(ASPCT, S_SELF),
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier 	/* * */
2263e12c5d1SDavid du Colombier 	STAR1,	{ C_XX },	ACT(STAR, S_SELFB),
2273e12c5d1SDavid du Colombier 	STAR1,	{ '=' },	ACT(ASSTAR, S_SELF),
2283e12c5d1SDavid du Colombier 
2293e12c5d1SDavid du Colombier 	/* ^ */
2303e12c5d1SDavid du Colombier 	CIRC1,	{ C_XX },	ACT(CIRC, S_SELFB),
2313e12c5d1SDavid du Colombier 	CIRC1,	{ '=' },	ACT(ASCIRC, S_SELF),
2323e12c5d1SDavid du Colombier 
2333e12c5d1SDavid du Colombier 	-1
2343e12c5d1SDavid du Colombier };
2353e12c5d1SDavid du Colombier 
236bd389b36SDavid du Colombier /* first index is char, second is state */
2373e12c5d1SDavid du Colombier /* increase #states to power of 2 to encourage use of shift */
238bd389b36SDavid du Colombier short	bigfsm[256][MAXSTATE];
2393e12c5d1SDavid du Colombier 
2403e12c5d1SDavid du Colombier void
expandlex(void)2413e12c5d1SDavid du Colombier expandlex(void)
2423e12c5d1SDavid du Colombier {
2433e12c5d1SDavid du Colombier 	/*const*/ struct fsm *fp;
2443e12c5d1SDavid du Colombier 	int i, j, nstate;
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 	for (fp = fsm; fp->state>=0; fp++) {
2473e12c5d1SDavid du Colombier 		for (i=0; fp->ch[i]; i++) {
2483e12c5d1SDavid du Colombier 			nstate = fp->nextstate;
2493e12c5d1SDavid du Colombier 			if (nstate >= S_SELF)
2503e12c5d1SDavid du Colombier 				nstate = ~nstate;
2513e12c5d1SDavid du Colombier 			switch (fp->ch[i]) {
2523e12c5d1SDavid du Colombier 
2533e12c5d1SDavid du Colombier 			case C_XX:		/* random characters */
254bd389b36SDavid du Colombier 				for (j=0; j<256; j++)
2553e12c5d1SDavid du Colombier 					bigfsm[j][fp->state] = nstate;
2563e12c5d1SDavid du Colombier 				continue;
2573e12c5d1SDavid du Colombier 			case C_ALPH:
258bd389b36SDavid du Colombier 				for (j=0; j<=256; j++)
2593e12c5d1SDavid du Colombier 					if ('a'<=j&&j<='z' || 'A'<=j&&j<='Z'
2603e12c5d1SDavid du Colombier 					  || UTF2(j) || UTF3(j) || j=='_')
261bd389b36SDavid du Colombier 						bigfsm[j][fp->state] = nstate;
2623e12c5d1SDavid du Colombier 				continue;
2633e12c5d1SDavid du Colombier 			case C_NUM:
2643e12c5d1SDavid du Colombier 				for (j='0'; j<='9'; j++)
265bd389b36SDavid du Colombier 					bigfsm[j][fp->state] = nstate;
2663e12c5d1SDavid du Colombier 				continue;
2673e12c5d1SDavid du Colombier 			default:
268bd389b36SDavid du Colombier 				bigfsm[fp->ch[i]][fp->state] = nstate;
2693e12c5d1SDavid du Colombier 			}
2703e12c5d1SDavid du Colombier 		}
2713e12c5d1SDavid du Colombier 	}
2723e12c5d1SDavid du Colombier 	/* install special cases for ? (trigraphs),  \ (splicing), runes, and EOB */
2733e12c5d1SDavid du Colombier 	for (i=0; i<MAXSTATE; i++) {
2743e12c5d1SDavid du Colombier 		for (j=0; j<0xFF; j++)
2753e12c5d1SDavid du Colombier 			if (j=='?' || j=='\\' || UTF2(j) || UTF3(j)) {
276bd389b36SDavid du Colombier 				if (bigfsm[j][i]>0)
277bd389b36SDavid du Colombier 					bigfsm[j][i] = ~bigfsm[j][i];
278bd389b36SDavid du Colombier 				bigfsm[j][i] &= ~QBSBIT;
2793e12c5d1SDavid du Colombier 			}
280bd389b36SDavid du Colombier 		bigfsm[EOB][i] = ~S_EOB;
281bd389b36SDavid du Colombier 		if (bigfsm[EOFC][i]>=0)
282bd389b36SDavid du Colombier 			bigfsm[EOFC][i] = ~S_EOF;
2833e12c5d1SDavid du Colombier 	}
2843e12c5d1SDavid du Colombier }
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier void
fixlex(void)2873e12c5d1SDavid du Colombier fixlex(void)
2883e12c5d1SDavid du Colombier {
2893e12c5d1SDavid du Colombier 	/* do C++ comments? */
2903e12c5d1SDavid du Colombier 	if (Cplusplus==0)
291bd389b36SDavid du Colombier 		bigfsm['/'][COM1] = bigfsm['x'][COM1];
2923e12c5d1SDavid du Colombier }
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier /*
2953e12c5d1SDavid du Colombier  * fill in a row of tokens from input, terminated by NL or END
2963e12c5d1SDavid du Colombier  * First token is put at trp->lp.
2973e12c5d1SDavid du Colombier  * Reset is non-zero when the input buffer can be "rewound."
2983e12c5d1SDavid du Colombier  * The value is a flag indicating that possible macros have
2993e12c5d1SDavid du Colombier  * been seen in the row.
3003e12c5d1SDavid du Colombier  */
3013e12c5d1SDavid du Colombier int
gettokens(Tokenrow * trp,int reset)3023e12c5d1SDavid du Colombier gettokens(Tokenrow *trp, int reset)
3033e12c5d1SDavid du Colombier {
3043e12c5d1SDavid du Colombier 	register int c, state, oldstate;
3053e12c5d1SDavid du Colombier 	register uchar *ip;
3063e12c5d1SDavid du Colombier 	register Token *tp, *maxp;
3073e12c5d1SDavid du Colombier 	int runelen;
3083e12c5d1SDavid du Colombier 	Source *s = cursource;
3093e12c5d1SDavid du Colombier 	int nmac = 0;
3103e12c5d1SDavid du Colombier 	extern char outbuf[];
3113e12c5d1SDavid du Colombier 
3123e12c5d1SDavid du Colombier 	tp = trp->lp;
3133e12c5d1SDavid du Colombier 	ip = s->inp;
3143e12c5d1SDavid du Colombier 	if (reset) {
3153e12c5d1SDavid du Colombier 		s->lineinc = 0;
3163e12c5d1SDavid du Colombier 		if (ip>=s->inl) {		/* nothing in buffer */
3173e12c5d1SDavid du Colombier 			s->inl = s->inb;
3183e12c5d1SDavid du Colombier 			fillbuf(s);
3193e12c5d1SDavid du Colombier 			ip = s->inp = s->inb;
320a8453668SDavid du Colombier 		} else if (ip >= s->inb+(3*s->ins/4)) {
3213e12c5d1SDavid du Colombier 			memmove(s->inb, ip, 4+s->inl-ip);
3223e12c5d1SDavid du Colombier 			s->inl = s->inb+(s->inl-ip);
3233e12c5d1SDavid du Colombier 			ip = s->inp = s->inb;
3243e12c5d1SDavid du Colombier 		}
3253e12c5d1SDavid du Colombier 	}
3263e12c5d1SDavid du Colombier 	maxp = &trp->bp[trp->max];
3273e12c5d1SDavid du Colombier 	runelen = 1;
3283e12c5d1SDavid du Colombier 	for (;;) {
3293e12c5d1SDavid du Colombier 	   continue2:
3303e12c5d1SDavid du Colombier 		if (tp>=maxp) {
3313e12c5d1SDavid du Colombier 			trp->lp = tp;
3323e12c5d1SDavid du Colombier 			tp = growtokenrow(trp);
3333e12c5d1SDavid du Colombier 			maxp = &trp->bp[trp->max];
3343e12c5d1SDavid du Colombier 		}
3353e12c5d1SDavid du Colombier 		tp->type = UNCLASS;
3363e12c5d1SDavid du Colombier 		tp->hideset = 0;
3373e12c5d1SDavid du Colombier 		tp->t = ip;
3383e12c5d1SDavid du Colombier 		tp->wslen = 0;
3393e12c5d1SDavid du Colombier 		tp->flag = 0;
3403e12c5d1SDavid du Colombier 		state = START;
3413e12c5d1SDavid du Colombier 		for (;;) {
3423e12c5d1SDavid du Colombier 			oldstate = state;
3433e12c5d1SDavid du Colombier 			c = *ip;
344bd389b36SDavid du Colombier 			if ((state = bigfsm[c][state]) >= 0) {
3453e12c5d1SDavid du Colombier 				ip += runelen;
3463e12c5d1SDavid du Colombier 				runelen = 1;
3473e12c5d1SDavid du Colombier 				continue;
3483e12c5d1SDavid du Colombier 			}
3493e12c5d1SDavid du Colombier 			state = ~state;
3503e12c5d1SDavid du Colombier 		reswitch:
3513e12c5d1SDavid du Colombier 			switch (state&0177) {
3523e12c5d1SDavid du Colombier 			case S_SELF:
3533e12c5d1SDavid du Colombier 				ip += runelen;
3543e12c5d1SDavid du Colombier 				runelen = 1;
3553e12c5d1SDavid du Colombier 			case S_SELFB:
3563e12c5d1SDavid du Colombier 				tp->type = GETACT(state);
3573e12c5d1SDavid du Colombier 				tp->len = ip - tp->t;
3583e12c5d1SDavid du Colombier 				tp++;
3593e12c5d1SDavid du Colombier 				goto continue2;
3603e12c5d1SDavid du Colombier 
3613e12c5d1SDavid du Colombier 			case S_NAME:	/* like S_SELFB but with nmac check */
3623e12c5d1SDavid du Colombier 				tp->type = NAME;
3633e12c5d1SDavid du Colombier 				tp->len = ip - tp->t;
3643e12c5d1SDavid du Colombier 				nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0);
3653e12c5d1SDavid du Colombier 				tp++;
3663e12c5d1SDavid du Colombier 				goto continue2;
3673e12c5d1SDavid du Colombier 
3683e12c5d1SDavid du Colombier 			case S_WS:
3693e12c5d1SDavid du Colombier 				tp->wslen = ip - tp->t;
3703e12c5d1SDavid du Colombier 				tp->t = ip;
3713e12c5d1SDavid du Colombier 				state = START;
3723e12c5d1SDavid du Colombier 				continue;
3733e12c5d1SDavid du Colombier 
3743e12c5d1SDavid du Colombier 			default:
3753e12c5d1SDavid du Colombier 				if ((state&QBSBIT)==0) {
3763e12c5d1SDavid du Colombier 					ip += runelen;
3773e12c5d1SDavid du Colombier 					runelen = 1;
3783e12c5d1SDavid du Colombier 					continue;
3793e12c5d1SDavid du Colombier 				}
3803e12c5d1SDavid du Colombier 				state &= ~QBSBIT;
3813e12c5d1SDavid du Colombier 				s->inp = ip;
3823e12c5d1SDavid du Colombier 				if (c=='?') { 	/* check trigraph */
3833e12c5d1SDavid du Colombier 					if (trigraph(s)) {
3843e12c5d1SDavid du Colombier 						state = oldstate;
3853e12c5d1SDavid du Colombier 						continue;
3863e12c5d1SDavid du Colombier 					}
3873e12c5d1SDavid du Colombier 					goto reswitch;
3883e12c5d1SDavid du Colombier 				}
3893e12c5d1SDavid du Colombier 				if (c=='\\') { /* line-folding */
3903e12c5d1SDavid du Colombier 					if (foldline(s)) {
3913e12c5d1SDavid du Colombier 						s->lineinc++;
3923e12c5d1SDavid du Colombier 						state = oldstate;
3933e12c5d1SDavid du Colombier 						continue;
3943e12c5d1SDavid du Colombier 					}
3953e12c5d1SDavid du Colombier 					goto reswitch;
3963e12c5d1SDavid du Colombier 				}
3973e12c5d1SDavid du Colombier 				if (UTF2(c)) {
3983e12c5d1SDavid du Colombier 					runelen = 2;
3993e12c5d1SDavid du Colombier 					goto reswitch;
4003e12c5d1SDavid du Colombier 				}
4013e12c5d1SDavid du Colombier 				if (UTF3(c)) {
4023e12c5d1SDavid du Colombier 					runelen = 3;
4033e12c5d1SDavid du Colombier 					goto reswitch;
4043e12c5d1SDavid du Colombier 				}
4053e12c5d1SDavid du Colombier 				error(WARNING, "Lexical botch in cpp");
4063e12c5d1SDavid du Colombier 				ip += runelen;
4073e12c5d1SDavid du Colombier 				runelen = 1;
4083e12c5d1SDavid du Colombier 				continue;
4093e12c5d1SDavid du Colombier 
4103e12c5d1SDavid du Colombier 			case S_EOB:
4113e12c5d1SDavid du Colombier 				s->inp = ip;
4123e12c5d1SDavid du Colombier 				fillbuf(cursource);
4133e12c5d1SDavid du Colombier 				state = oldstate;
4143e12c5d1SDavid du Colombier 				continue;
4153e12c5d1SDavid du Colombier 
4163e12c5d1SDavid du Colombier 			case S_EOF:
4173e12c5d1SDavid du Colombier 				tp->type = END;
4183e12c5d1SDavid du Colombier 				tp->len = 0;
4193e12c5d1SDavid du Colombier 				s->inp = ip;
4203e12c5d1SDavid du Colombier 				if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1)
4213e12c5d1SDavid du Colombier 					error(WARNING,"No newline at end of file");
4223e12c5d1SDavid du Colombier 				trp->lp = tp+1;
4233e12c5d1SDavid du Colombier 				return nmac;
4243e12c5d1SDavid du Colombier 
4253e12c5d1SDavid du Colombier 			case S_STNL:
4263e12c5d1SDavid du Colombier 				error(ERROR, "Unterminated string or char const");
4273e12c5d1SDavid du Colombier 			case S_NL:
4283e12c5d1SDavid du Colombier 				tp->t = ip;
4293e12c5d1SDavid du Colombier 				tp->type = NL;
4303e12c5d1SDavid du Colombier 				tp->len = 1;
4313e12c5d1SDavid du Colombier 				tp->wslen = 0;
4323e12c5d1SDavid du Colombier 				s->lineinc++;
4333e12c5d1SDavid du Colombier 				s->inp = ip+1;
4343e12c5d1SDavid du Colombier 				trp->lp = tp+1;
4353e12c5d1SDavid du Colombier 				return nmac;
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier 			case S_EOFSTR:
4383e12c5d1SDavid du Colombier 				error(FATAL, "EOF in string or char constant");
4393e12c5d1SDavid du Colombier 				break;
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 			case S_COMNL:
4423e12c5d1SDavid du Colombier 				s->lineinc++;
4433e12c5d1SDavid du Colombier 				state = COM2;
4443e12c5d1SDavid du Colombier 				ip += runelen;
4453e12c5d1SDavid du Colombier 				runelen = 1;
446a8453668SDavid du Colombier  				if (ip >= s->inb+(7*s->ins/8)) { /* very long comment */
4477dd7cddfSDavid du Colombier 					memmove(tp->t, ip, 4+s->inl-ip);
4487dd7cddfSDavid du Colombier 					s->inl -= ip-tp->t;
4497dd7cddfSDavid du Colombier 					ip = tp->t+1;
4507dd7cddfSDavid du Colombier 				}
4513e12c5d1SDavid du Colombier 				continue;
4523e12c5d1SDavid du Colombier 
4533e12c5d1SDavid du Colombier 			case S_EOFCOM:
4543e12c5d1SDavid du Colombier 				error(WARNING, "EOF inside comment");
4553e12c5d1SDavid du Colombier 				--ip;
4563e12c5d1SDavid du Colombier 			case S_COMMENT:
4573e12c5d1SDavid du Colombier 				++ip;
4583e12c5d1SDavid du Colombier 				tp->t = ip;
4593e12c5d1SDavid du Colombier 				tp->t[-1] = ' ';
4603e12c5d1SDavid du Colombier 				tp->wslen = 1;
4613e12c5d1SDavid du Colombier 				state = START;
4623e12c5d1SDavid du Colombier 				continue;
4633e12c5d1SDavid du Colombier 			}
4643e12c5d1SDavid du Colombier 			break;
4653e12c5d1SDavid du Colombier 		}
4663e12c5d1SDavid du Colombier 		ip += runelen;
4673e12c5d1SDavid du Colombier 		runelen = 1;
4683e12c5d1SDavid du Colombier 		tp->len = ip - tp->t;
4693e12c5d1SDavid du Colombier 		tp++;
4703e12c5d1SDavid du Colombier 	}
4713e12c5d1SDavid du Colombier }
4723e12c5d1SDavid du Colombier 
4733e12c5d1SDavid du Colombier /* have seen ?; handle the trigraph it starts (if any) else 0 */
4743e12c5d1SDavid du Colombier int
trigraph(Source * s)4753e12c5d1SDavid du Colombier trigraph(Source *s)
4763e12c5d1SDavid du Colombier {
4773e12c5d1SDavid du Colombier 	int c;
4783e12c5d1SDavid du Colombier 
4793e12c5d1SDavid du Colombier 	while (s->inp+2 >= s->inl && fillbuf(s)!=EOF)
4803e12c5d1SDavid du Colombier 		;
4813e12c5d1SDavid du Colombier 	if (s->inp[1]!='?')
4823e12c5d1SDavid du Colombier 		return 0;
4833e12c5d1SDavid du Colombier 	c = 0;
4843e12c5d1SDavid du Colombier 	switch(s->inp[2]) {
4853e12c5d1SDavid du Colombier 	case '=':
4863e12c5d1SDavid du Colombier 		c = '#'; break;
4873e12c5d1SDavid du Colombier 	case '(':
4883e12c5d1SDavid du Colombier 		c = '['; break;
4893e12c5d1SDavid du Colombier 	case '/':
4903e12c5d1SDavid du Colombier 		c = '\\'; break;
4913e12c5d1SDavid du Colombier 	case ')':
4923e12c5d1SDavid du Colombier 		c = ']'; break;
4933e12c5d1SDavid du Colombier 	case '\'':
4943e12c5d1SDavid du Colombier 		c = '^'; break;
4953e12c5d1SDavid du Colombier 	case '<':
4963e12c5d1SDavid du Colombier 		c = '{'; break;
4973e12c5d1SDavid du Colombier 	case '!':
4983e12c5d1SDavid du Colombier 		c = '|'; break;
4993e12c5d1SDavid du Colombier 	case '>':
5003e12c5d1SDavid du Colombier 		c = '}'; break;
5013e12c5d1SDavid du Colombier 	case '-':
5023e12c5d1SDavid du Colombier 		c = '~'; break;
5033e12c5d1SDavid du Colombier 	}
5043e12c5d1SDavid du Colombier 	if (c) {
5053e12c5d1SDavid du Colombier 		*s->inp = c;
5063e12c5d1SDavid du Colombier 		memmove(s->inp+1, s->inp+3, s->inl-s->inp+2);
5073e12c5d1SDavid du Colombier 		s->inl -= 2;
5083e12c5d1SDavid du Colombier 	}
5093e12c5d1SDavid du Colombier 	return c;
5103e12c5d1SDavid du Colombier }
5113e12c5d1SDavid du Colombier 
5123e12c5d1SDavid du Colombier int
foldline(Source * s)5133e12c5d1SDavid du Colombier foldline(Source *s)
5143e12c5d1SDavid du Colombier {
51559cc4ca5SDavid du Colombier 	int ncr = 0;
51659cc4ca5SDavid du Colombier 
51759cc4ca5SDavid du Colombier recheck:
5183e12c5d1SDavid du Colombier 	while (s->inp+1 >= s->inl && fillbuf(s)!=EOF)
5193e12c5d1SDavid du Colombier 		;
52059cc4ca5SDavid du Colombier 	if (s->inp[ncr+1] == '\r') {	/* nonstandardly, ignore CR before line-folding */
52159cc4ca5SDavid du Colombier 		ncr++;
52259cc4ca5SDavid du Colombier 		goto recheck;
52359cc4ca5SDavid du Colombier 	}
52459cc4ca5SDavid du Colombier 	if (s->inp[ncr+1] == '\n') {
52559cc4ca5SDavid du Colombier 		memmove(s->inp, s->inp+2+ncr, s->inl-s->inp+3-ncr);
52659cc4ca5SDavid du Colombier 		s->inl -= 2+ncr;
5273e12c5d1SDavid du Colombier 		return 1;
5283e12c5d1SDavid du Colombier 	}
5293e12c5d1SDavid du Colombier 	return 0;
5303e12c5d1SDavid du Colombier }
5313e12c5d1SDavid du Colombier 
5323e12c5d1SDavid du Colombier int
fillbuf(Source * s)5333e12c5d1SDavid du Colombier fillbuf(Source *s)
5343e12c5d1SDavid du Colombier {
5353e12c5d1SDavid du Colombier 	int n;
5363e12c5d1SDavid du Colombier 
537a8453668SDavid du Colombier 	while((char *)s->inl+s->ins/8 > (char *)s->inb+s->ins) {
538*c93608ccSDavid du Colombier 		int l = s->inl - s->inb;
539*c93608ccSDavid du Colombier 		int p = s->inp - s->inb;
540a8453668SDavid du Colombier 		if(l < 0)
541a8453668SDavid du Colombier 			error(FATAL, "negative end of input!?");
542a8453668SDavid du Colombier 		if(p < 0)
543a8453668SDavid du Colombier 			error(FATAL, "negative input pointer!?");
544a8453668SDavid du Colombier 		/* double the buffer size and try again */
545a8453668SDavid du Colombier 		s->ins *= 2;
546a8453668SDavid du Colombier 		s->inb = dorealloc(s->inb, s->ins);
547a8453668SDavid du Colombier 		s->inl = s->inb + l;
548a8453668SDavid du Colombier 		s->inp = s->inb + p;
549a8453668SDavid du Colombier 	}
550a8453668SDavid du Colombier 	if (s->fd<0 || (n=read(s->fd, (char *)s->inl, s->ins/8)) <= 0)
5513e12c5d1SDavid du Colombier 		n = 0;
5527dd7cddfSDavid du Colombier 	if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */
5537dd7cddfSDavid du Colombier 		*s->inp = EOFC;
5543e12c5d1SDavid du Colombier 	s->inl += n;
5553e12c5d1SDavid du Colombier 	s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB;
5563e12c5d1SDavid du Colombier 	if (n==0) {
557bd389b36SDavid du Colombier 		s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC;
5583e12c5d1SDavid du Colombier 		return EOF;
5593e12c5d1SDavid du Colombier 	}
5603e12c5d1SDavid du Colombier 	return 0;
5613e12c5d1SDavid du Colombier }
5623e12c5d1SDavid du Colombier 
5633e12c5d1SDavid du Colombier /*
5643e12c5d1SDavid du Colombier  * Push down to new source of characters.
5653e12c5d1SDavid du Colombier  * If fd>0 and str==NULL, then from a file `name';
5663e12c5d1SDavid du Colombier  * if fd==-1 and str, then from the string.
5673e12c5d1SDavid du Colombier  */
5683e12c5d1SDavid du Colombier Source *
setsource(char * name,int fd,char * str)5693e12c5d1SDavid du Colombier setsource(char *name, int fd, char *str)
5703e12c5d1SDavid du Colombier {
5713e12c5d1SDavid du Colombier 	Source *s = new(Source);
5723e12c5d1SDavid du Colombier 	int len;
5733e12c5d1SDavid du Colombier 
5743e12c5d1SDavid du Colombier 	s->line = 1;
5753e12c5d1SDavid du Colombier 	s->lineinc = 0;
5763e12c5d1SDavid du Colombier 	s->fd = fd;
5773e12c5d1SDavid du Colombier 	s->filename = name;
578219b2ee8SDavid du Colombier 	s->next = cursource;
579219b2ee8SDavid du Colombier 	s->ifdepth = 0;
580219b2ee8SDavid du Colombier 	cursource = s;
5813e12c5d1SDavid du Colombier 	/* slop at right for EOB */
5823e12c5d1SDavid du Colombier 	if (str) {
5833e12c5d1SDavid du Colombier 		len = strlen(str);
5843e12c5d1SDavid du Colombier 		s->inb = domalloc(len+4);
5853e12c5d1SDavid du Colombier 		s->inp = s->inb;
5863e12c5d1SDavid du Colombier 		strncpy((char *)s->inp, str, len);
5873e12c5d1SDavid du Colombier 	} else {
5889a747e4fSDavid du Colombier 		Dir *d;
5897dd7cddfSDavid du Colombier 		int junk;
5909a747e4fSDavid du Colombier 		ulong length = 0;
5919a747e4fSDavid du Colombier 		d = dirfstat(fd);
5929a747e4fSDavid du Colombier 		if (d != nil) {
5939a747e4fSDavid du Colombier 			length = d->length;
5949a747e4fSDavid du Colombier 			free(d);
5959a747e4fSDavid du Colombier 		}
5969a747e4fSDavid du Colombier 		junk = length;
5977dd7cddfSDavid du Colombier 		if (junk<INS)
5987dd7cddfSDavid du Colombier 			junk = INS;
5997dd7cddfSDavid du Colombier 		s->inb = domalloc((junk)+4);
6003e12c5d1SDavid du Colombier 		s->inp = s->inb;
6013e12c5d1SDavid du Colombier 		len = 0;
6023e12c5d1SDavid du Colombier 	}
603a8453668SDavid du Colombier 
604a8453668SDavid du Colombier 	s->ins = INS;
6053e12c5d1SDavid du Colombier 	s->inl = s->inp+len;
6063e12c5d1SDavid du Colombier 	s->inl[0] = s->inl[1] = EOB;
6073e12c5d1SDavid du Colombier 	return s;
6083e12c5d1SDavid du Colombier }
6093e12c5d1SDavid du Colombier 
6103e12c5d1SDavid du Colombier void
unsetsource(void)6113e12c5d1SDavid du Colombier unsetsource(void)
6123e12c5d1SDavid du Colombier {
6133e12c5d1SDavid du Colombier 	Source *s = cursource;
6143e12c5d1SDavid du Colombier 
6153e12c5d1SDavid du Colombier 	if (s->fd>=0) {
6163e12c5d1SDavid du Colombier 		close(s->fd);
6173e12c5d1SDavid du Colombier 		dofree(s->inb);
6183e12c5d1SDavid du Colombier 	}
6193e12c5d1SDavid du Colombier 	cursource = s->next;
6203e12c5d1SDavid du Colombier 	dofree(s);
6213e12c5d1SDavid du Colombier }
622