xref: /titanic_50/usr/src/lib/libpp/common/ppcontrol.c (revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968)
1*da2e3ebdSchin /***********************************************************************
2*da2e3ebdSchin *                                                                      *
3*da2e3ebdSchin *               This software is part of the ast package               *
4*da2e3ebdSchin *           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
5*da2e3ebdSchin *                      and is licensed under the                       *
6*da2e3ebdSchin *                  Common Public License, Version 1.0                  *
7*da2e3ebdSchin *                      by AT&T Knowledge Ventures                      *
8*da2e3ebdSchin *                                                                      *
9*da2e3ebdSchin *                A copy of the License is available at                 *
10*da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*da2e3ebdSchin *                                                                      *
13*da2e3ebdSchin *              Information and Software Systems Research               *
14*da2e3ebdSchin *                            AT&T Research                             *
15*da2e3ebdSchin *                           Florham Park NJ                            *
16*da2e3ebdSchin *                                                                      *
17*da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18*da2e3ebdSchin *                                                                      *
19*da2e3ebdSchin ***********************************************************************/
20*da2e3ebdSchin #pragma prototyped
21*da2e3ebdSchin /*
22*da2e3ebdSchin  * Glenn Fowler
23*da2e3ebdSchin  * AT&T Research
24*da2e3ebdSchin  *
25*da2e3ebdSchin  * preprocessor control directive support
26*da2e3ebdSchin  */
27*da2e3ebdSchin 
28*da2e3ebdSchin #include "pplib.h"
29*da2e3ebdSchin 
30*da2e3ebdSchin #include <regex.h>
31*da2e3ebdSchin 
32*da2e3ebdSchin #define TOKOP_DUP	(1<<0)
33*da2e3ebdSchin #define TOKOP_STRING	(1<<1)
34*da2e3ebdSchin #define TOKOP_UNSET	(1<<2)
35*da2e3ebdSchin 
36*da2e3ebdSchin struct edit
37*da2e3ebdSchin {
38*da2e3ebdSchin 	struct edit*	next;
39*da2e3ebdSchin 	regex_t		re;
40*da2e3ebdSchin };
41*da2e3ebdSchin 
42*da2e3ebdSchin struct map
43*da2e3ebdSchin {
44*da2e3ebdSchin 	struct map*	next;
45*da2e3ebdSchin 	regex_t		re;
46*da2e3ebdSchin 	struct edit*	edit;
47*da2e3ebdSchin };
48*da2e3ebdSchin 
49*da2e3ebdSchin #define RESTORE		(COLLECTING|CONDITIONAL|DEFINITION|DIRECTIVE|DISABLE|EOF2NL|HEADER|NOSPACE|NOVERTICAL|PASSEOF|STRIP)
50*da2e3ebdSchin 
51*da2e3ebdSchin /*
52*da2e3ebdSchin  * common predicate assertion operations
53*da2e3ebdSchin  * op is DEFINE or UNDEF
54*da2e3ebdSchin  */
55*da2e3ebdSchin 
56*da2e3ebdSchin static void
57*da2e3ebdSchin assert(int op, char* pred, char* args)
58*da2e3ebdSchin {
59*da2e3ebdSchin 	register struct pplist*		a;
60*da2e3ebdSchin 	register struct ppsymbol*	sym;
61*da2e3ebdSchin 	register struct pplist*		p;
62*da2e3ebdSchin 	register struct pplist*		q;
63*da2e3ebdSchin 
64*da2e3ebdSchin 	if (!args) switch (op)
65*da2e3ebdSchin 	{
66*da2e3ebdSchin 	case DEFINE:
67*da2e3ebdSchin 		goto mark;
68*da2e3ebdSchin 	case UNDEF:
69*da2e3ebdSchin 		a = 0;
70*da2e3ebdSchin 		goto unmark;
71*da2e3ebdSchin 	}
72*da2e3ebdSchin 	if (a = (struct pplist*)hashget(pp.prdtab, pred))
73*da2e3ebdSchin 	{
74*da2e3ebdSchin 		p = 0;
75*da2e3ebdSchin 		q = a;
76*da2e3ebdSchin 		while (q)
77*da2e3ebdSchin 		{
78*da2e3ebdSchin 			if (streq(q->value, args))
79*da2e3ebdSchin 			{
80*da2e3ebdSchin 				if (op == DEFINE) return;
81*da2e3ebdSchin 				q = q->next;
82*da2e3ebdSchin 				if (p) p->next = q;
83*da2e3ebdSchin 				else a = q;
84*da2e3ebdSchin 			}
85*da2e3ebdSchin 			else
86*da2e3ebdSchin 			{
87*da2e3ebdSchin 				p = q;
88*da2e3ebdSchin 				q = q->next;
89*da2e3ebdSchin 			}
90*da2e3ebdSchin 		}
91*da2e3ebdSchin 		if (op == UNDEF)
92*da2e3ebdSchin 		{
93*da2e3ebdSchin 		unmark:
94*da2e3ebdSchin 			hashput(pp.prdtab, pred, a);
95*da2e3ebdSchin 			if (sym = ppsymref(pp.symtab, pred))
96*da2e3ebdSchin 				sym->flags &= ~SYM_PREDICATE;
97*da2e3ebdSchin 			return;
98*da2e3ebdSchin 		}
99*da2e3ebdSchin 	}
100*da2e3ebdSchin 	if (op == DEFINE)
101*da2e3ebdSchin 	{
102*da2e3ebdSchin 		p = newof(0, struct pplist, 1, 0);
103*da2e3ebdSchin 		p->next = a;
104*da2e3ebdSchin 		p->value = strdup(args);
105*da2e3ebdSchin 		hashput(pp.prdtab, NiL, p);
106*da2e3ebdSchin 	mark:
107*da2e3ebdSchin 		if ((pp.state & COMPILE) && pp.truncate) return;
108*da2e3ebdSchin 		if (sym = ppsymset(pp.symtab, pred))
109*da2e3ebdSchin 			sym->flags |= SYM_PREDICATE;
110*da2e3ebdSchin 	}
111*da2e3ebdSchin }
112*da2e3ebdSchin 
113*da2e3ebdSchin /*
114*da2e3ebdSchin  * tokenize string ppop()
115*da2e3ebdSchin  *
116*da2e3ebdSchin  *	op	PP_* op
117*da2e3ebdSchin  *	name	option name
118*da2e3ebdSchin  *	s	string of option values
119*da2e3ebdSchin  *	n	option sense
120*da2e3ebdSchin  *	flags	TOKOP_* flags
121*da2e3ebdSchin  */
122*da2e3ebdSchin 
123*da2e3ebdSchin static void
124*da2e3ebdSchin tokop(int op, char* name, register char* s, register int n, int flags)
125*da2e3ebdSchin {
126*da2e3ebdSchin 	register int	c;
127*da2e3ebdSchin 	register char*	t;
128*da2e3ebdSchin 
129*da2e3ebdSchin 	if (!(flags & TOKOP_UNSET) && !n) error(2, "%s: option cannot be unset", name);
130*da2e3ebdSchin 	else if (!s) ppop(op, s, n);
131*da2e3ebdSchin 	else if (flags & TOKOP_STRING)
132*da2e3ebdSchin 	{
133*da2e3ebdSchin 		PUSH_LINE(s);
134*da2e3ebdSchin 		for (;;)
135*da2e3ebdSchin 		{
136*da2e3ebdSchin 			pp.state &= ~NOSPACE;
137*da2e3ebdSchin 			c = pplex();
138*da2e3ebdSchin 			pp.state |= NOSPACE;
139*da2e3ebdSchin 			if (!c) break;
140*da2e3ebdSchin 			if (c != ' ')
141*da2e3ebdSchin 				ppop(op, (flags & TOKOP_DUP) ? strdup(pp.token) : pp.token, n);
142*da2e3ebdSchin 		}
143*da2e3ebdSchin 		POP_LINE();
144*da2e3ebdSchin 	}
145*da2e3ebdSchin 	else do
146*da2e3ebdSchin 	{
147*da2e3ebdSchin 		while (*s == ' ') s++;
148*da2e3ebdSchin 		for (t = s; *t && *t != ' '; t++);
149*da2e3ebdSchin 		if (*t) *t++ = 0;
150*da2e3ebdSchin 		else t = 0;
151*da2e3ebdSchin 		if (*s) ppop(op, (flags & TOKOP_DUP) ? strdup(s) : s, n);
152*da2e3ebdSchin 	} while (s = t);
153*da2e3ebdSchin }
154*da2e3ebdSchin 
155*da2e3ebdSchin /*
156*da2e3ebdSchin  * return symbol pointer for next token macro (re)definition
157*da2e3ebdSchin  */
158*da2e3ebdSchin 
159*da2e3ebdSchin static struct ppsymbol*
160*da2e3ebdSchin macsym(int tok)
161*da2e3ebdSchin {
162*da2e3ebdSchin 	register struct ppsymbol*	sym;
163*da2e3ebdSchin 
164*da2e3ebdSchin 	if (tok != T_ID)
165*da2e3ebdSchin 	{
166*da2e3ebdSchin 		error(2, "%s: invalid macro name", pptokstr(pp.token, 0));
167*da2e3ebdSchin 		return 0;
168*da2e3ebdSchin 	}
169*da2e3ebdSchin 	sym = pprefmac(pp.token, REF_CREATE);
170*da2e3ebdSchin 	if ((sym->flags & SYM_FINAL) && (pp.mode & HOSTED)) return 0;
171*da2e3ebdSchin 	if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
172*da2e3ebdSchin 	{
173*da2e3ebdSchin 		if (!(pp.option & ALLPOSSIBLE))
174*da2e3ebdSchin 			error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
175*da2e3ebdSchin 		return 0;
176*da2e3ebdSchin 	}
177*da2e3ebdSchin 	if (!sym->macro) sym->macro = newof(0, struct ppmacro, 1, 0);
178*da2e3ebdSchin 	return sym;
179*da2e3ebdSchin }
180*da2e3ebdSchin 
181*da2e3ebdSchin /*
182*da2e3ebdSchin  * get one space canonical pplex() line, sans '\n', and place in p
183*da2e3ebdSchin  * x is max+1 pos in p
184*da2e3ebdSchin  * 0 returned if line too large
185*da2e3ebdSchin  * otherwise end of p ('\0') returned
186*da2e3ebdSchin  */
187*da2e3ebdSchin 
188*da2e3ebdSchin static char*
189*da2e3ebdSchin getline(register char* p, char* x, int disable)
190*da2e3ebdSchin {
191*da2e3ebdSchin 	register int	c;
192*da2e3ebdSchin 	register char*	s;
193*da2e3ebdSchin 	char*		b;
194*da2e3ebdSchin 	long		restore;
195*da2e3ebdSchin 
196*da2e3ebdSchin 	restore = pp.state & (NOSPACE|STRIP);
197*da2e3ebdSchin 	pp.state &= ~(NEWLINE|NOSPACE|STRIP);
198*da2e3ebdSchin 	pp.state |= EOF2NL;
199*da2e3ebdSchin 	b = p;
200*da2e3ebdSchin 	while ((c = pplex()) != '\n')
201*da2e3ebdSchin 	{
202*da2e3ebdSchin 		if (disable)
203*da2e3ebdSchin 		{
204*da2e3ebdSchin 			if (c == ' ')
205*da2e3ebdSchin 				/*ignore*/;
206*da2e3ebdSchin 			else if (disable == 1)
207*da2e3ebdSchin 				disable = (c == T_ID && streq(pp.token, pp.pass)) ? 2 : 0;
208*da2e3ebdSchin 			else
209*da2e3ebdSchin 			{
210*da2e3ebdSchin 				disable = 0;
211*da2e3ebdSchin 				if (c == ':')
212*da2e3ebdSchin 					pp.state |= DISABLE;
213*da2e3ebdSchin 			}
214*da2e3ebdSchin 		}
215*da2e3ebdSchin 		s = pp.token;
216*da2e3ebdSchin 		while (*p = *s++)
217*da2e3ebdSchin 			if (++p >= x)
218*da2e3ebdSchin 			{
219*da2e3ebdSchin 				p = 0;
220*da2e3ebdSchin 				goto done;
221*da2e3ebdSchin 			}
222*da2e3ebdSchin 	}
223*da2e3ebdSchin 	if (p > b && *(p - 1) == ' ')
224*da2e3ebdSchin 		p--;
225*da2e3ebdSchin 	if (p >= x)
226*da2e3ebdSchin 		p = 0;
227*da2e3ebdSchin 	else
228*da2e3ebdSchin 		*p = 0;
229*da2e3ebdSchin  done:
230*da2e3ebdSchin 	pp.state &= ~(NOSPACE|STRIP);
231*da2e3ebdSchin 	pp.state |= restore;
232*da2e3ebdSchin 	return p;
233*da2e3ebdSchin }
234*da2e3ebdSchin 
235*da2e3ebdSchin /*
236*da2e3ebdSchin  * regex error handler
237*da2e3ebdSchin  */
238*da2e3ebdSchin 
239*da2e3ebdSchin void
240*da2e3ebdSchin regfatal(regex_t* p, int level, int code)
241*da2e3ebdSchin {
242*da2e3ebdSchin 	char	buf[128];
243*da2e3ebdSchin 
244*da2e3ebdSchin 	regerror(code, p, buf, sizeof(buf));
245*da2e3ebdSchin 	regfree(p);
246*da2e3ebdSchin 	error(level, "regular expression: %s", buf);
247*da2e3ebdSchin }
248*da2e3ebdSchin 
249*da2e3ebdSchin /*
250*da2e3ebdSchin  * process a single directive line
251*da2e3ebdSchin  */
252*da2e3ebdSchin 
253*da2e3ebdSchin int
254*da2e3ebdSchin ppcontrol(void)
255*da2e3ebdSchin {
256*da2e3ebdSchin 	register char*			p;
257*da2e3ebdSchin 	register int			c;
258*da2e3ebdSchin 	register int			n;
259*da2e3ebdSchin 	register char*			s;
260*da2e3ebdSchin 	register struct ppmacro*	mac;
261*da2e3ebdSchin 	register struct ppsymbol*	sym;
262*da2e3ebdSchin 	struct edit*			edit;
263*da2e3ebdSchin 	struct map*			map;
264*da2e3ebdSchin 	struct ppfile*			fp;
265*da2e3ebdSchin 	int				o;
266*da2e3ebdSchin 	int				directive;
267*da2e3ebdSchin 	long				restore;
268*da2e3ebdSchin 	struct pptuple*			rp;
269*da2e3ebdSchin 	struct pptuple*			tp;
270*da2e3ebdSchin 	char*				v;
271*da2e3ebdSchin 	int				emitted;
272*da2e3ebdSchin 
273*da2e3ebdSchin 	union
274*da2e3ebdSchin 	{
275*da2e3ebdSchin 		struct map*		best;
276*da2e3ebdSchin 		struct ppinstk*		inp;
277*da2e3ebdSchin 		struct pplist*		list;
278*da2e3ebdSchin 		char*			string;
279*da2e3ebdSchin 		struct ppsymbol*	symbol;
280*da2e3ebdSchin 		int			type;
281*da2e3ebdSchin 		PPLINESYNC		linesync;
282*da2e3ebdSchin 	}				var;
283*da2e3ebdSchin 
284*da2e3ebdSchin 	static char			__va_args__[] = "__VA_ARGS__";
285*da2e3ebdSchin 	static int			i0;
286*da2e3ebdSchin 	static int			i1;
287*da2e3ebdSchin 	static int			i2;
288*da2e3ebdSchin 	static int			i3;
289*da2e3ebdSchin 	static int			i4;
290*da2e3ebdSchin 
291*da2e3ebdSchin 	static long			n1;
292*da2e3ebdSchin 	static long			n2;
293*da2e3ebdSchin 	static long			n3;
294*da2e3ebdSchin 
295*da2e3ebdSchin 	static char*			p0;
296*da2e3ebdSchin 	static char*			p1;
297*da2e3ebdSchin 	static char*			p2;
298*da2e3ebdSchin 	static char*			p3;
299*da2e3ebdSchin 	static char*			p4;
300*da2e3ebdSchin 	static char*			p5;
301*da2e3ebdSchin 	static char*			p6;
302*da2e3ebdSchin 
303*da2e3ebdSchin 	static struct ppmacro		old;
304*da2e3ebdSchin 	static char*			formargs[MAXFORMALS];
305*da2e3ebdSchin #if MACKEYARGS
306*da2e3ebdSchin 	static char*			formvals[MAXFORMALS];
307*da2e3ebdSchin #endif
308*da2e3ebdSchin 
309*da2e3ebdSchin 	emitted = 0;
310*da2e3ebdSchin 	if (pp.state & SKIPCONTROL) pp.level--;
311*da2e3ebdSchin 	restore = (pp.state & RESTORE)|NEWLINE;
312*da2e3ebdSchin 	if (pp.state & PASSTHROUGH) restore |= DISABLE;
313*da2e3ebdSchin 	else restore &= ~DISABLE;
314*da2e3ebdSchin 	pp.state &= ~(NEWLINE|RESTORE|SKIPCONTROL);
315*da2e3ebdSchin 	pp.state |= DIRECTIVE|DISABLE|EOF2NL|NOSPACE|NOVERTICAL;
316*da2e3ebdSchin #if COMPATIBLE
317*da2e3ebdSchin 	if ((pp.state & (COMPATIBILITY|STRICT)) == COMPATIBILITY || (pp.mode & HOSTED)) pp.state &= ~NOVERTICAL;
318*da2e3ebdSchin #else
319*da2e3ebdSchin 	if (pp.mode & HOSTED) pp.state &= ~NOVERTICAL;
320*da2e3ebdSchin #endif
321*da2e3ebdSchin 	switch (c = pplex())
322*da2e3ebdSchin 	{
323*da2e3ebdSchin 	case T_DECIMAL:
324*da2e3ebdSchin 	case T_OCTAL:
325*da2e3ebdSchin 		if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
326*da2e3ebdSchin 			error(1, "# <line> [ \"<file>\" [ <type> ] ]: non-standard directive");
327*da2e3ebdSchin 		directive = INCLUDE;
328*da2e3ebdSchin 		goto linesync;
329*da2e3ebdSchin 	case T_ID:
330*da2e3ebdSchin 		switch (directive = (int)hashref(pp.dirtab, pp.token))
331*da2e3ebdSchin 		{
332*da2e3ebdSchin 		case ELIF:
333*da2e3ebdSchin 		else_if:
334*da2e3ebdSchin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
335*da2e3ebdSchin 				goto eatdirective;
336*da2e3ebdSchin 			if (pp.control <= pp.in->control)
337*da2e3ebdSchin 			{
338*da2e3ebdSchin 				error(2, "no matching #%s for #%s", dirname(IF), dirname(ELIF));
339*da2e3ebdSchin 				goto eatdirective;
340*da2e3ebdSchin 			}
341*da2e3ebdSchin 			if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
342*da2e3ebdSchin 			if (*pp.control & HADELSE)
343*da2e3ebdSchin 			{
344*da2e3ebdSchin 				error(2, "invalid #%s after #%s", dirname(ELIF), dirname(ELSE));
345*da2e3ebdSchin 				*pp.control |= SKIP;
346*da2e3ebdSchin 				goto eatdirective;
347*da2e3ebdSchin 			}
348*da2e3ebdSchin 			if (*pp.control & KEPT)
349*da2e3ebdSchin 			{
350*da2e3ebdSchin 				*pp.control |= SKIP;
351*da2e3ebdSchin 				goto eatdirective;
352*da2e3ebdSchin 			}
353*da2e3ebdSchin 			if (directive == IFDEF || directive == IFNDEF)
354*da2e3ebdSchin 			{
355*da2e3ebdSchin 				*pp.control &= ~SKIP;
356*da2e3ebdSchin 				goto else_ifdef;
357*da2e3ebdSchin 			}
358*da2e3ebdSchin 		conditional:
359*da2e3ebdSchin 			if (ppexpr(&i1))
360*da2e3ebdSchin 			{
361*da2e3ebdSchin 				*pp.control &= ~SKIP;
362*da2e3ebdSchin 				*pp.control |= KEPT;
363*da2e3ebdSchin 			}
364*da2e3ebdSchin 			else *pp.control |= SKIP;
365*da2e3ebdSchin 			c = (pp.state & NEWLINE) ? '\n' : ' ';
366*da2e3ebdSchin 			goto eatdirective;
367*da2e3ebdSchin 		case ELSE:
368*da2e3ebdSchin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
369*da2e3ebdSchin 				goto eatdirective;
370*da2e3ebdSchin 			if ((pp.option & ELSEIF) && (c = pplex()) == T_ID && ((n = (int)hashref(pp.dirtab, pp.token)) == IF || n == IFDEF || n == IFNDEF))
371*da2e3ebdSchin 			{
372*da2e3ebdSchin 				error(1, "#%s %s is non-standard -- use #%s", dirname(directive), dirname(n), dirname(ELIF));
373*da2e3ebdSchin 				directive = n;
374*da2e3ebdSchin 				goto else_if;
375*da2e3ebdSchin 			}
376*da2e3ebdSchin 			if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ELSE));
377*da2e3ebdSchin 			else
378*da2e3ebdSchin 			{
379*da2e3ebdSchin 				if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
380*da2e3ebdSchin 				if (!(*pp.control & KEPT))
381*da2e3ebdSchin 				{
382*da2e3ebdSchin 					*pp.control &= ~SKIP;
383*da2e3ebdSchin 					*pp.control |= HADELSE|KEPT;
384*da2e3ebdSchin 				}
385*da2e3ebdSchin 				else
386*da2e3ebdSchin 				{
387*da2e3ebdSchin 					if (*pp.control & HADELSE) error(2, "more than one #%s for #%s", dirname(ELSE), dirname(IF));
388*da2e3ebdSchin 					*pp.control |= HADELSE|SKIP;
389*da2e3ebdSchin 				}
390*da2e3ebdSchin 			}
391*da2e3ebdSchin 			goto enddirective;
392*da2e3ebdSchin 		case ENDIF:
393*da2e3ebdSchin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
394*da2e3ebdSchin 				goto eatdirective;
395*da2e3ebdSchin 			if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ENDIF));
396*da2e3ebdSchin 			else if (--pp.control == pp.in->control && pp.in->symbol)
397*da2e3ebdSchin 			{
398*da2e3ebdSchin 				if (pp.in->flags & IN_endguard) pp.in->flags |= IN_noguard;
399*da2e3ebdSchin 				else
400*da2e3ebdSchin 				{
401*da2e3ebdSchin 					pp.in->flags &= ~IN_tokens;
402*da2e3ebdSchin 					pp.in->flags |= IN_endguard;
403*da2e3ebdSchin 				}
404*da2e3ebdSchin 			}
405*da2e3ebdSchin 			goto enddirective;
406*da2e3ebdSchin 		case IF:
407*da2e3ebdSchin 		case IFDEF:
408*da2e3ebdSchin 		case IFNDEF:
409*da2e3ebdSchin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
410*da2e3ebdSchin 				goto eatdirective;
411*da2e3ebdSchin 			pushcontrol();
412*da2e3ebdSchin 			SETIFBLOCK(pp.control);
413*da2e3ebdSchin 			if (*pp.control & SKIP)
414*da2e3ebdSchin 			{
415*da2e3ebdSchin 				*pp.control |= KEPT;
416*da2e3ebdSchin 				goto eatdirective;
417*da2e3ebdSchin 			}
418*da2e3ebdSchin 			if (directive == IF) goto conditional;
419*da2e3ebdSchin 		else_ifdef:
420*da2e3ebdSchin 			if ((c = pplex()) == T_ID)
421*da2e3ebdSchin 			{
422*da2e3ebdSchin 				sym = pprefmac(pp.token, REF_IF);
423*da2e3ebdSchin 				if (directive == IFNDEF && pp.control == pp.in->control + 1)
424*da2e3ebdSchin 				{
425*da2e3ebdSchin 					if (pp.in->flags & (IN_defguard|IN_endguard))
426*da2e3ebdSchin 						pp.in->flags |= IN_noguard;
427*da2e3ebdSchin 					else
428*da2e3ebdSchin 					{
429*da2e3ebdSchin 						pp.in->flags |= IN_defguard;
430*da2e3ebdSchin 						if (!(pp.in->flags & IN_tokens))
431*da2e3ebdSchin 							pp.in->symbol = sym ? sym : pprefmac(pp.token, REF_CREATE);
432*da2e3ebdSchin 					}
433*da2e3ebdSchin 				}
434*da2e3ebdSchin 			}
435*da2e3ebdSchin 			else
436*da2e3ebdSchin 			{
437*da2e3ebdSchin 				sym = 0;
438*da2e3ebdSchin 				if (!(pp.mode & HOSTED))
439*da2e3ebdSchin 					error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
440*da2e3ebdSchin 			}
441*da2e3ebdSchin 			*pp.control |= ((sym != 0) == (directive == IFDEF)) ? KEPT : SKIP;
442*da2e3ebdSchin 			goto enddirective;
443*da2e3ebdSchin 		case INCLUDE:
444*da2e3ebdSchin 			if (*pp.control & SKIP)
445*da2e3ebdSchin 			{
446*da2e3ebdSchin 				pp.state |= HEADER;
447*da2e3ebdSchin 				c = pplex();
448*da2e3ebdSchin 				pp.state &= ~HEADER;
449*da2e3ebdSchin 				goto eatdirective;
450*da2e3ebdSchin 			}
451*da2e3ebdSchin 			pp.state &= ~DISABLE;
452*da2e3ebdSchin 			pp.state |= HEADER|STRIP;
453*da2e3ebdSchin 			switch (c = pplex())
454*da2e3ebdSchin 			{
455*da2e3ebdSchin 			case T_STRING:
456*da2e3ebdSchin 				p = pp.token;
457*da2e3ebdSchin 				do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING);
458*da2e3ebdSchin 				*pp.token = 0;
459*da2e3ebdSchin 				pp.token = p;
460*da2e3ebdSchin 				/*FALLTHROUGH*/
461*da2e3ebdSchin 			case T_HEADER:
462*da2e3ebdSchin 			header:
463*da2e3ebdSchin 				if (!*pp.token)
464*da2e3ebdSchin 				{
465*da2e3ebdSchin 					error(2, "#%s: null file name", dirname(INCLUDE));
466*da2e3ebdSchin 					break;
467*da2e3ebdSchin 				}
468*da2e3ebdSchin 				if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX)))
469*da2e3ebdSchin 					error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token);
470*da2e3ebdSchin 				n = ppsearch(pp.token, c, SEARCH_INCLUDE);
471*da2e3ebdSchin 				break;
472*da2e3ebdSchin 			case '<':
473*da2e3ebdSchin 				/*
474*da2e3ebdSchin 				 * HEADEREXPAND|HEADEREXPANDALL gets us here
475*da2e3ebdSchin 				 */
476*da2e3ebdSchin 
477*da2e3ebdSchin 				if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0)))
478*da2e3ebdSchin 					error(3, "out of space");
479*da2e3ebdSchin 				pp.state &= ~NOSPACE;
480*da2e3ebdSchin 				while ((c = pplex()) && c != '>')
481*da2e3ebdSchin 				{
482*da2e3ebdSchin 					v = p + 1;
483*da2e3ebdSchin 					STRCOPY(p, pp.token, s);
484*da2e3ebdSchin 					if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO)
485*da2e3ebdSchin 						p--;
486*da2e3ebdSchin 				}
487*da2e3ebdSchin 				pp.state |= NOSPACE;
488*da2e3ebdSchin 				*p++ = 0;
489*da2e3ebdSchin 				memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf);
490*da2e3ebdSchin 				c = T_HEADER;
491*da2e3ebdSchin 				goto header;
492*da2e3ebdSchin 			default:
493*da2e3ebdSchin 				error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE));
494*da2e3ebdSchin 				goto eatdirective;
495*da2e3ebdSchin 			}
496*da2e3ebdSchin 			goto enddirective;
497*da2e3ebdSchin 		case 0:
498*da2e3ebdSchin 			{
499*da2e3ebdSchin 				regmatch_t	match[10];
500*da2e3ebdSchin 
501*da2e3ebdSchin 				/*UNDENT*/
502*da2e3ebdSchin 	p = pp.valbuf;
503*da2e3ebdSchin 	*p++ = '#';
504*da2e3ebdSchin 	STRCOPY(p, pp.token, s);
505*da2e3ebdSchin 	p0 = p;
506*da2e3ebdSchin 	pp.mode |= EXPOSE;
507*da2e3ebdSchin 	pp.state |= HEADER;
508*da2e3ebdSchin 	p6 = getline(p, &pp.valbuf[MAXTOKEN], 0);
509*da2e3ebdSchin 	pp.state &= ~HEADER;
510*da2e3ebdSchin 	pp.mode &= ~EXPOSE;
511*da2e3ebdSchin 	if (!p6)
512*da2e3ebdSchin 	{
513*da2e3ebdSchin 		*p0 = 0;
514*da2e3ebdSchin 		error(2, "%s: directive too long", pp.valbuf);
515*da2e3ebdSchin 		c = 0;
516*da2e3ebdSchin 		goto eatdirective;
517*da2e3ebdSchin 	}
518*da2e3ebdSchin 	p1 = p2 = p3 = p4 = 0;
519*da2e3ebdSchin 	p5 = *p ? p + 1 : 0;
520*da2e3ebdSchin  checkmap:
521*da2e3ebdSchin 	i0 = *p0;
522*da2e3ebdSchin 	p = pp.valbuf;
523*da2e3ebdSchin 	var.best = 0;
524*da2e3ebdSchin 	n = 0;
525*da2e3ebdSchin 	for (map = (struct map*)pp.maps; map; map = map->next)
526*da2e3ebdSchin 		if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0)))
527*da2e3ebdSchin 		{
528*da2e3ebdSchin 			if ((c = match[0].rm_eo - match[0].rm_so) > n)
529*da2e3ebdSchin 			{
530*da2e3ebdSchin 				n = c;
531*da2e3ebdSchin 				var.best = map;
532*da2e3ebdSchin 			}
533*da2e3ebdSchin 		}
534*da2e3ebdSchin 		else if (i1 != REG_NOMATCH)
535*da2e3ebdSchin 			regfatal(&map->re, 3, i1);
536*da2e3ebdSchin 	c = '\n';
537*da2e3ebdSchin 	if (map = var.best)
538*da2e3ebdSchin 	{
539*da2e3ebdSchin 		if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX)))
540*da2e3ebdSchin 		{
541*da2e3ebdSchin 			*p0 = 0;
542*da2e3ebdSchin 			if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA)))
543*da2e3ebdSchin 				error(1, "%s: non-standard directive", p);
544*da2e3ebdSchin 			*p0 = i0;
545*da2e3ebdSchin 		}
546*da2e3ebdSchin 		if (!(*pp.control & SKIP))
547*da2e3ebdSchin 		{
548*da2e3ebdSchin 			n = 0;
549*da2e3ebdSchin 			for (edit = map->edit; edit; edit = edit->next)
550*da2e3ebdSchin 				if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0)))
551*da2e3ebdSchin 				{
552*da2e3ebdSchin 					n++;
553*da2e3ebdSchin 					if (i0 = regsubexec(&edit->re, p, elementsof(match), match))
554*da2e3ebdSchin 						regfatal(&edit->re, 3, i0);
555*da2e3ebdSchin 					p = edit->re.re_sub->re_buf;
556*da2e3ebdSchin 					if (edit->re.re_sub->re_flags & REG_SUB_STOP)
557*da2e3ebdSchin 						break;
558*da2e3ebdSchin 				}
559*da2e3ebdSchin 				else if (i0 != REG_NOMATCH)
560*da2e3ebdSchin 					regfatal(&edit->re, 3, i0);
561*da2e3ebdSchin 			if (n && *p)
562*da2e3ebdSchin 			{
563*da2e3ebdSchin 				p1 = s = oldof(0, char, 0, strlen(p) + 32);
564*da2e3ebdSchin 				while (*s = *p++) s++;
565*da2e3ebdSchin 				debug((-4, "map: %s", p1));
566*da2e3ebdSchin 				*s++ = '\n';
567*da2e3ebdSchin 				*s = 0;
568*da2e3ebdSchin 				error_info.line++;
569*da2e3ebdSchin 				PUSH_RESCAN(p1);
570*da2e3ebdSchin 				error_info.line--;
571*da2e3ebdSchin 				directive = LINE;
572*da2e3ebdSchin 			}
573*da2e3ebdSchin 		}
574*da2e3ebdSchin 		goto donedirective;
575*da2e3ebdSchin 	}
576*da2e3ebdSchin 	if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX))))
577*da2e3ebdSchin 	{
578*da2e3ebdSchin 		*p0 = 0;
579*da2e3ebdSchin 		error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0));
580*da2e3ebdSchin 		*p0 = i0;
581*da2e3ebdSchin 	}
582*da2e3ebdSchin  pass:
583*da2e3ebdSchin 	if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT)))
584*da2e3ebdSchin 	{
585*da2e3ebdSchin 		*p0 = 0;
586*da2e3ebdSchin 		if (p2) *p2 = 0;
587*da2e3ebdSchin 		if (p4)
588*da2e3ebdSchin 		{
589*da2e3ebdSchin 			if (p4 == p5)
590*da2e3ebdSchin 			{
591*da2e3ebdSchin 				p5 = strcpy(pp.tmpbuf, p5);
592*da2e3ebdSchin 				if (p = strchr(p5, MARK))
593*da2e3ebdSchin 				{
594*da2e3ebdSchin 					s = p;
595*da2e3ebdSchin 					while (*p)
596*da2e3ebdSchin 						if ((*s++ = *p++) == MARK && *p == MARK) p++;
597*da2e3ebdSchin 					*s = 0;
598*da2e3ebdSchin 				}
599*da2e3ebdSchin 			}
600*da2e3ebdSchin 			*p4 = 0;
601*da2e3ebdSchin 		}
602*da2e3ebdSchin 		if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1))
603*da2e3ebdSchin 		{
604*da2e3ebdSchin 			s = p;
605*da2e3ebdSchin 			while (p < p6) switch (*s++ = *p++)
606*da2e3ebdSchin 			{
607*da2e3ebdSchin 			case 0:
608*da2e3ebdSchin 				s = p;
609*da2e3ebdSchin 				break;
610*da2e3ebdSchin 			case MARK:
611*da2e3ebdSchin 				p++;
612*da2e3ebdSchin 				break;
613*da2e3ebdSchin 			}
614*da2e3ebdSchin 			*s = 0;
615*da2e3ebdSchin 		}
616*da2e3ebdSchin 		(*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0);
617*da2e3ebdSchin 		emitted = 1;
618*da2e3ebdSchin 	}
619*da2e3ebdSchin 	goto donedirective;
620*da2e3ebdSchin 
621*da2e3ebdSchin 				/*INDENT*/
622*da2e3ebdSchin 			}
623*da2e3ebdSchin 		}
624*da2e3ebdSchin 		if (*pp.control & SKIP) goto eatdirective;
625*da2e3ebdSchin 		switch (directive)
626*da2e3ebdSchin 		{
627*da2e3ebdSchin #if MACDEF
628*da2e3ebdSchin 		case ENDMAC:
629*da2e3ebdSchin 			c = pplex();
630*da2e3ebdSchin 			error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC));
631*da2e3ebdSchin 			goto enddirective;
632*da2e3ebdSchin #endif
633*da2e3ebdSchin #if MACDEF
634*da2e3ebdSchin 		case MACDEF:
635*da2e3ebdSchin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
636*da2e3ebdSchin 				error(1, "#%s: non-standard directive", pp.token);
637*da2e3ebdSchin 			/*FALLTHROUGH*/
638*da2e3ebdSchin #endif
639*da2e3ebdSchin 		case DEFINE:
640*da2e3ebdSchin 			n2 = error_info.line;
641*da2e3ebdSchin 			if ((c = pplex()) == '#' && directive == DEFINE)
642*da2e3ebdSchin 				goto assertion;
643*da2e3ebdSchin 			if (c == '<')
644*da2e3ebdSchin 			{
645*da2e3ebdSchin 				n = 1;
646*da2e3ebdSchin 				c = pplex();
647*da2e3ebdSchin 			}
648*da2e3ebdSchin 			else
649*da2e3ebdSchin 				n = 0;
650*da2e3ebdSchin 			if (!(sym = macsym(c)))
651*da2e3ebdSchin 				goto eatdirective;
652*da2e3ebdSchin 			if (pp.truncate)
653*da2e3ebdSchin 				ppfsm(FSM_MACRO, pp.token);
654*da2e3ebdSchin 			mac = sym->macro;
655*da2e3ebdSchin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value)
656*da2e3ebdSchin 				goto eatdirective;
657*da2e3ebdSchin 			if (n)
658*da2e3ebdSchin 				goto tuple;
659*da2e3ebdSchin 			old = *mac;
660*da2e3ebdSchin 			i0 = sym->flags;
661*da2e3ebdSchin 			sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
662*da2e3ebdSchin #if MACDEF
663*da2e3ebdSchin 			if (directive == MACDEF)
664*da2e3ebdSchin 				sym->flags |= SYM_MULTILINE;
665*da2e3ebdSchin #endif
666*da2e3ebdSchin 			mac->arity = 0;
667*da2e3ebdSchin 			mac->formals = 0;
668*da2e3ebdSchin 			mac->value = 0;
669*da2e3ebdSchin 			pp.state &= ~NOSPACE;
670*da2e3ebdSchin 			pp.state |= DEFINITION|NOEXPAND;
671*da2e3ebdSchin 			switch (c = pplex())
672*da2e3ebdSchin 			{
673*da2e3ebdSchin 			case '(':
674*da2e3ebdSchin 				sym->flags |= SYM_FUNCTION;
675*da2e3ebdSchin 				pp.state |= NOSPACE;
676*da2e3ebdSchin #if MACKEYARGS
677*da2e3ebdSchin 				if (pp.option & KEYARGS)
678*da2e3ebdSchin 				{
679*da2e3ebdSchin 					n = 2 * MAXTOKEN;
680*da2e3ebdSchin 					p = mac->formals = oldof(0, char, 0, n);
681*da2e3ebdSchin 					if ((c = pplex()) == T_ID) for (;;)
682*da2e3ebdSchin 					{
683*da2e3ebdSchin 						if (mac->arity < MAXFORMALS)
684*da2e3ebdSchin 						{
685*da2e3ebdSchin 							if (mac->arity) p++;
686*da2e3ebdSchin 							formargs[mac->arity] = p;
687*da2e3ebdSchin 							STRAPP(p, pp.token, s);
688*da2e3ebdSchin 							formvals[mac->arity++] = p1 = p;
689*da2e3ebdSchin 							if (mac->arity == 1) *p++ = ' ';
690*da2e3ebdSchin 							*p++ = ' ';
691*da2e3ebdSchin 							*p = 0;
692*da2e3ebdSchin 						}
693*da2e3ebdSchin 						else error(2, "%s: formal argument %s ignored", sym->name, pp.token);
694*da2e3ebdSchin 						switch (c = pplex())
695*da2e3ebdSchin 						{
696*da2e3ebdSchin 						case '=':
697*da2e3ebdSchin 							c = pplex();
698*da2e3ebdSchin 							break;
699*da2e3ebdSchin 						case ',':
700*da2e3ebdSchin 							break;
701*da2e3ebdSchin 						default:
702*da2e3ebdSchin 							goto endformals;
703*da2e3ebdSchin 						}
704*da2e3ebdSchin 						pp.state &= ~NOSPACE;
705*da2e3ebdSchin 						p0 = 0;
706*da2e3ebdSchin 						for (;;)
707*da2e3ebdSchin 						{
708*da2e3ebdSchin 							switch (c)
709*da2e3ebdSchin 							{
710*da2e3ebdSchin 							case '\n':
711*da2e3ebdSchin 								goto endformals;
712*da2e3ebdSchin 							case '(':
713*da2e3ebdSchin 								p0++;
714*da2e3ebdSchin 								break;
715*da2e3ebdSchin 							case ')':
716*da2e3ebdSchin 								if (!p0--)
717*da2e3ebdSchin 								{
718*da2e3ebdSchin 									if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
719*da2e3ebdSchin 									goto endformals;
720*da2e3ebdSchin 								}
721*da2e3ebdSchin 								break;
722*da2e3ebdSchin 							case ',':
723*da2e3ebdSchin 								if (!p0)
724*da2e3ebdSchin 								{
725*da2e3ebdSchin 									if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
726*da2e3ebdSchin 									goto nextformal;
727*da2e3ebdSchin 								}
728*da2e3ebdSchin 								break;
729*da2e3ebdSchin 							case ' ':
730*da2e3ebdSchin 								if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue;
731*da2e3ebdSchin 								break;
732*da2e3ebdSchin 							}
733*da2e3ebdSchin 							STRCOPY(p, pp.token, s);
734*da2e3ebdSchin 							if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals)
735*da2e3ebdSchin 							{
736*da2e3ebdSchin 								n1 = s - mac->formals;
737*da2e3ebdSchin 								for (n = 0; n < mac->arity; n++)
738*da2e3ebdSchin 								{
739*da2e3ebdSchin 									formargs[n] += n1;
740*da2e3ebdSchin 									formvals[n] += n1;
741*da2e3ebdSchin 								}
742*da2e3ebdSchin 								c = p - mac->formals;
743*da2e3ebdSchin 								mac->formals = s;
744*da2e3ebdSchin 								p = mac->formals + c;
745*da2e3ebdSchin 							}
746*da2e3ebdSchin 							c = pplex();
747*da2e3ebdSchin 						}
748*da2e3ebdSchin 					nextformal:
749*da2e3ebdSchin 						pp.state |= NOSPACE;
750*da2e3ebdSchin 						if ((c = pplex()) != T_ID)
751*da2e3ebdSchin 						{
752*da2e3ebdSchin 							c = ',';
753*da2e3ebdSchin 							break;
754*da2e3ebdSchin 						}
755*da2e3ebdSchin 					}
756*da2e3ebdSchin 				endformals: /*NOP*/;
757*da2e3ebdSchin 				}
758*da2e3ebdSchin 				else
759*da2e3ebdSchin #endif
760*da2e3ebdSchin 				{
761*da2e3ebdSchin 					p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1));
762*da2e3ebdSchin 					c = pplex();
763*da2e3ebdSchin #if COMPATIBLE
764*da2e3ebdSchin 					if ((pp.state & COMPATIBILITY) && c == ',')
765*da2e3ebdSchin 					{
766*da2e3ebdSchin 						if ((pp.state & WARN) && !(pp.mode & HOSTED))
767*da2e3ebdSchin 							error(1, "%s: macro formal argument expected", sym->name);
768*da2e3ebdSchin 						while ((c = pplex()) == ',');
769*da2e3ebdSchin 					}
770*da2e3ebdSchin #endif
771*da2e3ebdSchin 					for (;;)
772*da2e3ebdSchin 					{
773*da2e3ebdSchin 						if (c == T_VARIADIC)
774*da2e3ebdSchin 						{
775*da2e3ebdSchin 							if (sym->flags & SYM_VARIADIC)
776*da2e3ebdSchin 								error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
777*da2e3ebdSchin 							sym->flags |= SYM_VARIADIC;
778*da2e3ebdSchin 							v = __va_args__;
779*da2e3ebdSchin 						}
780*da2e3ebdSchin 						else if (c == T_ID)
781*da2e3ebdSchin 						{
782*da2e3ebdSchin 							v = pp.token;
783*da2e3ebdSchin 							if (sym->flags & SYM_VARIADIC)
784*da2e3ebdSchin 								error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v);
785*da2e3ebdSchin 							else if (streq(v, __va_args__))
786*da2e3ebdSchin 								error(2, "%s: %s: invalid macro formal argument", sym->name, v);
787*da2e3ebdSchin 						}
788*da2e3ebdSchin 						else
789*da2e3ebdSchin 							break;
790*da2e3ebdSchin 						if (mac->arity < MAXFORMALS)
791*da2e3ebdSchin 						{
792*da2e3ebdSchin 							for (n = 0; n < mac->arity; n++)
793*da2e3ebdSchin 								if (streq(formargs[n], v))
794*da2e3ebdSchin 									error(2, "%s: %s: duplicate macro formal argument", sym->name, v);
795*da2e3ebdSchin 							formargs[mac->arity++] = p;
796*da2e3ebdSchin 							STRAPP(p, v, s);
797*da2e3ebdSchin 						}
798*da2e3ebdSchin 						else
799*da2e3ebdSchin 							error(2, "%s: %s: macro formal argument ignored", sym->name, v);
800*da2e3ebdSchin 						if ((c = pplex()) == ',')
801*da2e3ebdSchin 						{
802*da2e3ebdSchin 							c = pplex();
803*da2e3ebdSchin #if COMPATIBLE
804*da2e3ebdSchin 							if ((pp.state & COMPATIBILITY) && c == ',')
805*da2e3ebdSchin 							{
806*da2e3ebdSchin 								if ((pp.state & WARN) && !(pp.mode & HOSTED))
807*da2e3ebdSchin 									error(1, "%s: macro formal argument expected", sym->name);
808*da2e3ebdSchin 								while ((c = pplex()) == ',');
809*da2e3ebdSchin 							}
810*da2e3ebdSchin #endif
811*da2e3ebdSchin 						}
812*da2e3ebdSchin 						else if (c != T_VARIADIC)
813*da2e3ebdSchin 							break;
814*da2e3ebdSchin 						else
815*da2e3ebdSchin 						{
816*da2e3ebdSchin 							if (sym->flags & SYM_VARIADIC)
817*da2e3ebdSchin 								error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
818*da2e3ebdSchin 							sym->flags |= SYM_VARIADIC;
819*da2e3ebdSchin 							c = pplex();
820*da2e3ebdSchin 							break;
821*da2e3ebdSchin 						}
822*da2e3ebdSchin 					}
823*da2e3ebdSchin 					if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals)
824*da2e3ebdSchin 					{
825*da2e3ebdSchin 						n1 = s - mac->formals;
826*da2e3ebdSchin 						for (n = 0; n < mac->arity; n++)
827*da2e3ebdSchin 							formargs[n] += n1;
828*da2e3ebdSchin 						mac->formals = s;
829*da2e3ebdSchin 					}
830*da2e3ebdSchin 				}
831*da2e3ebdSchin 				if (!mac->arity)
832*da2e3ebdSchin 				{
833*da2e3ebdSchin 					free(mac->formals);
834*da2e3ebdSchin 					mac->formals = 0;
835*da2e3ebdSchin 				}
836*da2e3ebdSchin 				switch (c)
837*da2e3ebdSchin 				{
838*da2e3ebdSchin 				case ')':
839*da2e3ebdSchin #if MACKEYARGS
840*da2e3ebdSchin 					pp.state |= NOEXPAND|NOSPACE;
841*da2e3ebdSchin #else
842*da2e3ebdSchin 					pp.state |= NOEXPAND;
843*da2e3ebdSchin #endif
844*da2e3ebdSchin 					c = pplex();
845*da2e3ebdSchin 					break;
846*da2e3ebdSchin 				default:
847*da2e3ebdSchin 					error(2, "%s: invalid macro formal argument list", sym->name);
848*da2e3ebdSchin 					if (mac->formals)
849*da2e3ebdSchin 					{
850*da2e3ebdSchin 						free(mac->formals);
851*da2e3ebdSchin 						mac->formals = 0;
852*da2e3ebdSchin 						mac->arity = 0;
853*da2e3ebdSchin 					}
854*da2e3ebdSchin 					free(mac);
855*da2e3ebdSchin 					sym->macro = 0;
856*da2e3ebdSchin 					goto eatdirective;
857*da2e3ebdSchin 				}
858*da2e3ebdSchin 				pp.state &= ~NOSPACE;
859*da2e3ebdSchin 				break;
860*da2e3ebdSchin 			case ' ':
861*da2e3ebdSchin 			case '\t':
862*da2e3ebdSchin 				c = pplex();
863*da2e3ebdSchin 				break;
864*da2e3ebdSchin 			}
865*da2e3ebdSchin 			n = 2 * MAXTOKEN;
866*da2e3ebdSchin #if MACKEYARGS
867*da2e3ebdSchin 			p1 = p;
868*da2e3ebdSchin #endif
869*da2e3ebdSchin 			p = mac->value = oldof(0, char, 0, n);
870*da2e3ebdSchin 			var.type = 0;
871*da2e3ebdSchin 			n1 = 0;
872*da2e3ebdSchin #if MACDEF
873*da2e3ebdSchin 			i2 = i3 = 0;
874*da2e3ebdSchin 			n3 = pp.state;
875*da2e3ebdSchin #endif
876*da2e3ebdSchin 			if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
877*da2e3ebdSchin 				switch (c)
878*da2e3ebdSchin 				{
879*da2e3ebdSchin 				case '+':
880*da2e3ebdSchin 				case '-':
881*da2e3ebdSchin 				case '&':
882*da2e3ebdSchin 				case '|':
883*da2e3ebdSchin 				case '<':
884*da2e3ebdSchin 				case '>':
885*da2e3ebdSchin 				case ':':
886*da2e3ebdSchin 				case '=':
887*da2e3ebdSchin 					*p++ = ' ';
888*da2e3ebdSchin 					break;
889*da2e3ebdSchin 				}
890*da2e3ebdSchin 			o = 0;
891*da2e3ebdSchin 			for (;;)
892*da2e3ebdSchin 			{
893*da2e3ebdSchin 				switch (c)
894*da2e3ebdSchin 				{
895*da2e3ebdSchin 				case T_ID:
896*da2e3ebdSchin 					for (c = 0; c < mac->arity; c++)
897*da2e3ebdSchin 						if (streq(formargs[c], pp.token))
898*da2e3ebdSchin 						{
899*da2e3ebdSchin #if COMPATIBLE
900*da2e3ebdSchin 							if (!(pp.state & COMPATIBILITY))
901*da2e3ebdSchin #endif
902*da2e3ebdSchin 							if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' ';
903*da2e3ebdSchin 							*p++ = MARK;
904*da2e3ebdSchin #if COMPATIBLE
905*da2e3ebdSchin 							if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C';
906*da2e3ebdSchin 							else
907*da2e3ebdSchin #endif
908*da2e3ebdSchin 							*p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A';
909*da2e3ebdSchin 							*p++ = c + ARGOFFSET;
910*da2e3ebdSchin 							var.type = TOK_FORMAL|TOK_ID;
911*da2e3ebdSchin 							c = '>';
912*da2e3ebdSchin 							goto checkvalue;
913*da2e3ebdSchin 						}
914*da2e3ebdSchin 					if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token))
915*da2e3ebdSchin 					{
916*da2e3ebdSchin 					case V_DEFAULT:
917*da2e3ebdSchin 					case V_EMPTY:
918*da2e3ebdSchin 						sym->flags |= SYM_EMPTY;
919*da2e3ebdSchin 						break;
920*da2e3ebdSchin 					}
921*da2e3ebdSchin 					else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden)
922*da2e3ebdSchin 					{
923*da2e3ebdSchin 						for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev);
924*da2e3ebdSchin 						p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token);
925*da2e3ebdSchin 						var.type = TOK_ID;
926*da2e3ebdSchin 						goto checkvalue;
927*da2e3ebdSchin 					}
928*da2e3ebdSchin 					var.type = TOK_ID;
929*da2e3ebdSchin 					break;
930*da2e3ebdSchin 				case '#':
931*da2e3ebdSchin 					var.type = 0;
932*da2e3ebdSchin #if MACDEF
933*da2e3ebdSchin 					if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break;
934*da2e3ebdSchin #else
935*da2e3ebdSchin 					if (!(sym->flags & SYM_FUNCTION)) break;
936*da2e3ebdSchin #endif
937*da2e3ebdSchin 					pp.state |= NOSPACE;
938*da2e3ebdSchin 					c = pplex();
939*da2e3ebdSchin 					if (c == '@')
940*da2e3ebdSchin 					{
941*da2e3ebdSchin 						c = pplex();
942*da2e3ebdSchin 						i4 = 'S';
943*da2e3ebdSchin 					}
944*da2e3ebdSchin 					else i4 = 'Q';
945*da2e3ebdSchin 					pp.state &= ~NOSPACE;
946*da2e3ebdSchin 					if (c != T_ID) c = mac->arity;
947*da2e3ebdSchin 					else for (c = 0; c < mac->arity; c++)
948*da2e3ebdSchin 						if (streq(formargs[c], pp.token))
949*da2e3ebdSchin 							break;
950*da2e3ebdSchin 					if (c >= mac->arity)
951*da2e3ebdSchin 					{
952*da2e3ebdSchin #if MACDEF
953*da2e3ebdSchin 						if (sym->flags & SYM_MULTILINE)
954*da2e3ebdSchin 						{
955*da2e3ebdSchin 							if (n3 & NEWLINE)
956*da2e3ebdSchin 							{
957*da2e3ebdSchin 								pp.state &= ~NOEXPAND;
958*da2e3ebdSchin 								switch ((int)hashref(pp.dirtab, pp.token))
959*da2e3ebdSchin 								{
960*da2e3ebdSchin 								case ENDMAC:
961*da2e3ebdSchin 									if (!i2--) goto gotdefinition;
962*da2e3ebdSchin 									break;
963*da2e3ebdSchin 								case INCLUDE:
964*da2e3ebdSchin 									/* PARSE HEADER constant */
965*da2e3ebdSchin 									break;
966*da2e3ebdSchin 								case MACDEF:
967*da2e3ebdSchin 									i2++;
968*da2e3ebdSchin 									break;
969*da2e3ebdSchin 								}
970*da2e3ebdSchin 								*p++ = '#';
971*da2e3ebdSchin 							}
972*da2e3ebdSchin 						}
973*da2e3ebdSchin 						else
974*da2e3ebdSchin #endif
975*da2e3ebdSchin #if COMPATIBLE
976*da2e3ebdSchin 						if (pp.state & COMPATIBILITY) *p++ = '#';
977*da2e3ebdSchin 						else
978*da2e3ebdSchin #endif
979*da2e3ebdSchin 						error(2, "# must precede a formal parameter");
980*da2e3ebdSchin 					}
981*da2e3ebdSchin 					else
982*da2e3ebdSchin 					{
983*da2e3ebdSchin 						if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' ';
984*da2e3ebdSchin 						*p++ = MARK;
985*da2e3ebdSchin 						*p++ = i4;
986*da2e3ebdSchin 						*p++ = c + ARGOFFSET;
987*da2e3ebdSchin 						goto checkvalue;
988*da2e3ebdSchin 					}
989*da2e3ebdSchin 					break;
990*da2e3ebdSchin 				case T_TOKCAT:
991*da2e3ebdSchin 					if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token);
992*da2e3ebdSchin 					else
993*da2e3ebdSchin 					{
994*da2e3ebdSchin 						if (*(p - 1) == ' ') p--;
995*da2e3ebdSchin 						if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
996*da2e3ebdSchin 					}
997*da2e3ebdSchin 					pp.state |= NOSPACE;
998*da2e3ebdSchin 					c = pplex();
999*da2e3ebdSchin 					pp.state &= ~NOSPACE;
1000*da2e3ebdSchin 					if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT));
1001*da2e3ebdSchin 					var.type = TOK_TOKCAT;
1002*da2e3ebdSchin 					continue;
1003*da2e3ebdSchin 				case '(':
1004*da2e3ebdSchin 					if (*pp.token == '#')
1005*da2e3ebdSchin 					{
1006*da2e3ebdSchin 						var.type = TOK_BUILTIN;
1007*da2e3ebdSchin 						n1++;
1008*da2e3ebdSchin 					}
1009*da2e3ebdSchin 					else
1010*da2e3ebdSchin 					{
1011*da2e3ebdSchin 						var.type = 0;
1012*da2e3ebdSchin 						if (n1) n1++;
1013*da2e3ebdSchin 					}
1014*da2e3ebdSchin 					break;
1015*da2e3ebdSchin 				case ')':
1016*da2e3ebdSchin 					var.type = 0;
1017*da2e3ebdSchin 					if (n1) n1--;
1018*da2e3ebdSchin 					break;
1019*da2e3ebdSchin 				case T_STRING:
1020*da2e3ebdSchin 				case T_CHARCONST:
1021*da2e3ebdSchin 					pp.state &= ~NOEXPAND;
1022*da2e3ebdSchin 					var.type = 0;
1023*da2e3ebdSchin 					if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND;
1024*da2e3ebdSchin #if COMPATIBLE
1025*da2e3ebdSchin 					/*UNDENT*/
1026*da2e3ebdSchin 
1027*da2e3ebdSchin 	if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION)))
1028*da2e3ebdSchin 	{
1029*da2e3ebdSchin 		char*	v;
1030*da2e3ebdSchin 
1031*da2e3ebdSchin 		s = pp.token;
1032*da2e3ebdSchin 		for (;;)
1033*da2e3ebdSchin 		{
1034*da2e3ebdSchin 			if (!*s) goto checkvalue;
1035*da2e3ebdSchin 			if (ppisid(*s))
1036*da2e3ebdSchin 			{
1037*da2e3ebdSchin 				v = s;
1038*da2e3ebdSchin 				while (ppisid(*++s));
1039*da2e3ebdSchin 				i1 = *s;
1040*da2e3ebdSchin 				*s = 0;
1041*da2e3ebdSchin 				for (c = 0; c < mac->arity; c++)
1042*da2e3ebdSchin 					if (streq(formargs[c], v))
1043*da2e3ebdSchin 					{
1044*da2e3ebdSchin 						*p++ = MARK;
1045*da2e3ebdSchin 						*p++ = 'C';
1046*da2e3ebdSchin 						*p++ = c + ARGOFFSET;
1047*da2e3ebdSchin 						if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token)
1048*da2e3ebdSchin 						{
1049*da2e3ebdSchin 						case '"':
1050*da2e3ebdSchin 							error(1, "use the # operator to \"...\" quote macro arguments");
1051*da2e3ebdSchin 							break;
1052*da2e3ebdSchin 						case '\'':
1053*da2e3ebdSchin 							error(1, "macro arguments should be '...' quoted before substitution");
1054*da2e3ebdSchin 							break;
1055*da2e3ebdSchin 						}
1056*da2e3ebdSchin 						goto quotearg;
1057*da2e3ebdSchin 					}
1058*da2e3ebdSchin 				STRCOPY2(p, v);
1059*da2e3ebdSchin 			quotearg:
1060*da2e3ebdSchin 				*s = i1;
1061*da2e3ebdSchin 			}
1062*da2e3ebdSchin 			else *p++ = *s++;
1063*da2e3ebdSchin 		}
1064*da2e3ebdSchin 	}
1065*da2e3ebdSchin 					/*INDENT*/
1066*da2e3ebdSchin #endif
1067*da2e3ebdSchin 					break;
1068*da2e3ebdSchin 				case '\n':
1069*da2e3ebdSchin #if MACDEF
1070*da2e3ebdSchin 					if (sym->flags & SYM_MULTILINE)
1071*da2e3ebdSchin 					{
1072*da2e3ebdSchin 						if (pp.state & EOF2NL)
1073*da2e3ebdSchin 						{
1074*da2e3ebdSchin 							error_info.line++;
1075*da2e3ebdSchin 							pp.state |= HIDDEN;
1076*da2e3ebdSchin 							pp.hidden++;
1077*da2e3ebdSchin 							var.type = 0;
1078*da2e3ebdSchin 							if (!i3++)
1079*da2e3ebdSchin 								goto checkvalue;
1080*da2e3ebdSchin 							break;
1081*da2e3ebdSchin 						}
1082*da2e3ebdSchin 						pp.state |= EOF2NL;
1083*da2e3ebdSchin 						error(2, "%s: missing #%s", sym->name, dirname(ENDMAC));
1084*da2e3ebdSchin 					}
1085*da2e3ebdSchin #endif
1086*da2e3ebdSchin 					goto gotdefinition;
1087*da2e3ebdSchin 				case 0:
1088*da2e3ebdSchin 					c = '\n';
1089*da2e3ebdSchin 					goto gotdefinition;
1090*da2e3ebdSchin #if COMPATIBLE
1091*da2e3ebdSchin 				case ' ':
1092*da2e3ebdSchin 					if (pp.state & COMPATIBILITY) var.type = 0;
1093*da2e3ebdSchin 					if (pp.option & PRESERVE) break;
1094*da2e3ebdSchin 					if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
1095*da2e3ebdSchin 					goto checkvalue;
1096*da2e3ebdSchin 				case '\t':
1097*da2e3ebdSchin 					if (var.type & TOK_ID)
1098*da2e3ebdSchin 					{
1099*da2e3ebdSchin 						while ((c = pplex()) == '\t');
1100*da2e3ebdSchin 						if (c == T_ID)
1101*da2e3ebdSchin 						{
1102*da2e3ebdSchin 							if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
1103*da2e3ebdSchin 							var.type = TOK_TOKCAT;
1104*da2e3ebdSchin 							if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments");
1105*da2e3ebdSchin 						}
1106*da2e3ebdSchin 						else var.type = 0;
1107*da2e3ebdSchin 						continue;
1108*da2e3ebdSchin 					}
1109*da2e3ebdSchin 					var.type = 0;
1110*da2e3ebdSchin 					if (pp.option & PRESERVE) break;
1111*da2e3ebdSchin 					if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
1112*da2e3ebdSchin 					goto checkvalue;
1113*da2e3ebdSchin #endif
1114*da2e3ebdSchin 				case MARK:
1115*da2e3ebdSchin 					pp.state &= ~NOEXPAND;
1116*da2e3ebdSchin 					/*FALLTHROUGH*/
1117*da2e3ebdSchin 
1118*da2e3ebdSchin 				default:
1119*da2e3ebdSchin 					var.type = 0;
1120*da2e3ebdSchin 					break;
1121*da2e3ebdSchin 				}
1122*da2e3ebdSchin 				STRCOPY(p, pp.token, s);
1123*da2e3ebdSchin 			checkvalue:
1124*da2e3ebdSchin 				o = c;
1125*da2e3ebdSchin 				if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value)
1126*da2e3ebdSchin 				{
1127*da2e3ebdSchin 					c = p - mac->value;
1128*da2e3ebdSchin 					mac->value = s;
1129*da2e3ebdSchin 					p = mac->value + c;
1130*da2e3ebdSchin 				}
1131*da2e3ebdSchin #if MACDEF
1132*da2e3ebdSchin 				n3 = pp.state;
1133*da2e3ebdSchin #endif
1134*da2e3ebdSchin 				c = pplex();
1135*da2e3ebdSchin 			}
1136*da2e3ebdSchin 		gotdefinition:
1137*da2e3ebdSchin 			while (p > mac->value && *(p - 1) == ' ') p--;
1138*da2e3ebdSchin 			if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
1139*da2e3ebdSchin 				switch (o)
1140*da2e3ebdSchin 				{
1141*da2e3ebdSchin 				case '+':
1142*da2e3ebdSchin 				case '-':
1143*da2e3ebdSchin 				case '&':
1144*da2e3ebdSchin 				case '|':
1145*da2e3ebdSchin 				case '<':
1146*da2e3ebdSchin 				case '>':
1147*da2e3ebdSchin 				case ':':
1148*da2e3ebdSchin 				case '=':
1149*da2e3ebdSchin 					*p++ = ' ';
1150*da2e3ebdSchin 					break;
1151*da2e3ebdSchin 				}
1152*da2e3ebdSchin 			*p = 0;
1153*da2e3ebdSchin #if MACKEYARGS
1154*da2e3ebdSchin 			if (!mac->arity) /* ok */;
1155*da2e3ebdSchin 			else if (pp.option & KEYARGS)
1156*da2e3ebdSchin 			{
1157*da2e3ebdSchin 				p0 = mac->formals;
1158*da2e3ebdSchin 				mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1);
1159*da2e3ebdSchin 				s = (char*)&mac->formkeys[mac->arity];
1160*da2e3ebdSchin 				(void)memcpy(s, p0, p1 - p0 + 1);
1161*da2e3ebdSchin 				free(p0);
1162*da2e3ebdSchin 				for (n = 0; n < mac->arity; n++)
1163*da2e3ebdSchin 				{
1164*da2e3ebdSchin 					mac->formkeys[n].name = s + (formargs[n] - p0);
1165*da2e3ebdSchin 					mac->formkeys[n].value = s + (formvals[n] - p0);
1166*da2e3ebdSchin 				}
1167*da2e3ebdSchin 			}
1168*da2e3ebdSchin 			else
1169*da2e3ebdSchin #endif
1170*da2e3ebdSchin 			for (n = 1; n < mac->arity; n++)
1171*da2e3ebdSchin 				*(formargs[n] - 1) = ',';
1172*da2e3ebdSchin 			if (old.value)
1173*da2e3ebdSchin 			{
1174*da2e3ebdSchin 				if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined;
1175*da2e3ebdSchin 				if (!old.formals)
1176*da2e3ebdSchin 				{
1177*da2e3ebdSchin 					if (mac->formals) goto redefined;
1178*da2e3ebdSchin 				}
1179*da2e3ebdSchin 				else if (mac->formals)
1180*da2e3ebdSchin 				{
1181*da2e3ebdSchin #if MACKEYARGS
1182*da2e3ebdSchin 					if (pp.option & KEYARGS)
1183*da2e3ebdSchin 					{
1184*da2e3ebdSchin 						for (n = 0; n < mac->arity; n++)
1185*da2e3ebdSchin 							if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value))
1186*da2e3ebdSchin 								goto redefined;
1187*da2e3ebdSchin 					}
1188*da2e3ebdSchin 					else
1189*da2e3ebdSchin #endif
1190*da2e3ebdSchin 					if (!streq(mac->formals, old.formals)) goto redefined;
1191*da2e3ebdSchin 				}
1192*da2e3ebdSchin #if MACKEYARGS
1193*da2e3ebdSchin 				if (pp.option & KEYARGS)
1194*da2e3ebdSchin 				{
1195*da2e3ebdSchin 					if (mac->formkeys) free(mac->formkeys);
1196*da2e3ebdSchin 					mac->formkeys = old.formkeys;
1197*da2e3ebdSchin 				}
1198*da2e3ebdSchin 				else
1199*da2e3ebdSchin #endif
1200*da2e3ebdSchin 				{
1201*da2e3ebdSchin 					if (mac->formals) free(mac->formals);
1202*da2e3ebdSchin 					mac->formals = old.formals;
1203*da2e3ebdSchin 				}
1204*da2e3ebdSchin 				free(mac->value);
1205*da2e3ebdSchin 				mac->value = old.value;
1206*da2e3ebdSchin 				goto benign;
1207*da2e3ebdSchin 			redefined:
1208*da2e3ebdSchin 				if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL))
1209*da2e3ebdSchin 					error(1, "%s redefined", sym->name);
1210*da2e3ebdSchin #if MACKEYARGS
1211*da2e3ebdSchin 				if ((pp.option & KEYARGS) && mac->formkeys)
1212*da2e3ebdSchin 					free(mac->formkeys);
1213*da2e3ebdSchin #endif
1214*da2e3ebdSchin #if MACKEYARGS
1215*da2e3ebdSchin 				if (!(pp.option & KEYARGS))
1216*da2e3ebdSchin #endif
1217*da2e3ebdSchin 				if (old.formals) free(old.formals);
1218*da2e3ebdSchin 				free(old.value);
1219*da2e3ebdSchin 			}
1220*da2e3ebdSchin 			else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name);
1221*da2e3ebdSchin 			mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0);
1222*da2e3ebdSchin 			if ((pp.option & (DEFINITIONS|PREDEFINITIONS|REGUARD)) && !sym->hidden && !(sym->flags & SYM_MULTILINE) && ((pp.option & PREDEFINITIONS) || !(pp.mode & INIT)) && ((pp.option & (DEFINITIONS|PREDEFINITIONS)) || !(pp.state & NOTEXT)))
1223*da2e3ebdSchin 			{
1224*da2e3ebdSchin 				ppsync();
1225*da2e3ebdSchin 				ppprintf("#%s %s", dirname(DEFINE), sym->name);
1226*da2e3ebdSchin 				if (sym->flags & SYM_FUNCTION)
1227*da2e3ebdSchin 				{
1228*da2e3ebdSchin 					ppputchar('(');
1229*da2e3ebdSchin 					if (mac->formals)
1230*da2e3ebdSchin 						ppprintf("%s", mac->formals);
1231*da2e3ebdSchin 					ppputchar(')');
1232*da2e3ebdSchin 				}
1233*da2e3ebdSchin 				if ((p = mac->value) && *p)
1234*da2e3ebdSchin 				{
1235*da2e3ebdSchin 					ppputchar(' ');
1236*da2e3ebdSchin 					i0 = 0;
1237*da2e3ebdSchin 					while (n = *p++)
1238*da2e3ebdSchin 					{
1239*da2e3ebdSchin 						if (n != MARK || (n = *p++) == MARK)
1240*da2e3ebdSchin 						{
1241*da2e3ebdSchin 							ppputchar(n);
1242*da2e3ebdSchin 							i0 = ppisid(n);
1243*da2e3ebdSchin 						}
1244*da2e3ebdSchin 						else
1245*da2e3ebdSchin 						{
1246*da2e3ebdSchin 							if (n == 'Q')
1247*da2e3ebdSchin 								ppputchar('#');
1248*da2e3ebdSchin 							else if (i0)
1249*da2e3ebdSchin 							{
1250*da2e3ebdSchin 								ppputchar('#');
1251*da2e3ebdSchin 								ppputchar('#');
1252*da2e3ebdSchin 							}
1253*da2e3ebdSchin 							s = formargs[*p++ - ARGOFFSET];
1254*da2e3ebdSchin 							while ((n = *s++) && n != ',')
1255*da2e3ebdSchin 								ppputchar(n);
1256*da2e3ebdSchin 							if (ppisid(*p) || *p == MARK)
1257*da2e3ebdSchin 							{
1258*da2e3ebdSchin 								ppputchar('#');
1259*da2e3ebdSchin 								ppputchar('#');
1260*da2e3ebdSchin 							}
1261*da2e3ebdSchin 							i0 = 0;
1262*da2e3ebdSchin 						}
1263*da2e3ebdSchin 						ppcheckout();
1264*da2e3ebdSchin 					}
1265*da2e3ebdSchin 				}
1266*da2e3ebdSchin 				emitted = 1;
1267*da2e3ebdSchin 			}
1268*da2e3ebdSchin 		benign:
1269*da2e3ebdSchin 			if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN;
1270*da2e3ebdSchin 			if (pp.option & FINAL) sym->flags |= SYM_FINAL;
1271*da2e3ebdSchin 			if (pp.mode & INIT) sym->flags |= SYM_INIT;
1272*da2e3ebdSchin 			if (pp.option & INITIAL) sym->flags |= SYM_INITIAL;
1273*da2e3ebdSchin 			if (pp.state & NOEXPAND)  sym->flags |= SYM_NOEXPAND;
1274*da2e3ebdSchin 			if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED;
1275*da2e3ebdSchin 			if (pp.mode & READONLY) sym->flags |= SYM_READONLY;
1276*da2e3ebdSchin 			if (pp.macref) (*pp.macref)(sym, error_info.file, n2, mac ? error_info.line - n2 + 1 : REF_UNDEF, mac ? strsum(mac->value, (long)mac->arity) : 0L);
1277*da2e3ebdSchin 			break;
1278*da2e3ebdSchin 		assertion:
1279*da2e3ebdSchin 			c = pplex();
1280*da2e3ebdSchin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1281*da2e3ebdSchin 				error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0));
1282*da2e3ebdSchin 			if (c != T_ID)
1283*da2e3ebdSchin 			{
1284*da2e3ebdSchin 				error(2, "%s: invalid predicate name", pptokstr(pp.token, 0));
1285*da2e3ebdSchin 				goto eatdirective;
1286*da2e3ebdSchin 			}
1287*da2e3ebdSchin 			switch ((int)hashref(pp.strtab, pp.token))
1288*da2e3ebdSchin 			{
1289*da2e3ebdSchin 			case X_DEFINED:
1290*da2e3ebdSchin 			case X_EXISTS:
1291*da2e3ebdSchin 			case X_STRCMP:
1292*da2e3ebdSchin 				error(2, "%s is a builtin predicate", pp.token);
1293*da2e3ebdSchin 				goto eatdirective;
1294*da2e3ebdSchin 			case X_SIZEOF:
1295*da2e3ebdSchin 				error(2, "%s cannot be a predicate", pp.token);
1296*da2e3ebdSchin 				goto eatdirective;
1297*da2e3ebdSchin 			}
1298*da2e3ebdSchin 			strcpy(pp.tmpbuf, pp.token);
1299*da2e3ebdSchin 			switch (pppredargs())
1300*da2e3ebdSchin 			{
1301*da2e3ebdSchin 			case T_ID:
1302*da2e3ebdSchin 			case T_STRING:
1303*da2e3ebdSchin 				assert(directive, pp.tmpbuf, pp.args);
1304*da2e3ebdSchin 				break;
1305*da2e3ebdSchin 			case 0:
1306*da2e3ebdSchin 				assert(directive, pp.tmpbuf, NiL);
1307*da2e3ebdSchin 				break;
1308*da2e3ebdSchin 			default:
1309*da2e3ebdSchin 				error(2, "invalid predicate argument list");
1310*da2e3ebdSchin 				goto eatdirective;
1311*da2e3ebdSchin 			}
1312*da2e3ebdSchin 			break;
1313*da2e3ebdSchin 		tuple:
1314*da2e3ebdSchin 			pp.state |= DEFINITION|NOEXPAND|NOSPACE;
1315*da2e3ebdSchin 			rp = 0;
1316*da2e3ebdSchin 			tp = mac->tuple;
1317*da2e3ebdSchin 			if (!tp && !mac->value)
1318*da2e3ebdSchin 				ppfsm(FSM_MACRO, sym->name);
1319*da2e3ebdSchin 			while ((c = pplex()) && c != '>' && c != '\n')
1320*da2e3ebdSchin 			{
1321*da2e3ebdSchin 				for (; tp; tp = tp->nomatch)
1322*da2e3ebdSchin 					if (streq(tp->token, pp.token))
1323*da2e3ebdSchin 						break;
1324*da2e3ebdSchin 				if (!tp)
1325*da2e3ebdSchin 				{
1326*da2e3ebdSchin 					if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token))))
1327*da2e3ebdSchin 						error(3, "out of space");
1328*da2e3ebdSchin 					strcpy(tp->token, pp.token);
1329*da2e3ebdSchin 					if (rp)
1330*da2e3ebdSchin 					{
1331*da2e3ebdSchin 						tp->nomatch = rp;
1332*da2e3ebdSchin 						rp->nomatch = tp;
1333*da2e3ebdSchin 					}
1334*da2e3ebdSchin 					else
1335*da2e3ebdSchin 					{
1336*da2e3ebdSchin 						tp->nomatch = mac->tuple;
1337*da2e3ebdSchin 						mac->tuple = tp;
1338*da2e3ebdSchin 					}
1339*da2e3ebdSchin 				}
1340*da2e3ebdSchin 				rp = tp;
1341*da2e3ebdSchin 				tp = tp->match;
1342*da2e3ebdSchin 			}
1343*da2e3ebdSchin 			pp.state &= ~NOSPACE;
1344*da2e3ebdSchin 			if (!rp || c != '>')
1345*da2e3ebdSchin 				error(2, "%s: > omitted in tuple macro definition", sym->name);
1346*da2e3ebdSchin 			else
1347*da2e3ebdSchin 			{
1348*da2e3ebdSchin 				n = 2 * MAXTOKEN;
1349*da2e3ebdSchin 				p = v = oldof(0, char, 0, n);
1350*da2e3ebdSchin 				while ((c = pplex()) && c != '\n')
1351*da2e3ebdSchin 					if (p > v || c != ' ')
1352*da2e3ebdSchin 					{
1353*da2e3ebdSchin 						STRCOPY(p, pp.token, s);
1354*da2e3ebdSchin 						if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v)
1355*da2e3ebdSchin 						{
1356*da2e3ebdSchin 							c = p - v;
1357*da2e3ebdSchin 							v = s;
1358*da2e3ebdSchin 							p = v + c;
1359*da2e3ebdSchin 						}
1360*da2e3ebdSchin 					}
1361*da2e3ebdSchin 				while (p > v && *(p - 1) == ' ')
1362*da2e3ebdSchin 					p--;
1363*da2e3ebdSchin 				n = p - v;
1364*da2e3ebdSchin 				tp = newof(0, struct pptuple, 1, n);
1365*da2e3ebdSchin 				strcpy(tp->token, v);
1366*da2e3ebdSchin 				tp->match = rp->match;
1367*da2e3ebdSchin 				rp->match = tp;
1368*da2e3ebdSchin 			}
1369*da2e3ebdSchin 			goto benign;
1370*da2e3ebdSchin 		case WARNING:
1371*da2e3ebdSchin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1372*da2e3ebdSchin 				error(1, "#%s: non-standard directive", pp.token);
1373*da2e3ebdSchin 			/*FALLTHROUGH*/
1374*da2e3ebdSchin 		case ERROR:
1375*da2e3ebdSchin 			pp.state &= ~DISABLE;
1376*da2e3ebdSchin 			p = pp.tmpbuf;
1377*da2e3ebdSchin 			while ((c = pplex()) != '\n')
1378*da2e3ebdSchin 				if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN])
1379*da2e3ebdSchin 				{
1380*da2e3ebdSchin 					STRCOPY(p, pp.token, s);
1381*da2e3ebdSchin 					pp.state &= ~NOSPACE;
1382*da2e3ebdSchin 				}
1383*da2e3ebdSchin 			*p = 0;
1384*da2e3ebdSchin 			p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error");
1385*da2e3ebdSchin 			n = (directive == WARNING) ? 1 : 3;
1386*da2e3ebdSchin 			error(n, "%s", p);
1387*da2e3ebdSchin 			break;
1388*da2e3ebdSchin 		case LET:
1389*da2e3ebdSchin 			n2 = error_info.line;
1390*da2e3ebdSchin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1391*da2e3ebdSchin 				error(1, "#%s: non-standard directive", pp.token);
1392*da2e3ebdSchin 			if (!(sym = macsym(c = pplex()))) goto eatdirective;
1393*da2e3ebdSchin 			if ((c = pplex()) != '=')
1394*da2e3ebdSchin 			{
1395*da2e3ebdSchin 				error(2, "%s: = expected", sym->name);
1396*da2e3ebdSchin 				goto eatdirective;
1397*da2e3ebdSchin 			}
1398*da2e3ebdSchin 			sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC);
1399*da2e3ebdSchin 			mac = sym->macro;
1400*da2e3ebdSchin 			mac->arity = 0;
1401*da2e3ebdSchin 			if (mac->value)
1402*da2e3ebdSchin 			{
1403*da2e3ebdSchin 				if (!(sym->flags & SYM_REDEFINE) && !sym->hidden)
1404*da2e3ebdSchin 					error(1, "%s: redefined", sym->name);
1405*da2e3ebdSchin #if MACKEYARGS
1406*da2e3ebdSchin 				if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys);
1407*da2e3ebdSchin 				else
1408*da2e3ebdSchin #endif
1409*da2e3ebdSchin 				free(mac->formals);
1410*da2e3ebdSchin 				mac->formals = 0;
1411*da2e3ebdSchin 				n = strlen(mac->value) + 1;
1412*da2e3ebdSchin 			}
1413*da2e3ebdSchin 			else
1414*da2e3ebdSchin 			{
1415*da2e3ebdSchin 				ppfsm(FSM_MACRO, sym->name);
1416*da2e3ebdSchin 				n = 0;
1417*da2e3ebdSchin 			}
1418*da2e3ebdSchin 			n1 = ppexpr(&i1);
1419*da2e3ebdSchin 			if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1);
1420*da2e3ebdSchin 			else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1);
1421*da2e3ebdSchin 			if (n < ++c)
1422*da2e3ebdSchin 			{
1423*da2e3ebdSchin 				if (mac->value) free(mac->value);
1424*da2e3ebdSchin 				mac->value = oldof(0, char, 0, c);
1425*da2e3ebdSchin 			}
1426*da2e3ebdSchin 			strcpy(mac->value, pp.tmpbuf);
1427*da2e3ebdSchin 			sym->flags |= SYM_REDEFINE;
1428*da2e3ebdSchin 			c = (pp.state & NEWLINE) ? '\n' : ' ';
1429*da2e3ebdSchin 			goto benign;
1430*da2e3ebdSchin 		case LINE:
1431*da2e3ebdSchin 			pp.state &= ~DISABLE;
1432*da2e3ebdSchin 			if ((c = pplex()) == '#')
1433*da2e3ebdSchin 			{
1434*da2e3ebdSchin 				c = pplex();
1435*da2e3ebdSchin 				directive = INCLUDE;
1436*da2e3ebdSchin 			}
1437*da2e3ebdSchin 			if (c != T_DECIMAL && c != T_OCTAL)
1438*da2e3ebdSchin 			{
1439*da2e3ebdSchin 				error(1, "#%s: line number expected", dirname(LINE));
1440*da2e3ebdSchin 				goto eatdirective;
1441*da2e3ebdSchin 			}
1442*da2e3ebdSchin 		linesync:
1443*da2e3ebdSchin 			n = error_info.line;
1444*da2e3ebdSchin 			error_info.line = strtol(pp.token, NiL, 0);
1445*da2e3ebdSchin 			if (error_info.line == 0 && directive == LINE && (pp.state & STRICT) && !(pp.mode & HOSTED))
1446*da2e3ebdSchin 				error(1, "#%s: line number should be > 0", dirname(LINE));
1447*da2e3ebdSchin 			pp.state &= ~DISABLE;
1448*da2e3ebdSchin 			pp.state |= STRIP;
1449*da2e3ebdSchin 			switch (c = pplex())
1450*da2e3ebdSchin 			{
1451*da2e3ebdSchin 			case T_STRING:
1452*da2e3ebdSchin 				s = error_info.file;
1453*da2e3ebdSchin 				if (*(p = pp.token)) pathcanon(p, 0);
1454*da2e3ebdSchin 				fp = ppsetfile(p);
1455*da2e3ebdSchin 				error_info.file = fp->name;
1456*da2e3ebdSchin 				if (error_info.line == 1)
1457*da2e3ebdSchin 					ppmultiple(fp, INC_TEST);
1458*da2e3ebdSchin 				switch (c = pplex())
1459*da2e3ebdSchin 				{
1460*da2e3ebdSchin 				case '\n':
1461*da2e3ebdSchin 					break;
1462*da2e3ebdSchin 				case T_DECIMAL:
1463*da2e3ebdSchin 				case T_OCTAL:
1464*da2e3ebdSchin 					if (directive == LINE && (pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1465*da2e3ebdSchin 						error(1, "#%s: integer file type argument is non-standard", dirname(LINE));
1466*da2e3ebdSchin 					break;
1467*da2e3ebdSchin 				default:
1468*da2e3ebdSchin 					error(1, "#%s: integer file type argument expected", dirname(LINE));
1469*da2e3ebdSchin 					break;
1470*da2e3ebdSchin 				}
1471*da2e3ebdSchin 				if (directive == LINE) pp.in->flags &= ~IN_ignoreline;
1472*da2e3ebdSchin 				else if (pp.incref)
1473*da2e3ebdSchin 				{
1474*da2e3ebdSchin 					if (error_info.file != s)
1475*da2e3ebdSchin 					{
1476*da2e3ebdSchin 						switch (*pp.token)
1477*da2e3ebdSchin 						{
1478*da2e3ebdSchin 						case PP_sync_push:
1479*da2e3ebdSchin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1480*da2e3ebdSchin 							else (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
1481*da2e3ebdSchin 							break;
1482*da2e3ebdSchin 						case PP_sync_pop:
1483*da2e3ebdSchin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1484*da2e3ebdSchin 							else (*pp.incref)(s, error_info.file, n - 1, PP_SYNC_POP);
1485*da2e3ebdSchin 							break;
1486*da2e3ebdSchin 						case PP_sync_ignore:
1487*da2e3ebdSchin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1488*da2e3ebdSchin 							else
1489*da2e3ebdSchin 							{
1490*da2e3ebdSchin 								(*pp.incref)(s, error_info.file, n, PP_SYNC_IGNORE);
1491*da2e3ebdSchin 								error_info.file = s;
1492*da2e3ebdSchin 							}
1493*da2e3ebdSchin 							break;
1494*da2e3ebdSchin 						default:
1495*da2e3ebdSchin 							if (*s)
1496*da2e3ebdSchin 							{
1497*da2e3ebdSchin 								if (fp == pp.insert)
1498*da2e3ebdSchin 									pp.insert = 0;
1499*da2e3ebdSchin 								else if (error_info.line == 1 && !pp.insert)
1500*da2e3ebdSchin 									(*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
1501*da2e3ebdSchin 								else
1502*da2e3ebdSchin 								{
1503*da2e3ebdSchin 									if (!pp.insert) pp.insert = ppgetfile(s);
1504*da2e3ebdSchin 									(*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1505*da2e3ebdSchin 								}
1506*da2e3ebdSchin 							}
1507*da2e3ebdSchin 							break;
1508*da2e3ebdSchin 						}
1509*da2e3ebdSchin 					}
1510*da2e3ebdSchin 				}
1511*da2e3ebdSchin 				break;
1512*da2e3ebdSchin 			case '\n':
1513*da2e3ebdSchin 				break;
1514*da2e3ebdSchin 			default:
1515*da2e3ebdSchin 				error(1, "#%s: \"file-name\" expected", dirname(LINE));
1516*da2e3ebdSchin 				break;
1517*da2e3ebdSchin 			}
1518*da2e3ebdSchin 			if (directive == LINE && (pp.in->flags & IN_ignoreline))
1519*da2e3ebdSchin 				error_info.line = n + 1;
1520*da2e3ebdSchin 			else
1521*da2e3ebdSchin 			{
1522*da2e3ebdSchin 				pp.hidden = 0;
1523*da2e3ebdSchin 				pp.state &= ~HIDDEN;
1524*da2e3ebdSchin 				if (pp.linesync)
1525*da2e3ebdSchin 				{
1526*da2e3ebdSchin #if CATSTRINGS
1527*da2e3ebdSchin 					if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
1528*da2e3ebdSchin 					else
1529*da2e3ebdSchin #endif
1530*da2e3ebdSchin 					{
1531*da2e3ebdSchin 						s = pp.lineid;
1532*da2e3ebdSchin 						n = pp.flags;
1533*da2e3ebdSchin 						if (directive == LINE)
1534*da2e3ebdSchin 						{
1535*da2e3ebdSchin 							pp.flags &= ~PP_linetype;
1536*da2e3ebdSchin 							if (pp.macref) pp.lineid = dirname(LINE);
1537*da2e3ebdSchin 						}
1538*da2e3ebdSchin 						(*pp.linesync)(error_info.line, error_info.file);
1539*da2e3ebdSchin 						pp.flags = n;
1540*da2e3ebdSchin 						pp.lineid = s;
1541*da2e3ebdSchin 					}
1542*da2e3ebdSchin 				}
1543*da2e3ebdSchin 			}
1544*da2e3ebdSchin 			directive = LINE;
1545*da2e3ebdSchin 			break;
1546*da2e3ebdSchin 		case PRAGMA:
1547*da2e3ebdSchin 			/*
1548*da2e3ebdSchin 			 * #pragma [STDC] [pass:] [no]option [arg ...]
1549*da2e3ebdSchin 			 *
1550*da2e3ebdSchin 			 * pragma args are not expanded by default
1551*da2e3ebdSchin 			 *
1552*da2e3ebdSchin 			 * if STDC is present then it is silently passed on
1553*da2e3ebdSchin 			 *
1554*da2e3ebdSchin 			 * if pass is pp.pass then the option is used
1555*da2e3ebdSchin 			 * and verified but is not passed on
1556*da2e3ebdSchin 			 *
1557*da2e3ebdSchin 			 * if pass is omitted then the option is passed on
1558*da2e3ebdSchin 			 *
1559*da2e3ebdSchin 			 * otherwise if pass is non-null and not pp.pass then
1560*da2e3ebdSchin 			 * the option is passed on but not used
1561*da2e3ebdSchin 			 *
1562*da2e3ebdSchin 			 * if the line does not match this form then
1563*da2e3ebdSchin 			 * it is passed on unchanged
1564*da2e3ebdSchin 			 *
1565*da2e3ebdSchin 			 *	#directive   pass:  option  [...]
1566*da2e3ebdSchin 			 *	^         ^  ^   ^  ^     ^  ^   ^
1567*da2e3ebdSchin 			 *	pp.valbuf p0 p1  p2 p3    p4 p5  p6
1568*da2e3ebdSchin 			 *
1569*da2e3ebdSchin 			 * p?	0 if component omitted
1570*da2e3ebdSchin 			 * i0	0 if ``no''option
1571*da2e3ebdSchin 			 */
1572*da2e3ebdSchin 
1573*da2e3ebdSchin 			p = pp.valbuf;
1574*da2e3ebdSchin 			*p++ = '#';
1575*da2e3ebdSchin 			STRCOPY(p, pp.token, s);
1576*da2e3ebdSchin 			p0 = p;
1577*da2e3ebdSchin 			if (pp.option & PRAGMAEXPAND)
1578*da2e3ebdSchin 				pp.state &= ~DISABLE;
1579*da2e3ebdSchin 			if (!(p6 = getline(p, &pp.valbuf[MAXTOKEN], !!(pp.option & PRAGMAEXPAND))))
1580*da2e3ebdSchin 			{
1581*da2e3ebdSchin 				*p0 = 0;
1582*da2e3ebdSchin 				error(2, "%s: directive too long", pp.valbuf);
1583*da2e3ebdSchin 				c = 0;
1584*da2e3ebdSchin 				goto eatdirective;
1585*da2e3ebdSchin 			}
1586*da2e3ebdSchin 			p1 = ++p;
1587*da2e3ebdSchin 			while (ppisid(*p))
1588*da2e3ebdSchin 				p++;
1589*da2e3ebdSchin 			if (p == p1)
1590*da2e3ebdSchin 			{
1591*da2e3ebdSchin 				p5 = p;
1592*da2e3ebdSchin 				p4 = 0;
1593*da2e3ebdSchin 				p3 = 0;
1594*da2e3ebdSchin 				p2 = 0;
1595*da2e3ebdSchin 				p1 = 0;
1596*da2e3ebdSchin 			}
1597*da2e3ebdSchin 			else if (*p != ':')
1598*da2e3ebdSchin 			{
1599*da2e3ebdSchin 				p5 = *p ? p + (*p == ' ') : 0;
1600*da2e3ebdSchin 				p4 = p;
1601*da2e3ebdSchin 				p3 = p1;
1602*da2e3ebdSchin 				p2 = 0;
1603*da2e3ebdSchin 				p1 = 0;
1604*da2e3ebdSchin 			}
1605*da2e3ebdSchin 			else
1606*da2e3ebdSchin 			{
1607*da2e3ebdSchin 				p2 = p++;
1608*da2e3ebdSchin 				p3 = p;
1609*da2e3ebdSchin 				while (ppisid(*p))
1610*da2e3ebdSchin 					p++;
1611*da2e3ebdSchin 				if (p == p3)
1612*da2e3ebdSchin 				{
1613*da2e3ebdSchin 					p4 = p1;
1614*da2e3ebdSchin 					p3 = 0;
1615*da2e3ebdSchin 					p2 = 0;
1616*da2e3ebdSchin 					p1 = 0;
1617*da2e3ebdSchin 				}
1618*da2e3ebdSchin 				else
1619*da2e3ebdSchin 					p4 = p;
1620*da2e3ebdSchin 				p5 = *p4 ? p4 + (*p4 == ' ') : 0;
1621*da2e3ebdSchin 			}
1622*da2e3ebdSchin 			if (!p1 && p3 && (p4 - p3) == 4 && strneq(p3, "STDC", 4))
1623*da2e3ebdSchin 				goto pass;
1624*da2e3ebdSchin 			if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX)))
1625*da2e3ebdSchin 				error(1, "#%s: non-standard directive", dirname(PRAGMA));
1626*da2e3ebdSchin 			i0 = !p3 || *p3 != 'n' || *(p3 + 1) != 'o';
1627*da2e3ebdSchin 			if (!p3)
1628*da2e3ebdSchin 				goto checkmap;
1629*da2e3ebdSchin 			if (p1)
1630*da2e3ebdSchin 			{
1631*da2e3ebdSchin 				*p2 = 0;
1632*da2e3ebdSchin 				n = streq(p1, pp.pass);
1633*da2e3ebdSchin 				*p2 = ':';
1634*da2e3ebdSchin 				if (!n)
1635*da2e3ebdSchin 					goto checkmap;
1636*da2e3ebdSchin 			}
1637*da2e3ebdSchin 			else
1638*da2e3ebdSchin 				n = 0;
1639*da2e3ebdSchin 			i2 = *p4;
1640*da2e3ebdSchin 			*p4 = 0;
1641*da2e3ebdSchin 			if (((i1 = (int)hashref(pp.strtab, p3 + (i0 ? 0 : 2))) < 1 || i1 > X_last_option) && (i0 || (i1 = (int)hashref(pp.strtab, p3)) > X_last_option))
1642*da2e3ebdSchin 				i1 = 0;
1643*da2e3ebdSchin 			if ((pp.state & (COMPATIBILITY|STRICT)) == STRICT && !(pp.mode & (HOSTED|RELAX)))
1644*da2e3ebdSchin 			{
1645*da2e3ebdSchin 				if (pp.optflags[i1] & OPT_GLOBAL)
1646*da2e3ebdSchin 					goto donedirective;
1647*da2e3ebdSchin 				if (n || (pp.mode & WARN))
1648*da2e3ebdSchin 				{
1649*da2e3ebdSchin 					n = 0;
1650*da2e3ebdSchin 					error(1, "#%s: non-standard directive ignored", dirname(PRAGMA));
1651*da2e3ebdSchin 				}
1652*da2e3ebdSchin 				i1 = 0;
1653*da2e3ebdSchin 			}
1654*da2e3ebdSchin 			if (!n)
1655*da2e3ebdSchin 			{
1656*da2e3ebdSchin 				if (!(pp.optflags[i1] & OPT_GLOBAL))
1657*da2e3ebdSchin 				{
1658*da2e3ebdSchin 					*p4 = i2;
1659*da2e3ebdSchin 					goto checkmap;
1660*da2e3ebdSchin 				}
1661*da2e3ebdSchin 				if (!(pp.optflags[i1] & OPT_PASS))
1662*da2e3ebdSchin 					n = 1;
1663*da2e3ebdSchin 			}
1664*da2e3ebdSchin 			else if (!i1)
1665*da2e3ebdSchin 				error(2, "%s: unknown option", p1);
1666*da2e3ebdSchin 			else if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1667*da2e3ebdSchin 				error(1, "%s: non-standard option", p1);
1668*da2e3ebdSchin 			p = p5;
1669*da2e3ebdSchin 			switch (i1)
1670*da2e3ebdSchin 			{
1671*da2e3ebdSchin 			case X_ALLMULTIPLE:
1672*da2e3ebdSchin 				ppop(PP_MULTIPLE, i0);
1673*da2e3ebdSchin 				break;
1674*da2e3ebdSchin 			case X_ALLPOSSIBLE:
1675*da2e3ebdSchin 				setoption(ALLPOSSIBLE, i0);
1676*da2e3ebdSchin 				break;
1677*da2e3ebdSchin 			case X_BUILTIN:
1678*da2e3ebdSchin 				setmode(BUILTIN, i0);
1679*da2e3ebdSchin 				break;
1680*da2e3ebdSchin 			case X_CATLITERAL:
1681*da2e3ebdSchin 				setmode(CATLITERAL, i0);
1682*da2e3ebdSchin 				if (pp.mode & CATLITERAL)
1683*da2e3ebdSchin 					setoption(STRINGSPLIT, 0);
1684*da2e3ebdSchin 				break;
1685*da2e3ebdSchin 			case X_CDIR:
1686*da2e3ebdSchin 				tokop(PP_CDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
1687*da2e3ebdSchin 				break;
1688*da2e3ebdSchin 			case X_CHECKPOINT:
1689*da2e3ebdSchin #if CHECKPOINT
1690*da2e3ebdSchin 				ppload(p);
1691*da2e3ebdSchin #else
1692*da2e3ebdSchin 				error(3, "%s: preprocessor not compiled with checkpoint enabled", p3);
1693*da2e3ebdSchin #endif
1694*da2e3ebdSchin 				break;
1695*da2e3ebdSchin 			case X_CHOP:
1696*da2e3ebdSchin 				tokop(PP_CHOP, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
1697*da2e3ebdSchin 				break;
1698*da2e3ebdSchin 			case X_COMPATIBILITY:
1699*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, i0);
1700*da2e3ebdSchin 				break;
1701*da2e3ebdSchin 			case X_DEBUG:
1702*da2e3ebdSchin 				error_info.trace = i0 ? (p ? -strtol(p, NiL, 0) : -1) : 0;
1703*da2e3ebdSchin 				break;
1704*da2e3ebdSchin 			case X_ELSEIF:
1705*da2e3ebdSchin 				setoption(ELSEIF, i0);
1706*da2e3ebdSchin 				break;
1707*da2e3ebdSchin 			case X_EXTERNALIZE:
1708*da2e3ebdSchin 				setmode(EXTERNALIZE, i0);
1709*da2e3ebdSchin 				break;
1710*da2e3ebdSchin 			case X_FINAL:
1711*da2e3ebdSchin 				setoption(FINAL, i0);
1712*da2e3ebdSchin 				break;
1713*da2e3ebdSchin 			case X_HEADEREXPAND:
1714*da2e3ebdSchin 				setoption(HEADEREXPAND, i0);
1715*da2e3ebdSchin 				break;
1716*da2e3ebdSchin 			case X_HEADEREXPANDALL:
1717*da2e3ebdSchin 				setoption(HEADEREXPANDALL, i0);
1718*da2e3ebdSchin 				break;
1719*da2e3ebdSchin 			case X_HIDE:
1720*da2e3ebdSchin 			case X_NOTE:
1721*da2e3ebdSchin 				PUSH_LINE(p);
1722*da2e3ebdSchin 				/* UNDENT...*/
1723*da2e3ebdSchin 	while (c = pplex())
1724*da2e3ebdSchin 	{
1725*da2e3ebdSchin 		if (c != T_ID) error(1, "%s: %s: identifier expected", p3, pp.token);
1726*da2e3ebdSchin 		else if (sym = ppsymset(pp.symtab, pp.token))
1727*da2e3ebdSchin 		{
1728*da2e3ebdSchin 			if (i1 == X_NOTE)
1729*da2e3ebdSchin 			{
1730*da2e3ebdSchin 				sym->flags &= ~SYM_NOTICED;
1731*da2e3ebdSchin 				ppfsm(FSM_MACRO, sym->name);
1732*da2e3ebdSchin 			}
1733*da2e3ebdSchin 			else if (i0)
1734*da2e3ebdSchin 			{
1735*da2e3ebdSchin 				if (!sym->hidden && !(sym->hidden = newof(0, struct pphide, 1, 0)))
1736*da2e3ebdSchin 					error(3, "out of space");
1737*da2e3ebdSchin 				if (!sym->macro)
1738*da2e3ebdSchin 					ppfsm(FSM_MACRO, sym->name);
1739*da2e3ebdSchin 				if (!sym->hidden->level++)
1740*da2e3ebdSchin 				{
1741*da2e3ebdSchin 					pp.hiding++;
1742*da2e3ebdSchin 					if (sym->macro && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
1743*da2e3ebdSchin 					{
1744*da2e3ebdSchin 						sym->hidden->macro = sym->macro;
1745*da2e3ebdSchin 						sym->macro = 0;
1746*da2e3ebdSchin 						sym->hidden->flags = sym->flags;
1747*da2e3ebdSchin 						sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
1748*da2e3ebdSchin 					}
1749*da2e3ebdSchin 				}
1750*da2e3ebdSchin 			}
1751*da2e3ebdSchin 			else if (sym->hidden)
1752*da2e3ebdSchin 			{
1753*da2e3ebdSchin 				if ((mac = sym->macro) && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
1754*da2e3ebdSchin 				{
1755*da2e3ebdSchin 					if (mac->formals) free(mac->formals);
1756*da2e3ebdSchin 					free(mac->value);
1757*da2e3ebdSchin 					free(mac);
1758*da2e3ebdSchin 					sym->macro = 0;
1759*da2e3ebdSchin 					sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
1760*da2e3ebdSchin 				}
1761*da2e3ebdSchin 				if (!--sym->hidden->level)
1762*da2e3ebdSchin 				{
1763*da2e3ebdSchin 					pp.hiding--;
1764*da2e3ebdSchin 					if (sym->hidden->macro)
1765*da2e3ebdSchin 					{
1766*da2e3ebdSchin 						sym->macro = sym->hidden->macro;
1767*da2e3ebdSchin 						sym->flags = sym->hidden->flags;
1768*da2e3ebdSchin 					}
1769*da2e3ebdSchin 					free(sym->hidden);
1770*da2e3ebdSchin 					sym->hidden = 0;
1771*da2e3ebdSchin 				}
1772*da2e3ebdSchin 			}
1773*da2e3ebdSchin 		}
1774*da2e3ebdSchin 	}
1775*da2e3ebdSchin 				/*...INDENT*/
1776*da2e3ebdSchin 				POP_LINE();
1777*da2e3ebdSchin 				break;
1778*da2e3ebdSchin 			case X_HOSTDIR:
1779*da2e3ebdSchin 				tokop(PP_HOSTDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
1780*da2e3ebdSchin 				break;
1781*da2e3ebdSchin 			case X_HOSTED:
1782*da2e3ebdSchin 				setmode(HOSTED, i0);
1783*da2e3ebdSchin 				break;
1784*da2e3ebdSchin 			case X_HOSTEDTRANSITION:
1785*da2e3ebdSchin 				setmode(HOSTEDTRANSITION, i0);
1786*da2e3ebdSchin 				break;
1787*da2e3ebdSchin 			case X_ID:
1788*da2e3ebdSchin 				tokop(PP_ID, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
1789*da2e3ebdSchin 				break;
1790*da2e3ebdSchin 			case X_IGNORE:
1791*da2e3ebdSchin 				tokop(PP_IGNORE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
1792*da2e3ebdSchin 				break;
1793*da2e3ebdSchin 			case X_INCLUDE:
1794*da2e3ebdSchin 				tokop(PP_INCLUDE, p3, p, i0, TOKOP_STRING|TOKOP_DUP);
1795*da2e3ebdSchin 				break;
1796*da2e3ebdSchin 			case X_INITIAL:
1797*da2e3ebdSchin 				setoption(INITIAL, i0);
1798*da2e3ebdSchin 				break;
1799*da2e3ebdSchin 			case X_KEYARGS:
1800*da2e3ebdSchin 				ppop(PP_KEYARGS, i0);
1801*da2e3ebdSchin 				break;
1802*da2e3ebdSchin 			case X_LINE:
1803*da2e3ebdSchin 				if (pp.linesync) pp.olinesync = pp.linesync;
1804*da2e3ebdSchin 				pp.linesync = i0 ? pp.olinesync : (PPLINESYNC)0;
1805*da2e3ebdSchin 				break;
1806*da2e3ebdSchin 			case X_LINEBASE:
1807*da2e3ebdSchin 				ppop(PP_LINEBASE, i0);
1808*da2e3ebdSchin 				break;
1809*da2e3ebdSchin 			case X_LINEFILE:
1810*da2e3ebdSchin 				ppop(PP_LINEFILE, i0);
1811*da2e3ebdSchin 				break;
1812*da2e3ebdSchin 			case X_LINEID:
1813*da2e3ebdSchin 				ppop(PP_LINEID, i0 ? p : (char*)0);
1814*da2e3ebdSchin 				break;
1815*da2e3ebdSchin 			case X_LINETYPE:
1816*da2e3ebdSchin 				ppop(PP_LINETYPE, i0 ? (p ? strtol(p, NiL, 0) : 1) : 0);
1817*da2e3ebdSchin 				break;
1818*da2e3ebdSchin 			case X_MACREF:
1819*da2e3ebdSchin 				if (!p)
1820*da2e3ebdSchin 				{
1821*da2e3ebdSchin 					if (i0 && !pp.macref)
1822*da2e3ebdSchin 					{
1823*da2e3ebdSchin 						ppop(PP_LINETYPE, 1);
1824*da2e3ebdSchin 						ppop(PP_MACREF, ppmacref);
1825*da2e3ebdSchin 					}
1826*da2e3ebdSchin 					else error(2, "%s: option cannot be unset", p3);
1827*da2e3ebdSchin 				}
1828*da2e3ebdSchin 				else if (s = strchr(p, ' '))
1829*da2e3ebdSchin 				{
1830*da2e3ebdSchin 					if (pp.macref && (s = strchr(p, ' ')))
1831*da2e3ebdSchin 					{
1832*da2e3ebdSchin 						*s++ = 0;
1833*da2e3ebdSchin 						c = strtol(s, NiL, 0);
1834*da2e3ebdSchin 						var.type = pp.truncate;
1835*da2e3ebdSchin 						pp.truncate = PPTOKSIZ;
1836*da2e3ebdSchin 						(*pp.macref)(pprefmac(p, REF_CREATE), error_info.file, error_info.line - (c == REF_NORMAL ? 2 : 1), c, (s = strchr(s, ' ')) ? strtol(s, NiL, 0) : 0L);
1837*da2e3ebdSchin 						pp.truncate = var.type;
1838*da2e3ebdSchin 					}
1839*da2e3ebdSchin 					error_info.line -= 2;
1840*da2e3ebdSchin 				}
1841*da2e3ebdSchin 				break;
1842*da2e3ebdSchin 			case X_MAP:
1843*da2e3ebdSchin 				/*UNDENT*/
1844*da2e3ebdSchin 	/*
1845*da2e3ebdSchin 	 * #pragma pp:map [id ...] "/from/[,/to/]" [ "/old/new/[glnu]" ... ]
1846*da2e3ebdSchin 	 */
1847*da2e3ebdSchin 
1848*da2e3ebdSchin 	if (!i0)
1849*da2e3ebdSchin 	{
1850*da2e3ebdSchin 		error(2, "%s: option cannot be unset", p3);
1851*da2e3ebdSchin 		goto donedirective;
1852*da2e3ebdSchin 	}
1853*da2e3ebdSchin 	if (!p5)
1854*da2e3ebdSchin 	{
1855*da2e3ebdSchin 		error(2, "%s: address argument expected", p3);
1856*da2e3ebdSchin 		goto donedirective;
1857*da2e3ebdSchin 	}
1858*da2e3ebdSchin 	PUSH_LINE(p5);
1859*da2e3ebdSchin 	while ((c = pplex()) == T_ID)
1860*da2e3ebdSchin 	{
1861*da2e3ebdSchin 		sfsprintf(pp.tmpbuf, MAXTOKEN, "__%s__", s = pp.token);
1862*da2e3ebdSchin 		if (c = (int)hashget(pp.dirtab, s))
1863*da2e3ebdSchin 		{
1864*da2e3ebdSchin 			hashput(pp.dirtab, 0, 0);
1865*da2e3ebdSchin 			hashput(pp.dirtab, pp.tmpbuf, c);
1866*da2e3ebdSchin 		}
1867*da2e3ebdSchin 		if (c = (int)hashget(pp.strtab, s))
1868*da2e3ebdSchin 		{
1869*da2e3ebdSchin 			hashput(pp.strtab, 0, 0);
1870*da2e3ebdSchin 			hashput(pp.strtab, pp.tmpbuf, c);
1871*da2e3ebdSchin 		}
1872*da2e3ebdSchin 	}
1873*da2e3ebdSchin 	if (c != T_STRING || !*(s = pp.token))
1874*da2e3ebdSchin 	{
1875*da2e3ebdSchin 		if (c)
1876*da2e3ebdSchin 			error(2, "%s: %s: address argument expected", p3, pptokstr(pp.token, 0));
1877*da2e3ebdSchin 		goto eatmap;
1878*da2e3ebdSchin 	}
1879*da2e3ebdSchin 	map = newof(0, struct map, 1, 0);
1880*da2e3ebdSchin 
1881*da2e3ebdSchin 	/*
1882*da2e3ebdSchin 	 * /from/
1883*da2e3ebdSchin 	 */
1884*da2e3ebdSchin 
1885*da2e3ebdSchin 	if (i0 = regcomp(&map->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL))
1886*da2e3ebdSchin 		regfatal(&map->re, 3, i0);
1887*da2e3ebdSchin 	if (*(s += map->re.re_npat))
1888*da2e3ebdSchin 	{
1889*da2e3ebdSchin 		error(2, "%s: invalid characters after pattern: %s ", p3, s);
1890*da2e3ebdSchin 		goto eatmap;
1891*da2e3ebdSchin 	}
1892*da2e3ebdSchin 
1893*da2e3ebdSchin 	/*
1894*da2e3ebdSchin 	 * /old/new/[flags]
1895*da2e3ebdSchin 	 */
1896*da2e3ebdSchin 
1897*da2e3ebdSchin 	edit = 0;
1898*da2e3ebdSchin 	while ((c = pplex()) == T_STRING)
1899*da2e3ebdSchin 	{
1900*da2e3ebdSchin 		if (!*(s = pp.token))
1901*da2e3ebdSchin 		{
1902*da2e3ebdSchin 			error(2, "%s: substitution argument expected", p3);
1903*da2e3ebdSchin 			goto eatmap;
1904*da2e3ebdSchin 		}
1905*da2e3ebdSchin 		if (edit)
1906*da2e3ebdSchin 			edit = edit->next = newof(0, struct edit, 1, 0);
1907*da2e3ebdSchin 		else
1908*da2e3ebdSchin 			edit = map->edit = newof(0, struct edit, 1, 0);
1909*da2e3ebdSchin 		if (!(i0 = regcomp(&edit->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL)) && !(i0 = regsubcomp(&edit->re, s += edit->re.re_npat, NiL, 0, 0)))
1910*da2e3ebdSchin 			s += edit->re.re_npat;
1911*da2e3ebdSchin 		if (i0)
1912*da2e3ebdSchin 			regfatal(&edit->re, 3, i0);
1913*da2e3ebdSchin 		if (*s)
1914*da2e3ebdSchin 		{
1915*da2e3ebdSchin 			error(2, "%s: invalid characters after substitution: %s ", p3, s);
1916*da2e3ebdSchin 			goto eatmap;
1917*da2e3ebdSchin 		}
1918*da2e3ebdSchin 	}
1919*da2e3ebdSchin 	if (c)
1920*da2e3ebdSchin 	{
1921*da2e3ebdSchin 		error(2, "%s: %s: substitution argument expected", p3, pptokstr(pp.token, 0));
1922*da2e3ebdSchin 		goto eatmap;
1923*da2e3ebdSchin 	}
1924*da2e3ebdSchin 	map->next = (struct map*)pp.maps;
1925*da2e3ebdSchin 	pp.maps = (char*)map;
1926*da2e3ebdSchin  eatmap:
1927*da2e3ebdSchin 	POP_LINE();
1928*da2e3ebdSchin 				/*INDENT*/
1929*da2e3ebdSchin 				break;
1930*da2e3ebdSchin 			case X_MAPINCLUDE:
1931*da2e3ebdSchin 				ppmapinclude(NiL, p5);
1932*da2e3ebdSchin 				break;
1933*da2e3ebdSchin 			case X_MODERN:
1934*da2e3ebdSchin 				setoption(MODERN, i0);
1935*da2e3ebdSchin 				break;
1936*da2e3ebdSchin 			case X_MULTIPLE:
1937*da2e3ebdSchin 				n = 1;
1938*da2e3ebdSchin 				if (pp.in->type == IN_FILE)
1939*da2e3ebdSchin 					ppmultiple(ppsetfile(error_info.file), i0 ? INC_CLEAR : INC_TEST);
1940*da2e3ebdSchin 				break;
1941*da2e3ebdSchin 			case X_NATIVE:
1942*da2e3ebdSchin 				setoption(NATIVE, i0);
1943*da2e3ebdSchin 				break;
1944*da2e3ebdSchin 			case X_OPSPACE:
1945*da2e3ebdSchin 				ppfsm(FSM_OPSPACE, i0 ? p4 : (char*)0);
1946*da2e3ebdSchin 				break;
1947*da2e3ebdSchin 			case X_PASSTHROUGH:
1948*da2e3ebdSchin 				ppop(PP_PASSTHROUGH, i0);
1949*da2e3ebdSchin 				break;
1950*da2e3ebdSchin 			case X_PEDANTIC:
1951*da2e3ebdSchin 				ppop(PP_PEDANTIC, i0);
1952*da2e3ebdSchin 				break;
1953*da2e3ebdSchin 			case X_PLUSCOMMENT:
1954*da2e3ebdSchin 				ppop(PP_PLUSCOMMENT, i0);
1955*da2e3ebdSchin 				break;
1956*da2e3ebdSchin 			case X_PLUSPLUS:
1957*da2e3ebdSchin 				ppop(PP_PLUSPLUS, i0);
1958*da2e3ebdSchin 				break;
1959*da2e3ebdSchin 			case X_PLUSSPLICE:
1960*da2e3ebdSchin 				setoption(PLUSSPLICE, i0);
1961*da2e3ebdSchin 				break;
1962*da2e3ebdSchin 			case X_PRAGMAEXPAND:
1963*da2e3ebdSchin 				setoption(PRAGMAEXPAND, i0);
1964*da2e3ebdSchin 				break;
1965*da2e3ebdSchin 			case X_PRAGMAFLAGS:
1966*da2e3ebdSchin 				tokop(PP_PRAGMAFLAGS, p3, p, i0, 0);
1967*da2e3ebdSchin 				break;
1968*da2e3ebdSchin 			case X_PREDEFINED:
1969*da2e3ebdSchin 				setoption(PREDEFINED, i0);
1970*da2e3ebdSchin 				break;
1971*da2e3ebdSchin 			case X_PREFIX:
1972*da2e3ebdSchin 				setoption(PREFIX, i0);
1973*da2e3ebdSchin 				break;
1974*da2e3ebdSchin 			case X_PRESERVE:
1975*da2e3ebdSchin 				setoption(PRESERVE, i0);
1976*da2e3ebdSchin 				if (pp.option & PRESERVE)
1977*da2e3ebdSchin 				{
1978*da2e3ebdSchin 					setmode(CATLITERAL, 0);
1979*da2e3ebdSchin 					ppop(PP_COMPATIBILITY, 1);
1980*da2e3ebdSchin 					ppop(PP_TRANSITION, 0);
1981*da2e3ebdSchin 					ppop(PP_PLUSCOMMENT, 1);
1982*da2e3ebdSchin 					ppop(PP_SPACEOUT, 1);
1983*da2e3ebdSchin 					setoption(STRINGSPAN, 1);
1984*da2e3ebdSchin 					setoption(STRINGSPLIT, 0);
1985*da2e3ebdSchin 					ppop(PP_HOSTDIR, "-", 1);
1986*da2e3ebdSchin 				}
1987*da2e3ebdSchin 				break;
1988*da2e3ebdSchin 			case X_PROTOTYPED:
1989*da2e3ebdSchin 				/*
1990*da2e3ebdSchin 				 * this option doesn't bump the token count
1991*da2e3ebdSchin 				 */
1992*da2e3ebdSchin 
1993*da2e3ebdSchin 				n = 1;
1994*da2e3ebdSchin 				directive = ENDIF;
1995*da2e3ebdSchin #if PROTOTYPE
1996*da2e3ebdSchin 				setoption(PROTOTYPED, i0);
1997*da2e3ebdSchin #else
1998*da2e3ebdSchin 				error(1, "preprocessor not compiled with prototype conversion enabled");
1999*da2e3ebdSchin #endif
2000*da2e3ebdSchin 				break;
2001*da2e3ebdSchin 			case X_PROTO:
2002*da2e3ebdSchin 				setoption(NOPROTO, !i0);
2003*da2e3ebdSchin 				break;
2004*da2e3ebdSchin 			case X_QUOTE:
2005*da2e3ebdSchin 				tokop(PP_QUOTE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
2006*da2e3ebdSchin 				break;
2007*da2e3ebdSchin 			case X_READONLY:
2008*da2e3ebdSchin 				setmode(READONLY, i0);
2009*da2e3ebdSchin 				break;
2010*da2e3ebdSchin 			case X_REGUARD:
2011*da2e3ebdSchin 				setoption(REGUARD, i0);
2012*da2e3ebdSchin 				break;
2013*da2e3ebdSchin 			case X_RESERVED:
2014*da2e3ebdSchin 				tokop(PP_RESERVED, p3, p, i0, 0);
2015*da2e3ebdSchin 				break;
2016*da2e3ebdSchin 			case X_SPACEOUT:
2017*da2e3ebdSchin 				if (!(pp.state & (COMPATIBILITY|COMPILE)))
2018*da2e3ebdSchin 					ppop(PP_SPACEOUT, i0);
2019*da2e3ebdSchin 				break;
2020*da2e3ebdSchin 			case X_SPLICECAT:
2021*da2e3ebdSchin 				setoption(SPLICECAT, i0);
2022*da2e3ebdSchin 				break;
2023*da2e3ebdSchin 			case X_SPLICESPACE:
2024*da2e3ebdSchin 				setoption(SPLICESPACE, i0);
2025*da2e3ebdSchin 				break;
2026*da2e3ebdSchin 			case X_STANDARD:
2027*da2e3ebdSchin 				tokop(PP_STANDARD, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
2028*da2e3ebdSchin 				break;
2029*da2e3ebdSchin 			case X_STRICT:
2030*da2e3ebdSchin 				ppop(PP_STRICT, i0);
2031*da2e3ebdSchin 				break;
2032*da2e3ebdSchin 			case X_STRINGSPAN:
2033*da2e3ebdSchin 				setoption(STRINGSPAN, i0);
2034*da2e3ebdSchin 				break;
2035*da2e3ebdSchin 			case X_STRINGSPLIT:
2036*da2e3ebdSchin 				setoption(STRINGSPLIT, i0);
2037*da2e3ebdSchin 				if (pp.option & STRINGSPLIT)
2038*da2e3ebdSchin 					setmode(CATLITERAL, 0);
2039*da2e3ebdSchin 				break;
2040*da2e3ebdSchin 			case X_SYSTEM_HEADER:
2041*da2e3ebdSchin 				if (i0)
2042*da2e3ebdSchin 				{
2043*da2e3ebdSchin 					pp.mode |= HOSTED;
2044*da2e3ebdSchin 					pp.flags |= PP_hosted;
2045*da2e3ebdSchin 					pp.in->flags |= IN_hosted;
2046*da2e3ebdSchin 				}
2047*da2e3ebdSchin 				else
2048*da2e3ebdSchin 				{
2049*da2e3ebdSchin 					pp.mode &= ~HOSTED;
2050*da2e3ebdSchin 					pp.flags &= ~PP_hosted;
2051*da2e3ebdSchin 					pp.in->flags &= ~PP_hosted;
2052*da2e3ebdSchin 				}
2053*da2e3ebdSchin 				break;
2054*da2e3ebdSchin 			case X_TEST:
2055*da2e3ebdSchin 				ppop(PP_TEST, p);
2056*da2e3ebdSchin 				break;
2057*da2e3ebdSchin 			case X_TEXT:
2058*da2e3ebdSchin 				if (!(pp.option & KEEPNOTEXT))
2059*da2e3ebdSchin 					setstate(NOTEXT, !i0);
2060*da2e3ebdSchin 				break;
2061*da2e3ebdSchin 			case X_TRANSITION:
2062*da2e3ebdSchin 				ppop(PP_TRANSITION, i0);
2063*da2e3ebdSchin 				if (pp.state & TRANSITION) ppop(PP_COMPATIBILITY, i0);
2064*da2e3ebdSchin 				break;
2065*da2e3ebdSchin 			case X_TRUNCATE:
2066*da2e3ebdSchin 				ppop(PP_TRUNCATE, i0 ? (p ? strtol(p, NiL, 0) : TRUNCLENGTH) : 0);
2067*da2e3ebdSchin 				break;
2068*da2e3ebdSchin 			case X_VENDOR:
2069*da2e3ebdSchin 				tokop(PP_VENDOR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
2070*da2e3ebdSchin 				break;
2071*da2e3ebdSchin 			case X_VERSION:
2072*da2e3ebdSchin 				if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT))
2073*da2e3ebdSchin 				{
2074*da2e3ebdSchin 					sfsprintf(pp.tmpbuf, MAXTOKEN, "\"%s\"", pp.version);
2075*da2e3ebdSchin 					(*pp.pragma)(dirname(PRAGMA), pp.pass, p3, pp.tmpbuf, !n);
2076*da2e3ebdSchin 					if (pp.linesync && !n)
2077*da2e3ebdSchin 						(*pp.linesync)(error_info.line, error_info.file);
2078*da2e3ebdSchin 					emitted = 1;
2079*da2e3ebdSchin 				}
2080*da2e3ebdSchin 				break;
2081*da2e3ebdSchin 			case X_WARN:
2082*da2e3ebdSchin 				ppop(PP_WARN, i0);
2083*da2e3ebdSchin 				break;
2084*da2e3ebdSchin 			case X_ZEOF:
2085*da2e3ebdSchin 				setoption(ZEOF, i0);
2086*da2e3ebdSchin 				break;
2087*da2e3ebdSchin #if DEBUG
2088*da2e3ebdSchin 			case 0:
2089*da2e3ebdSchin 			case X_INCLUDED:
2090*da2e3ebdSchin 			case X_NOTICED:
2091*da2e3ebdSchin 			case X_OPTION:
2092*da2e3ebdSchin 			case X_STATEMENT:
2093*da2e3ebdSchin 				break;
2094*da2e3ebdSchin 			default:
2095*da2e3ebdSchin 				error(PANIC, "%s: option recognized but not implemented", pp.valbuf);
2096*da2e3ebdSchin 				break;
2097*da2e3ebdSchin #endif
2098*da2e3ebdSchin 			}
2099*da2e3ebdSchin 			*p4 = i2;
2100*da2e3ebdSchin 			if (!n)
2101*da2e3ebdSchin 				goto checkmap;
2102*da2e3ebdSchin 			goto donedirective;
2103*da2e3ebdSchin 		case RENAME:
2104*da2e3ebdSchin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
2105*da2e3ebdSchin 				error(1, "#%s: non-standard directive", pp.token);
2106*da2e3ebdSchin 			if ((c = pplex()) != T_ID)
2107*da2e3ebdSchin 			{
2108*da2e3ebdSchin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
2109*da2e3ebdSchin 				goto eatdirective;
2110*da2e3ebdSchin 			}
2111*da2e3ebdSchin 			if (!(sym = pprefmac(pp.token, REF_DELETE)) || !sym->macro)
2112*da2e3ebdSchin 				goto eatdirective;
2113*da2e3ebdSchin 			if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
2114*da2e3ebdSchin 			{
2115*da2e3ebdSchin 				if (!(pp.option & ALLPOSSIBLE))
2116*da2e3ebdSchin 					error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
2117*da2e3ebdSchin 				goto eatdirective;
2118*da2e3ebdSchin 			}
2119*da2e3ebdSchin 			if ((c = pplex()) != T_ID)
2120*da2e3ebdSchin 			{
2121*da2e3ebdSchin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
2122*da2e3ebdSchin 				goto eatdirective;
2123*da2e3ebdSchin 			}
2124*da2e3ebdSchin 			var.symbol = pprefmac(pp.token, REF_CREATE);
2125*da2e3ebdSchin 			if (mac = var.symbol->macro)
2126*da2e3ebdSchin 			{
2127*da2e3ebdSchin 				if (var.symbol->flags & (SYM_ACTIVE|SYM_READONLY))
2128*da2e3ebdSchin 				{
2129*da2e3ebdSchin 					if (!(pp.option & ALLPOSSIBLE))
2130*da2e3ebdSchin 						error(2, "%s: macro is %s", var.symbol->name, (var.symbol->flags & SYM_READONLY) ? "readonly" : "active");
2131*da2e3ebdSchin 					goto eatdirective;
2132*da2e3ebdSchin 				}
2133*da2e3ebdSchin 				if (!(pp.mode & HOSTED) || !(var.symbol->flags & SYM_INITIAL))
2134*da2e3ebdSchin 					error(1, "%s redefined", var.symbol->name);
2135*da2e3ebdSchin 				if (mac->formals) free(mac->formals);
2136*da2e3ebdSchin 				free(mac->value);
2137*da2e3ebdSchin 				free(mac);
2138*da2e3ebdSchin 			}
2139*da2e3ebdSchin 			ppfsm(FSM_MACRO, var.symbol->name);
2140*da2e3ebdSchin 			var.symbol->flags = sym->flags;
2141*da2e3ebdSchin 			sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
2142*da2e3ebdSchin 			var.symbol->macro = sym->macro;
2143*da2e3ebdSchin 			sym->macro = 0;
2144*da2e3ebdSchin 			break;
2145*da2e3ebdSchin 		case UNDEF:
2146*da2e3ebdSchin 			if ((c = pplex()) != T_ID)
2147*da2e3ebdSchin 			{
2148*da2e3ebdSchin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
2149*da2e3ebdSchin 				goto eatdirective;
2150*da2e3ebdSchin 			}
2151*da2e3ebdSchin 			if (sym = pprefmac(pp.token, REF_DELETE))
2152*da2e3ebdSchin 			{
2153*da2e3ebdSchin 				if (mac = sym->macro)
2154*da2e3ebdSchin 				{
2155*da2e3ebdSchin 					if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
2156*da2e3ebdSchin 					{
2157*da2e3ebdSchin 						if (!(pp.option & ALLPOSSIBLE))
2158*da2e3ebdSchin 							error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
2159*da2e3ebdSchin 						goto eatdirective;
2160*da2e3ebdSchin 					}
2161*da2e3ebdSchin 					if (mac->formals) free(mac->formals);
2162*da2e3ebdSchin 					free(mac->value);
2163*da2e3ebdSchin 					free(mac);
2164*da2e3ebdSchin 					mac = sym->macro = 0;
2165*da2e3ebdSchin 				}
2166*da2e3ebdSchin 				if ((pp.option & (DEFINITIONS|PREDEFINITIONS|REGUARD)) && !sym->hidden && !(sym->flags & SYM_MULTILINE) && ((pp.option & PREDEFINITIONS) || !(pp.mode & INIT)) && ((pp.option & (DEFINITIONS|PREDEFINITIONS)) || !(pp.state & NOTEXT)))
2167*da2e3ebdSchin 				{
2168*da2e3ebdSchin 					ppsync();
2169*da2e3ebdSchin 					ppprintf("#%s %s", dirname(UNDEF), sym->name);
2170*da2e3ebdSchin 					emitted = 1;
2171*da2e3ebdSchin 				}
2172*da2e3ebdSchin 				sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
2173*da2e3ebdSchin 				n2 = error_info.line;
2174*da2e3ebdSchin 				goto benign;
2175*da2e3ebdSchin 			}
2176*da2e3ebdSchin 			else pprefmac(pp.token, REF_UNDEF);
2177*da2e3ebdSchin 			break;
2178*da2e3ebdSchin #if DEBUG
2179*da2e3ebdSchin 		default:
2180*da2e3ebdSchin 			error(PANIC, "#%s: directive recognized but not implemented", pp.token);
2181*da2e3ebdSchin 			goto eatdirective;
2182*da2e3ebdSchin #endif
2183*da2e3ebdSchin 		}
2184*da2e3ebdSchin 		break;
2185*da2e3ebdSchin 	case '\n':
2186*da2e3ebdSchin 		break;
2187*da2e3ebdSchin 	default:
2188*da2e3ebdSchin 		error(1, "%s: invalid directive name", pptokstr(pp.token, 0));
2189*da2e3ebdSchin 		goto eatdirective;
2190*da2e3ebdSchin 	}
2191*da2e3ebdSchin  enddirective:
2192*da2e3ebdSchin #if COMPATIBLE
2193*da2e3ebdSchin 	if (c != '\n' && !(pp.state & COMPATIBILITY))
2194*da2e3ebdSchin #else
2195*da2e3ebdSchin 	if (c != '\n')
2196*da2e3ebdSchin #endif
2197*da2e3ebdSchin 	{
2198*da2e3ebdSchin 		pp.state |= DISABLE|NOSPACE;
2199*da2e3ebdSchin 		if ((c = pplex()) != '\n' && (pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC)
2200*da2e3ebdSchin 			error(1, "%s: invalid characters after directive", pptokstr(pp.token, 0));
2201*da2e3ebdSchin 	}
2202*da2e3ebdSchin  eatdirective:
2203*da2e3ebdSchin 	if (c != '\n')
2204*da2e3ebdSchin 	{
2205*da2e3ebdSchin 		pp.state |= DISABLE;
2206*da2e3ebdSchin 		while (pplex() != '\n');
2207*da2e3ebdSchin 	}
2208*da2e3ebdSchin  donedirective:
2209*da2e3ebdSchin #if _HUH_2002_05_09
2210*da2e3ebdSchin 	if (!(pp.state & EOF2NL))
2211*da2e3ebdSchin 		error(2, "%s in directive", pptokchr(0));
2212*da2e3ebdSchin #endif
2213*da2e3ebdSchin 	pp.state &= ~RESTORE;
2214*da2e3ebdSchin 	pp.mode &= ~RELAX;
2215*da2e3ebdSchin 	if (!(*pp.control & SKIP))
2216*da2e3ebdSchin 	{
2217*da2e3ebdSchin 		pp.state |= restore;
2218*da2e3ebdSchin 		switch (directive)
2219*da2e3ebdSchin 		{
2220*da2e3ebdSchin 		case LINE:
2221*da2e3ebdSchin 			return 0;
2222*da2e3ebdSchin 		case INCLUDE:
2223*da2e3ebdSchin 			if (pp.include)
2224*da2e3ebdSchin 			{
2225*da2e3ebdSchin 				error_info.line++;
2226*da2e3ebdSchin 				PUSH_FILE(pp.include, n);
2227*da2e3ebdSchin 				if (!pp.vendor && (pp.found->type & TYPE_VENDOR))
2228*da2e3ebdSchin 					pp.vendor = 1;
2229*da2e3ebdSchin 				pp.include = 0;
2230*da2e3ebdSchin 				return 0;
2231*da2e3ebdSchin 			}
2232*da2e3ebdSchin 			if (pp.incref)
2233*da2e3ebdSchin 				(*pp.incref)(error_info.file, ppgetfile(pp.path)->name, error_info.line, PP_SYNC_IGNORE);
2234*da2e3ebdSchin 			else if (pp.linesync && pp.macref)
2235*da2e3ebdSchin 			{
2236*da2e3ebdSchin 				pp.flags |= PP_lineignore;
2237*da2e3ebdSchin 				(*pp.linesync)(error_info.line, ppgetfile(pp.path)->name);
2238*da2e3ebdSchin 			}
2239*da2e3ebdSchin 			/*FALLTHROUGH*/
2240*da2e3ebdSchin 		default:
2241*da2e3ebdSchin 			pp.in->flags |= IN_tokens;
2242*da2e3ebdSchin 			/*FALLTHROUGH*/
2243*da2e3ebdSchin 		case ENDIF:
2244*da2e3ebdSchin 			error_info.line++;
2245*da2e3ebdSchin 			if (emitted)
2246*da2e3ebdSchin 			{
2247*da2e3ebdSchin 				ppputchar('\n');
2248*da2e3ebdSchin 				ppcheckout();
2249*da2e3ebdSchin 			}
2250*da2e3ebdSchin 			else
2251*da2e3ebdSchin 			{
2252*da2e3ebdSchin 				pp.state |= HIDDEN;
2253*da2e3ebdSchin 				pp.hidden++;
2254*da2e3ebdSchin 			}
2255*da2e3ebdSchin 			return 0;
2256*da2e3ebdSchin 		}
2257*da2e3ebdSchin 	}
2258*da2e3ebdSchin 	pp.state |= restore|HIDDEN|SKIPCONTROL;
2259*da2e3ebdSchin 	pp.hidden++;
2260*da2e3ebdSchin 	pp.level++;
2261*da2e3ebdSchin 	error_info.line++;
2262*da2e3ebdSchin 	return 0;
2263*da2e3ebdSchin }
2264*da2e3ebdSchin 
2265*da2e3ebdSchin /*
2266*da2e3ebdSchin  * grow the pp nesting control stack
2267*da2e3ebdSchin  */
2268*da2e3ebdSchin 
2269*da2e3ebdSchin void
2270*da2e3ebdSchin ppnest(void)
2271*da2e3ebdSchin {
2272*da2e3ebdSchin 	register struct ppinstk*	ip;
2273*da2e3ebdSchin 	int				oz;
2274*da2e3ebdSchin 	int				nz;
2275*da2e3ebdSchin 	long				adjust;
2276*da2e3ebdSchin 	long*				op;
2277*da2e3ebdSchin 	long*				np;
2278*da2e3ebdSchin 
2279*da2e3ebdSchin 	oz = pp.constack;
2280*da2e3ebdSchin 	op = pp.maxcon - oz + 1;
2281*da2e3ebdSchin 	nz = oz * 2;
2282*da2e3ebdSchin 	np = newof(op, long, nz, 0);
2283*da2e3ebdSchin 	if (adjust = (np - op))
2284*da2e3ebdSchin 	{
2285*da2e3ebdSchin 		ip = pp.in;
2286*da2e3ebdSchin 		do
2287*da2e3ebdSchin 		{
2288*da2e3ebdSchin 			if (ip->control)
2289*da2e3ebdSchin 				ip->control += adjust;
2290*da2e3ebdSchin 		} while (ip = ip->prev);
2291*da2e3ebdSchin 	}
2292*da2e3ebdSchin 	pp.control = np + oz;
2293*da2e3ebdSchin 	pp.constack = nz;
2294*da2e3ebdSchin 	pp.maxcon = np + nz - 1;
2295*da2e3ebdSchin }
2296