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