1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*b30d1939SAndy Fiddaman * Copyright (c) 1986-2011 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6*b30d1939SAndy Fiddaman * Eclipse Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10*b30d1939SAndy Fiddaman * http://www.eclipse.org/org/documents/epl-v10.html *
11*b30d1939SAndy Fiddaman * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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
assert(int op,char * pred,char * args)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
tokop(int op,char * name,register char * s,register int n,int flags)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*
macsym(int tok)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*
getline(register char * p,char * x,int disable)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
regfatal(regex_t * p,int level,int code)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
ppcontrol(void)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;
45334f9b3eeSRoland Mainz pp.in->flags |= IN_noguard;
454da2e3ebdSchin switch (c = pplex())
455da2e3ebdSchin {
456da2e3ebdSchin case T_STRING:
457da2e3ebdSchin p = pp.token;
458da2e3ebdSchin do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING);
459da2e3ebdSchin *pp.token = 0;
460da2e3ebdSchin pp.token = p;
461da2e3ebdSchin /*FALLTHROUGH*/
462da2e3ebdSchin case T_HEADER:
463da2e3ebdSchin header:
464da2e3ebdSchin if (!*pp.token)
465da2e3ebdSchin {
466da2e3ebdSchin error(2, "#%s: null file name", dirname(INCLUDE));
467da2e3ebdSchin break;
468da2e3ebdSchin }
469da2e3ebdSchin if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX)))
470da2e3ebdSchin error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token);
471da2e3ebdSchin n = ppsearch(pp.token, c, SEARCH_INCLUDE);
472da2e3ebdSchin break;
473da2e3ebdSchin case '<':
474da2e3ebdSchin /*
475da2e3ebdSchin * HEADEREXPAND|HEADEREXPANDALL gets us here
476da2e3ebdSchin */
477da2e3ebdSchin
478da2e3ebdSchin if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0)))
479da2e3ebdSchin error(3, "out of space");
480da2e3ebdSchin pp.state &= ~NOSPACE;
481da2e3ebdSchin while ((c = pplex()) && c != '>')
482da2e3ebdSchin {
483da2e3ebdSchin v = p + 1;
484da2e3ebdSchin STRCOPY(p, pp.token, s);
485da2e3ebdSchin if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO)
486da2e3ebdSchin p--;
487da2e3ebdSchin }
488da2e3ebdSchin pp.state |= NOSPACE;
489da2e3ebdSchin *p++ = 0;
490da2e3ebdSchin memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf);
491da2e3ebdSchin c = T_HEADER;
492da2e3ebdSchin goto header;
493da2e3ebdSchin default:
494da2e3ebdSchin error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE));
495da2e3ebdSchin goto eatdirective;
496da2e3ebdSchin }
497da2e3ebdSchin goto enddirective;
498da2e3ebdSchin case 0:
499da2e3ebdSchin {
500da2e3ebdSchin regmatch_t match[10];
501da2e3ebdSchin
502da2e3ebdSchin /*UNDENT*/
503da2e3ebdSchin p = pp.valbuf;
504da2e3ebdSchin *p++ = '#';
505da2e3ebdSchin STRCOPY(p, pp.token, s);
506da2e3ebdSchin p0 = p;
507da2e3ebdSchin pp.mode |= EXPOSE;
508da2e3ebdSchin pp.state |= HEADER;
509da2e3ebdSchin p6 = getline(p, &pp.valbuf[MAXTOKEN], 0);
510da2e3ebdSchin pp.state &= ~HEADER;
511da2e3ebdSchin pp.mode &= ~EXPOSE;
512da2e3ebdSchin if (!p6)
513da2e3ebdSchin {
514da2e3ebdSchin *p0 = 0;
515da2e3ebdSchin error(2, "%s: directive too long", pp.valbuf);
516da2e3ebdSchin c = 0;
517da2e3ebdSchin goto eatdirective;
518da2e3ebdSchin }
519da2e3ebdSchin p1 = p2 = p3 = p4 = 0;
520da2e3ebdSchin p5 = *p ? p + 1 : 0;
521da2e3ebdSchin checkmap:
522da2e3ebdSchin i0 = *p0;
523da2e3ebdSchin p = pp.valbuf;
524da2e3ebdSchin var.best = 0;
525da2e3ebdSchin n = 0;
526da2e3ebdSchin for (map = (struct map*)pp.maps; map; map = map->next)
527da2e3ebdSchin if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0)))
528da2e3ebdSchin {
529da2e3ebdSchin if ((c = match[0].rm_eo - match[0].rm_so) > n)
530da2e3ebdSchin {
531da2e3ebdSchin n = c;
532da2e3ebdSchin var.best = map;
533da2e3ebdSchin }
534da2e3ebdSchin }
535da2e3ebdSchin else if (i1 != REG_NOMATCH)
536*b30d1939SAndy Fiddaman regfatal(&map->re, 4, i1);
537da2e3ebdSchin c = '\n';
538da2e3ebdSchin if (map = var.best)
539da2e3ebdSchin {
540da2e3ebdSchin if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX)))
541da2e3ebdSchin {
542da2e3ebdSchin *p0 = 0;
543da2e3ebdSchin if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA)))
544da2e3ebdSchin error(1, "%s: non-standard directive", p);
545da2e3ebdSchin *p0 = i0;
546da2e3ebdSchin }
547da2e3ebdSchin if (!(*pp.control & SKIP))
548da2e3ebdSchin {
549da2e3ebdSchin n = 0;
550da2e3ebdSchin for (edit = map->edit; edit; edit = edit->next)
551da2e3ebdSchin if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0)))
552da2e3ebdSchin {
553da2e3ebdSchin n++;
554da2e3ebdSchin if (i0 = regsubexec(&edit->re, p, elementsof(match), match))
555*b30d1939SAndy Fiddaman regfatal(&edit->re, 4, i0);
556da2e3ebdSchin p = edit->re.re_sub->re_buf;
557da2e3ebdSchin if (edit->re.re_sub->re_flags & REG_SUB_STOP)
558da2e3ebdSchin break;
559da2e3ebdSchin }
560da2e3ebdSchin else if (i0 != REG_NOMATCH)
561*b30d1939SAndy Fiddaman regfatal(&edit->re, 4, i0);
562da2e3ebdSchin if (n && *p)
563da2e3ebdSchin {
564da2e3ebdSchin p1 = s = oldof(0, char, 0, strlen(p) + 32);
565da2e3ebdSchin while (*s = *p++) s++;
566da2e3ebdSchin debug((-4, "map: %s", p1));
567da2e3ebdSchin *s++ = '\n';
568da2e3ebdSchin *s = 0;
569da2e3ebdSchin error_info.line++;
570da2e3ebdSchin PUSH_RESCAN(p1);
571da2e3ebdSchin error_info.line--;
572da2e3ebdSchin directive = LINE;
573da2e3ebdSchin }
574da2e3ebdSchin }
575da2e3ebdSchin goto donedirective;
576da2e3ebdSchin }
577da2e3ebdSchin if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX))))
578da2e3ebdSchin {
579da2e3ebdSchin *p0 = 0;
580da2e3ebdSchin error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0));
581da2e3ebdSchin *p0 = i0;
582da2e3ebdSchin }
583da2e3ebdSchin pass:
584da2e3ebdSchin if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT)))
585da2e3ebdSchin {
586da2e3ebdSchin *p0 = 0;
587da2e3ebdSchin if (p2) *p2 = 0;
588da2e3ebdSchin if (p4)
589da2e3ebdSchin {
590da2e3ebdSchin if (p4 == p5)
591da2e3ebdSchin {
592da2e3ebdSchin p5 = strcpy(pp.tmpbuf, p5);
593da2e3ebdSchin if (p = strchr(p5, MARK))
594da2e3ebdSchin {
595da2e3ebdSchin s = p;
596da2e3ebdSchin while (*p)
597da2e3ebdSchin if ((*s++ = *p++) == MARK && *p == MARK) p++;
598da2e3ebdSchin *s = 0;
599da2e3ebdSchin }
600da2e3ebdSchin }
601da2e3ebdSchin *p4 = 0;
602da2e3ebdSchin }
603da2e3ebdSchin if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1))
604da2e3ebdSchin {
605da2e3ebdSchin s = p;
606da2e3ebdSchin while (p < p6) switch (*s++ = *p++)
607da2e3ebdSchin {
608da2e3ebdSchin case 0:
609da2e3ebdSchin s = p;
610da2e3ebdSchin break;
611da2e3ebdSchin case MARK:
612da2e3ebdSchin p++;
613da2e3ebdSchin break;
614da2e3ebdSchin }
615da2e3ebdSchin *s = 0;
616da2e3ebdSchin }
617da2e3ebdSchin (*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0);
618da2e3ebdSchin emitted = 1;
619da2e3ebdSchin }
620da2e3ebdSchin goto donedirective;
621da2e3ebdSchin
622da2e3ebdSchin /*INDENT*/
623da2e3ebdSchin }
624da2e3ebdSchin }
625da2e3ebdSchin if (*pp.control & SKIP) goto eatdirective;
626da2e3ebdSchin switch (directive)
627da2e3ebdSchin {
628da2e3ebdSchin #if MACDEF
629da2e3ebdSchin case ENDMAC:
630da2e3ebdSchin c = pplex();
631da2e3ebdSchin error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC));
632da2e3ebdSchin goto enddirective;
633da2e3ebdSchin #endif
634da2e3ebdSchin #if MACDEF
635da2e3ebdSchin case MACDEF:
636da2e3ebdSchin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
637da2e3ebdSchin error(1, "#%s: non-standard directive", pp.token);
638da2e3ebdSchin #endif
639*b30d1939SAndy Fiddaman /* FALLTHROUGH */
640da2e3ebdSchin case DEFINE:
641da2e3ebdSchin n2 = error_info.line;
642da2e3ebdSchin if ((c = pplex()) == '#' && directive == DEFINE)
643da2e3ebdSchin goto assertion;
644da2e3ebdSchin if (c == '<')
645da2e3ebdSchin {
646da2e3ebdSchin n = 1;
647da2e3ebdSchin c = pplex();
648da2e3ebdSchin }
649da2e3ebdSchin else
650da2e3ebdSchin n = 0;
651da2e3ebdSchin if (!(sym = macsym(c)))
652da2e3ebdSchin goto eatdirective;
653da2e3ebdSchin if (pp.truncate)
654da2e3ebdSchin ppfsm(FSM_MACRO, pp.token);
655da2e3ebdSchin mac = sym->macro;
656da2e3ebdSchin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value)
657da2e3ebdSchin goto eatdirective;
658da2e3ebdSchin if (n)
659da2e3ebdSchin goto tuple;
660da2e3ebdSchin old = *mac;
661da2e3ebdSchin i0 = sym->flags;
662da2e3ebdSchin sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
663da2e3ebdSchin #if MACDEF
664da2e3ebdSchin if (directive == MACDEF)
665da2e3ebdSchin sym->flags |= SYM_MULTILINE;
666da2e3ebdSchin #endif
667da2e3ebdSchin mac->arity = 0;
668da2e3ebdSchin mac->formals = 0;
669da2e3ebdSchin mac->value = 0;
670da2e3ebdSchin pp.state &= ~NOSPACE;
671da2e3ebdSchin pp.state |= DEFINITION|NOEXPAND;
672da2e3ebdSchin switch (c = pplex())
673da2e3ebdSchin {
674da2e3ebdSchin case '(':
675da2e3ebdSchin sym->flags |= SYM_FUNCTION;
676da2e3ebdSchin pp.state |= NOSPACE;
677da2e3ebdSchin #if MACKEYARGS
678da2e3ebdSchin if (pp.option & KEYARGS)
679da2e3ebdSchin {
680da2e3ebdSchin n = 2 * MAXTOKEN;
681da2e3ebdSchin p = mac->formals = oldof(0, char, 0, n);
682da2e3ebdSchin if ((c = pplex()) == T_ID) for (;;)
683da2e3ebdSchin {
684da2e3ebdSchin if (mac->arity < MAXFORMALS)
685da2e3ebdSchin {
686da2e3ebdSchin if (mac->arity) p++;
687da2e3ebdSchin formargs[mac->arity] = p;
688da2e3ebdSchin STRAPP(p, pp.token, s);
689da2e3ebdSchin formvals[mac->arity++] = p1 = p;
690da2e3ebdSchin if (mac->arity == 1) *p++ = ' ';
691da2e3ebdSchin *p++ = ' ';
692da2e3ebdSchin *p = 0;
693da2e3ebdSchin }
694da2e3ebdSchin else error(2, "%s: formal argument %s ignored", sym->name, pp.token);
695da2e3ebdSchin switch (c = pplex())
696da2e3ebdSchin {
697da2e3ebdSchin case '=':
698da2e3ebdSchin c = pplex();
699da2e3ebdSchin break;
700da2e3ebdSchin case ',':
701da2e3ebdSchin break;
702da2e3ebdSchin default:
703da2e3ebdSchin goto endformals;
704da2e3ebdSchin }
705da2e3ebdSchin pp.state &= ~NOSPACE;
706da2e3ebdSchin p0 = 0;
707da2e3ebdSchin for (;;)
708da2e3ebdSchin {
709da2e3ebdSchin switch (c)
710da2e3ebdSchin {
711da2e3ebdSchin case '\n':
712da2e3ebdSchin goto endformals;
713da2e3ebdSchin case '(':
714da2e3ebdSchin p0++;
715da2e3ebdSchin break;
716da2e3ebdSchin case ')':
717da2e3ebdSchin if (!p0--)
718da2e3ebdSchin {
719da2e3ebdSchin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
720da2e3ebdSchin goto endformals;
721da2e3ebdSchin }
722da2e3ebdSchin break;
723da2e3ebdSchin case ',':
724da2e3ebdSchin if (!p0)
725da2e3ebdSchin {
726da2e3ebdSchin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
727da2e3ebdSchin goto nextformal;
728da2e3ebdSchin }
729da2e3ebdSchin break;
730da2e3ebdSchin case ' ':
731da2e3ebdSchin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue;
732da2e3ebdSchin break;
733da2e3ebdSchin }
734da2e3ebdSchin STRCOPY(p, pp.token, s);
735da2e3ebdSchin if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals)
736da2e3ebdSchin {
737da2e3ebdSchin n1 = s - mac->formals;
738da2e3ebdSchin for (n = 0; n < mac->arity; n++)
739da2e3ebdSchin {
740da2e3ebdSchin formargs[n] += n1;
741da2e3ebdSchin formvals[n] += n1;
742da2e3ebdSchin }
743da2e3ebdSchin c = p - mac->formals;
744da2e3ebdSchin mac->formals = s;
745da2e3ebdSchin p = mac->formals + c;
746da2e3ebdSchin }
747da2e3ebdSchin c = pplex();
748da2e3ebdSchin }
749da2e3ebdSchin nextformal:
750da2e3ebdSchin pp.state |= NOSPACE;
751da2e3ebdSchin if ((c = pplex()) != T_ID)
752da2e3ebdSchin {
753da2e3ebdSchin c = ',';
754da2e3ebdSchin break;
755da2e3ebdSchin }
756da2e3ebdSchin }
757da2e3ebdSchin endformals: /*NOP*/;
758da2e3ebdSchin }
759da2e3ebdSchin else
760da2e3ebdSchin #endif
761da2e3ebdSchin {
762da2e3ebdSchin p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1));
763da2e3ebdSchin c = pplex();
764da2e3ebdSchin #if COMPATIBLE
765da2e3ebdSchin if ((pp.state & COMPATIBILITY) && c == ',')
766da2e3ebdSchin {
767da2e3ebdSchin if ((pp.state & WARN) && !(pp.mode & HOSTED))
768da2e3ebdSchin error(1, "%s: macro formal argument expected", sym->name);
769da2e3ebdSchin while ((c = pplex()) == ',');
770da2e3ebdSchin }
771da2e3ebdSchin #endif
772da2e3ebdSchin for (;;)
773da2e3ebdSchin {
774da2e3ebdSchin if (c == T_VARIADIC)
775da2e3ebdSchin {
776da2e3ebdSchin if (sym->flags & SYM_VARIADIC)
777da2e3ebdSchin error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
778da2e3ebdSchin sym->flags |= SYM_VARIADIC;
779da2e3ebdSchin v = __va_args__;
780da2e3ebdSchin }
781da2e3ebdSchin else if (c == T_ID)
782da2e3ebdSchin {
783da2e3ebdSchin v = pp.token;
784da2e3ebdSchin if (sym->flags & SYM_VARIADIC)
785da2e3ebdSchin error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v);
786da2e3ebdSchin else if (streq(v, __va_args__))
787da2e3ebdSchin error(2, "%s: %s: invalid macro formal argument", sym->name, v);
788da2e3ebdSchin }
789da2e3ebdSchin else
790da2e3ebdSchin break;
791da2e3ebdSchin if (mac->arity < MAXFORMALS)
792da2e3ebdSchin {
793da2e3ebdSchin for (n = 0; n < mac->arity; n++)
794da2e3ebdSchin if (streq(formargs[n], v))
795da2e3ebdSchin error(2, "%s: %s: duplicate macro formal argument", sym->name, v);
796da2e3ebdSchin formargs[mac->arity++] = p;
797da2e3ebdSchin STRAPP(p, v, s);
798da2e3ebdSchin }
799da2e3ebdSchin else
800da2e3ebdSchin error(2, "%s: %s: macro formal argument ignored", sym->name, v);
801da2e3ebdSchin if ((c = pplex()) == ',')
802da2e3ebdSchin {
803da2e3ebdSchin c = pplex();
804da2e3ebdSchin #if COMPATIBLE
805da2e3ebdSchin if ((pp.state & COMPATIBILITY) && c == ',')
806da2e3ebdSchin {
807da2e3ebdSchin if ((pp.state & WARN) && !(pp.mode & HOSTED))
808da2e3ebdSchin error(1, "%s: macro formal argument expected", sym->name);
809da2e3ebdSchin while ((c = pplex()) == ',');
810da2e3ebdSchin }
811da2e3ebdSchin #endif
812da2e3ebdSchin }
813da2e3ebdSchin else if (c != T_VARIADIC)
814da2e3ebdSchin break;
815da2e3ebdSchin else
816da2e3ebdSchin {
817da2e3ebdSchin if (sym->flags & SYM_VARIADIC)
818da2e3ebdSchin error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
819da2e3ebdSchin sym->flags |= SYM_VARIADIC;
820da2e3ebdSchin c = pplex();
821da2e3ebdSchin break;
822da2e3ebdSchin }
823da2e3ebdSchin }
824da2e3ebdSchin if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals)
825da2e3ebdSchin {
826da2e3ebdSchin n1 = s - mac->formals;
827da2e3ebdSchin for (n = 0; n < mac->arity; n++)
828da2e3ebdSchin formargs[n] += n1;
829da2e3ebdSchin mac->formals = s;
830da2e3ebdSchin }
831da2e3ebdSchin }
832da2e3ebdSchin if (!mac->arity)
833da2e3ebdSchin {
834da2e3ebdSchin free(mac->formals);
835da2e3ebdSchin mac->formals = 0;
836da2e3ebdSchin }
837da2e3ebdSchin switch (c)
838da2e3ebdSchin {
839da2e3ebdSchin case ')':
840da2e3ebdSchin #if MACKEYARGS
841da2e3ebdSchin pp.state |= NOEXPAND|NOSPACE;
842da2e3ebdSchin #else
843da2e3ebdSchin pp.state |= NOEXPAND;
844da2e3ebdSchin #endif
845da2e3ebdSchin c = pplex();
846da2e3ebdSchin break;
847da2e3ebdSchin default:
848da2e3ebdSchin error(2, "%s: invalid macro formal argument list", sym->name);
849da2e3ebdSchin if (mac->formals)
850da2e3ebdSchin {
851da2e3ebdSchin free(mac->formals);
852da2e3ebdSchin mac->formals = 0;
853da2e3ebdSchin mac->arity = 0;
854da2e3ebdSchin }
855da2e3ebdSchin free(mac);
856da2e3ebdSchin sym->macro = 0;
857da2e3ebdSchin goto eatdirective;
858da2e3ebdSchin }
859da2e3ebdSchin pp.state &= ~NOSPACE;
860da2e3ebdSchin break;
861da2e3ebdSchin case ' ':
862da2e3ebdSchin case '\t':
863da2e3ebdSchin c = pplex();
864da2e3ebdSchin break;
865da2e3ebdSchin }
866da2e3ebdSchin n = 2 * MAXTOKEN;
867da2e3ebdSchin #if MACKEYARGS
868da2e3ebdSchin p1 = p;
869da2e3ebdSchin #endif
870da2e3ebdSchin p = mac->value = oldof(0, char, 0, n);
871da2e3ebdSchin var.type = 0;
872da2e3ebdSchin n1 = 0;
873da2e3ebdSchin #if MACDEF
874da2e3ebdSchin i2 = i3 = 0;
875da2e3ebdSchin n3 = pp.state;
876da2e3ebdSchin #endif
877da2e3ebdSchin if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
878da2e3ebdSchin switch (c)
879da2e3ebdSchin {
880da2e3ebdSchin case '+':
881da2e3ebdSchin case '-':
882da2e3ebdSchin case '&':
883da2e3ebdSchin case '|':
884da2e3ebdSchin case '<':
885da2e3ebdSchin case '>':
886da2e3ebdSchin case ':':
887da2e3ebdSchin case '=':
888da2e3ebdSchin *p++ = ' ';
889da2e3ebdSchin break;
890da2e3ebdSchin }
891da2e3ebdSchin o = 0;
892da2e3ebdSchin for (;;)
893da2e3ebdSchin {
894da2e3ebdSchin switch (c)
895da2e3ebdSchin {
896da2e3ebdSchin case T_ID:
897da2e3ebdSchin for (c = 0; c < mac->arity; c++)
898da2e3ebdSchin if (streq(formargs[c], pp.token))
899da2e3ebdSchin {
900da2e3ebdSchin #if COMPATIBLE
901da2e3ebdSchin if (!(pp.state & COMPATIBILITY))
902da2e3ebdSchin #endif
903da2e3ebdSchin if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' ';
904da2e3ebdSchin *p++ = MARK;
905da2e3ebdSchin #if COMPATIBLE
906da2e3ebdSchin if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C';
907da2e3ebdSchin else
908da2e3ebdSchin #endif
909da2e3ebdSchin *p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A';
910da2e3ebdSchin *p++ = c + ARGOFFSET;
9117c2fbfb3SApril Chin if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX)) && var.type != TOK_TOKCAT && !(var.type & TOK_ID))
9127c2fbfb3SApril Chin {
9137c2fbfb3SApril Chin s = pp.in->nextchr;
9147c2fbfb3SApril Chin while ((c = *s++) && (c == ' ' || c == '\t'));
9157c2fbfb3SApril Chin if (c == '\n')
9167c2fbfb3SApril Chin c = 0;
9177c2fbfb3SApril Chin else if (c == '*' && *s == ')')
9187c2fbfb3SApril Chin c = ')';
9197c2fbfb3SApril Chin else if (c == '=' || ppisidig(c) || c == *s || *s == '=')
9207c2fbfb3SApril Chin c = 0;
9217c2fbfb3SApril Chin if (o != '.' && o != T_PTRMEM)
9227c2fbfb3SApril Chin {
9237c2fbfb3SApril Chin if ((var.type & TOK_ID) || o == ' ' || ppisseparate(o))
9247c2fbfb3SApril Chin o = 0;
9257c2fbfb3SApril 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 == ')'))
9267c2fbfb3SApril 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);
9277c2fbfb3SApril Chin }
9287c2fbfb3SApril Chin }
929da2e3ebdSchin var.type = TOK_FORMAL|TOK_ID;
930da2e3ebdSchin c = '>';
931da2e3ebdSchin goto checkvalue;
932da2e3ebdSchin }
933da2e3ebdSchin if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token))
934da2e3ebdSchin {
935da2e3ebdSchin case V_DEFAULT:
936da2e3ebdSchin case V_EMPTY:
937da2e3ebdSchin sym->flags |= SYM_EMPTY;
938da2e3ebdSchin break;
939da2e3ebdSchin }
940da2e3ebdSchin else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden)
941da2e3ebdSchin {
942da2e3ebdSchin for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev);
943da2e3ebdSchin p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token);
944da2e3ebdSchin var.type = TOK_ID;
945da2e3ebdSchin goto checkvalue;
946da2e3ebdSchin }
947da2e3ebdSchin var.type = TOK_ID;
948da2e3ebdSchin break;
949da2e3ebdSchin case '#':
950da2e3ebdSchin var.type = 0;
951da2e3ebdSchin #if MACDEF
952da2e3ebdSchin if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break;
953da2e3ebdSchin #else
954da2e3ebdSchin if (!(sym->flags & SYM_FUNCTION)) break;
955da2e3ebdSchin #endif
956da2e3ebdSchin pp.state |= NOSPACE;
957da2e3ebdSchin c = pplex();
958da2e3ebdSchin if (c == '@')
959da2e3ebdSchin {
960da2e3ebdSchin c = pplex();
961da2e3ebdSchin i4 = 'S';
962da2e3ebdSchin }
963da2e3ebdSchin else i4 = 'Q';
964da2e3ebdSchin pp.state &= ~NOSPACE;
965da2e3ebdSchin if (c != T_ID) c = mac->arity;
966da2e3ebdSchin else for (c = 0; c < mac->arity; c++)
967da2e3ebdSchin if (streq(formargs[c], pp.token))
968da2e3ebdSchin break;
969da2e3ebdSchin if (c >= mac->arity)
970da2e3ebdSchin {
971da2e3ebdSchin #if MACDEF
972da2e3ebdSchin if (sym->flags & SYM_MULTILINE)
973da2e3ebdSchin {
974da2e3ebdSchin if (n3 & NEWLINE)
975da2e3ebdSchin {
976da2e3ebdSchin pp.state &= ~NOEXPAND;
977da2e3ebdSchin switch ((int)hashref(pp.dirtab, pp.token))
978da2e3ebdSchin {
979da2e3ebdSchin case ENDMAC:
980da2e3ebdSchin if (!i2--) goto gotdefinition;
981da2e3ebdSchin break;
982da2e3ebdSchin case INCLUDE:
983da2e3ebdSchin /* PARSE HEADER constant */
984da2e3ebdSchin break;
985da2e3ebdSchin case MACDEF:
986da2e3ebdSchin i2++;
987da2e3ebdSchin break;
988da2e3ebdSchin }
989da2e3ebdSchin *p++ = '#';
990da2e3ebdSchin }
991da2e3ebdSchin }
992da2e3ebdSchin else
993da2e3ebdSchin #endif
994da2e3ebdSchin #if COMPATIBLE
995da2e3ebdSchin if (pp.state & COMPATIBILITY) *p++ = '#';
996da2e3ebdSchin else
997da2e3ebdSchin #endif
998da2e3ebdSchin error(2, "# must precede a formal parameter");
999da2e3ebdSchin }
1000da2e3ebdSchin else
1001da2e3ebdSchin {
1002da2e3ebdSchin if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' ';
1003da2e3ebdSchin *p++ = MARK;
1004da2e3ebdSchin *p++ = i4;
1005da2e3ebdSchin *p++ = c + ARGOFFSET;
1006da2e3ebdSchin goto checkvalue;
1007da2e3ebdSchin }
1008da2e3ebdSchin break;
1009da2e3ebdSchin case T_TOKCAT:
1010da2e3ebdSchin if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token);
1011da2e3ebdSchin else
1012da2e3ebdSchin {
1013da2e3ebdSchin if (*(p - 1) == ' ') p--;
1014da2e3ebdSchin if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
1015da2e3ebdSchin }
1016da2e3ebdSchin pp.state |= NOSPACE;
1017da2e3ebdSchin c = pplex();
1018da2e3ebdSchin pp.state &= ~NOSPACE;
1019da2e3ebdSchin if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT));
1020da2e3ebdSchin var.type = TOK_TOKCAT;
1021da2e3ebdSchin continue;
1022da2e3ebdSchin case '(':
1023da2e3ebdSchin if (*pp.token == '#')
1024da2e3ebdSchin {
1025da2e3ebdSchin var.type = TOK_BUILTIN;
1026da2e3ebdSchin n1++;
1027da2e3ebdSchin }
1028da2e3ebdSchin else
1029da2e3ebdSchin {
1030da2e3ebdSchin var.type = 0;
1031da2e3ebdSchin if (n1) n1++;
1032da2e3ebdSchin }
1033da2e3ebdSchin break;
1034da2e3ebdSchin case ')':
1035da2e3ebdSchin var.type = 0;
1036da2e3ebdSchin if (n1) n1--;
1037da2e3ebdSchin break;
1038da2e3ebdSchin case T_STRING:
1039da2e3ebdSchin case T_CHARCONST:
1040da2e3ebdSchin pp.state &= ~NOEXPAND;
1041da2e3ebdSchin var.type = 0;
1042da2e3ebdSchin if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND;
1043da2e3ebdSchin #if COMPATIBLE
1044da2e3ebdSchin /*UNDENT*/
1045da2e3ebdSchin
1046da2e3ebdSchin if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION)))
1047da2e3ebdSchin {
1048da2e3ebdSchin char* v;
1049da2e3ebdSchin
1050da2e3ebdSchin s = pp.token;
1051da2e3ebdSchin for (;;)
1052da2e3ebdSchin {
1053da2e3ebdSchin if (!*s) goto checkvalue;
1054da2e3ebdSchin if (ppisid(*s))
1055da2e3ebdSchin {
1056da2e3ebdSchin v = s;
1057da2e3ebdSchin while (ppisid(*++s));
1058da2e3ebdSchin i1 = *s;
1059da2e3ebdSchin *s = 0;
1060da2e3ebdSchin for (c = 0; c < mac->arity; c++)
1061da2e3ebdSchin if (streq(formargs[c], v))
1062da2e3ebdSchin {
1063da2e3ebdSchin *p++ = MARK;
1064da2e3ebdSchin *p++ = 'C';
1065da2e3ebdSchin *p++ = c + ARGOFFSET;
1066da2e3ebdSchin if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token)
1067da2e3ebdSchin {
1068da2e3ebdSchin case '"':
1069da2e3ebdSchin error(1, "use the # operator to \"...\" quote macro arguments");
1070da2e3ebdSchin break;
1071da2e3ebdSchin case '\'':
1072da2e3ebdSchin error(1, "macro arguments should be '...' quoted before substitution");
1073da2e3ebdSchin break;
1074da2e3ebdSchin }
1075da2e3ebdSchin goto quotearg;
1076da2e3ebdSchin }
1077da2e3ebdSchin STRCOPY2(p, v);
1078da2e3ebdSchin quotearg:
1079da2e3ebdSchin *s = i1;
1080da2e3ebdSchin }
1081da2e3ebdSchin else *p++ = *s++;
1082da2e3ebdSchin }
1083da2e3ebdSchin }
1084da2e3ebdSchin /*INDENT*/
1085da2e3ebdSchin #endif
1086da2e3ebdSchin break;
1087da2e3ebdSchin case '\n':
1088da2e3ebdSchin #if MACDEF
1089da2e3ebdSchin if (sym->flags & SYM_MULTILINE)
1090da2e3ebdSchin {
1091da2e3ebdSchin if (pp.state & EOF2NL)
1092da2e3ebdSchin {
1093da2e3ebdSchin error_info.line++;
1094da2e3ebdSchin pp.state |= HIDDEN;
1095da2e3ebdSchin pp.hidden++;
1096da2e3ebdSchin var.type = 0;
1097da2e3ebdSchin if (!i3++)
1098da2e3ebdSchin goto checkvalue;
1099da2e3ebdSchin break;
1100da2e3ebdSchin }
1101da2e3ebdSchin pp.state |= EOF2NL;
1102da2e3ebdSchin error(2, "%s: missing #%s", sym->name, dirname(ENDMAC));
1103da2e3ebdSchin }
1104da2e3ebdSchin #endif
1105da2e3ebdSchin goto gotdefinition;
1106da2e3ebdSchin case 0:
1107da2e3ebdSchin c = '\n';
1108da2e3ebdSchin goto gotdefinition;
1109da2e3ebdSchin #if COMPATIBLE
1110da2e3ebdSchin case ' ':
1111da2e3ebdSchin if (pp.state & COMPATIBILITY) var.type = 0;
1112da2e3ebdSchin if (pp.option & PRESERVE) break;
1113da2e3ebdSchin if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
1114da2e3ebdSchin goto checkvalue;
1115da2e3ebdSchin case '\t':
1116da2e3ebdSchin if (var.type & TOK_ID)
1117da2e3ebdSchin {
1118da2e3ebdSchin while ((c = pplex()) == '\t');
1119da2e3ebdSchin if (c == T_ID)
1120da2e3ebdSchin {
1121da2e3ebdSchin if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
1122da2e3ebdSchin var.type = TOK_TOKCAT;
1123da2e3ebdSchin if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments");
1124da2e3ebdSchin }
1125da2e3ebdSchin else var.type = 0;
1126da2e3ebdSchin continue;
1127da2e3ebdSchin }
1128da2e3ebdSchin var.type = 0;
1129da2e3ebdSchin if (pp.option & PRESERVE) break;
1130da2e3ebdSchin if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
1131da2e3ebdSchin goto checkvalue;
1132da2e3ebdSchin #endif
1133da2e3ebdSchin case MARK:
1134da2e3ebdSchin pp.state &= ~NOEXPAND;
1135da2e3ebdSchin /*FALLTHROUGH*/
1136da2e3ebdSchin
1137da2e3ebdSchin default:
1138da2e3ebdSchin var.type = 0;
1139da2e3ebdSchin break;
1140da2e3ebdSchin }
1141da2e3ebdSchin STRCOPY(p, pp.token, s);
1142da2e3ebdSchin checkvalue:
1143da2e3ebdSchin o = c;
1144da2e3ebdSchin if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value)
1145da2e3ebdSchin {
1146da2e3ebdSchin c = p - mac->value;
1147da2e3ebdSchin mac->value = s;
1148da2e3ebdSchin p = mac->value + c;
1149da2e3ebdSchin }
1150da2e3ebdSchin #if MACDEF
1151da2e3ebdSchin n3 = pp.state;
1152da2e3ebdSchin #endif
1153da2e3ebdSchin c = pplex();
1154da2e3ebdSchin }
1155da2e3ebdSchin gotdefinition:
1156da2e3ebdSchin while (p > mac->value && *(p - 1) == ' ') p--;
1157da2e3ebdSchin if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
1158da2e3ebdSchin switch (o)
1159da2e3ebdSchin {
1160da2e3ebdSchin case '+':
1161da2e3ebdSchin case '-':
1162da2e3ebdSchin case '&':
1163da2e3ebdSchin case '|':
1164da2e3ebdSchin case '<':
1165da2e3ebdSchin case '>':
1166da2e3ebdSchin case ':':
1167da2e3ebdSchin case '=':
1168da2e3ebdSchin *p++ = ' ';
1169da2e3ebdSchin break;
1170da2e3ebdSchin }
1171da2e3ebdSchin *p = 0;
1172da2e3ebdSchin #if MACKEYARGS
1173da2e3ebdSchin if (!mac->arity) /* ok */;
1174da2e3ebdSchin else if (pp.option & KEYARGS)
1175da2e3ebdSchin {
1176da2e3ebdSchin p0 = mac->formals;
1177da2e3ebdSchin mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1);
1178da2e3ebdSchin s = (char*)&mac->formkeys[mac->arity];
1179da2e3ebdSchin (void)memcpy(s, p0, p1 - p0 + 1);
1180da2e3ebdSchin free(p0);
1181da2e3ebdSchin for (n = 0; n < mac->arity; n++)
1182da2e3ebdSchin {
1183da2e3ebdSchin mac->formkeys[n].name = s + (formargs[n] - p0);
1184da2e3ebdSchin mac->formkeys[n].value = s + (formvals[n] - p0);
1185da2e3ebdSchin }
1186da2e3ebdSchin }
1187da2e3ebdSchin else
1188da2e3ebdSchin #endif
1189da2e3ebdSchin for (n = 1; n < mac->arity; n++)
1190da2e3ebdSchin *(formargs[n] - 1) = ',';
1191da2e3ebdSchin if (old.value)
1192da2e3ebdSchin {
1193da2e3ebdSchin if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined;
1194da2e3ebdSchin if (!old.formals)
1195da2e3ebdSchin {
1196da2e3ebdSchin if (mac->formals) goto redefined;
1197da2e3ebdSchin }
1198da2e3ebdSchin else if (mac->formals)
1199da2e3ebdSchin {
1200da2e3ebdSchin #if MACKEYARGS
1201da2e3ebdSchin if (pp.option & KEYARGS)
1202da2e3ebdSchin {
1203da2e3ebdSchin for (n = 0; n < mac->arity; n++)
1204da2e3ebdSchin if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value))
1205da2e3ebdSchin goto redefined;
1206da2e3ebdSchin }
1207da2e3ebdSchin else
1208da2e3ebdSchin #endif
1209da2e3ebdSchin if (!streq(mac->formals, old.formals)) goto redefined;
1210da2e3ebdSchin }
1211da2e3ebdSchin #if MACKEYARGS
1212da2e3ebdSchin if (pp.option & KEYARGS)
1213da2e3ebdSchin {
1214da2e3ebdSchin if (mac->formkeys) free(mac->formkeys);
1215da2e3ebdSchin mac->formkeys = old.formkeys;
1216da2e3ebdSchin }
1217da2e3ebdSchin else
1218da2e3ebdSchin #endif
1219da2e3ebdSchin {
1220da2e3ebdSchin if (mac->formals) free(mac->formals);
1221da2e3ebdSchin mac->formals = old.formals;
1222da2e3ebdSchin }
1223da2e3ebdSchin free(mac->value);
1224da2e3ebdSchin mac->value = old.value;
1225da2e3ebdSchin goto benign;
1226da2e3ebdSchin redefined:
1227da2e3ebdSchin if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL))
1228da2e3ebdSchin error(1, "%s redefined", sym->name);
1229da2e3ebdSchin #if MACKEYARGS
1230da2e3ebdSchin if ((pp.option & KEYARGS) && mac->formkeys)
1231da2e3ebdSchin free(mac->formkeys);
1232da2e3ebdSchin #endif
1233da2e3ebdSchin #if MACKEYARGS
1234da2e3ebdSchin if (!(pp.option & KEYARGS))
1235da2e3ebdSchin #endif
1236da2e3ebdSchin if (old.formals) free(old.formals);
1237da2e3ebdSchin free(old.value);
1238da2e3ebdSchin }
1239da2e3ebdSchin else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name);
1240da2e3ebdSchin mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0);
1241da2e3ebdSchin 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)))
1242da2e3ebdSchin {
1243da2e3ebdSchin ppsync();
1244da2e3ebdSchin ppprintf("#%s %s", dirname(DEFINE), sym->name);
1245da2e3ebdSchin if (sym->flags & SYM_FUNCTION)
1246da2e3ebdSchin {
1247da2e3ebdSchin ppputchar('(');
1248da2e3ebdSchin if (mac->formals)
1249da2e3ebdSchin ppprintf("%s", mac->formals);
1250da2e3ebdSchin ppputchar(')');
1251da2e3ebdSchin }
1252da2e3ebdSchin if ((p = mac->value) && *p)
1253da2e3ebdSchin {
1254da2e3ebdSchin ppputchar(' ');
1255da2e3ebdSchin i0 = 0;
1256da2e3ebdSchin while (n = *p++)
1257da2e3ebdSchin {
1258da2e3ebdSchin if (n != MARK || (n = *p++) == MARK)
1259da2e3ebdSchin {
1260da2e3ebdSchin ppputchar(n);
1261da2e3ebdSchin i0 = ppisid(n);
1262da2e3ebdSchin }
1263da2e3ebdSchin else
1264da2e3ebdSchin {
1265da2e3ebdSchin if (n == 'Q')
1266da2e3ebdSchin ppputchar('#');
1267da2e3ebdSchin else if (i0)
1268da2e3ebdSchin {
1269da2e3ebdSchin ppputchar('#');
1270da2e3ebdSchin ppputchar('#');
1271da2e3ebdSchin }
1272da2e3ebdSchin s = formargs[*p++ - ARGOFFSET];
1273da2e3ebdSchin while ((n = *s++) && n != ',')
1274da2e3ebdSchin ppputchar(n);
1275da2e3ebdSchin if (ppisid(*p) || *p == MARK)
1276da2e3ebdSchin {
1277da2e3ebdSchin ppputchar('#');
1278da2e3ebdSchin ppputchar('#');
1279da2e3ebdSchin }
1280da2e3ebdSchin i0 = 0;
1281da2e3ebdSchin }
1282da2e3ebdSchin ppcheckout();
1283da2e3ebdSchin }
1284da2e3ebdSchin }
1285da2e3ebdSchin emitted = 1;
1286da2e3ebdSchin }
1287da2e3ebdSchin benign:
1288da2e3ebdSchin if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN;
1289da2e3ebdSchin if (pp.option & FINAL) sym->flags |= SYM_FINAL;
1290da2e3ebdSchin if (pp.mode & INIT) sym->flags |= SYM_INIT;
1291da2e3ebdSchin if (pp.option & INITIAL) sym->flags |= SYM_INITIAL;
1292da2e3ebdSchin if (pp.state & NOEXPAND) sym->flags |= SYM_NOEXPAND;
1293da2e3ebdSchin if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED;
1294da2e3ebdSchin if (pp.mode & READONLY) sym->flags |= SYM_READONLY;
1295da2e3ebdSchin 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);
1296da2e3ebdSchin break;
1297da2e3ebdSchin assertion:
1298da2e3ebdSchin c = pplex();
1299da2e3ebdSchin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1300da2e3ebdSchin error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0));
1301da2e3ebdSchin if (c != T_ID)
1302da2e3ebdSchin {
1303da2e3ebdSchin error(2, "%s: invalid predicate name", pptokstr(pp.token, 0));
1304da2e3ebdSchin goto eatdirective;
1305da2e3ebdSchin }
1306da2e3ebdSchin switch ((int)hashref(pp.strtab, pp.token))
1307da2e3ebdSchin {
1308da2e3ebdSchin case X_DEFINED:
1309da2e3ebdSchin case X_EXISTS:
1310da2e3ebdSchin case X_STRCMP:
1311da2e3ebdSchin error(2, "%s is a builtin predicate", pp.token);
1312da2e3ebdSchin goto eatdirective;
1313da2e3ebdSchin case X_SIZEOF:
1314da2e3ebdSchin error(2, "%s cannot be a predicate", pp.token);
1315da2e3ebdSchin goto eatdirective;
1316da2e3ebdSchin }
1317da2e3ebdSchin strcpy(pp.tmpbuf, pp.token);
1318da2e3ebdSchin switch (pppredargs())
1319da2e3ebdSchin {
1320da2e3ebdSchin case T_ID:
1321da2e3ebdSchin case T_STRING:
1322da2e3ebdSchin assert(directive, pp.tmpbuf, pp.args);
1323da2e3ebdSchin break;
1324da2e3ebdSchin case 0:
1325da2e3ebdSchin assert(directive, pp.tmpbuf, NiL);
1326da2e3ebdSchin break;
1327da2e3ebdSchin default:
1328da2e3ebdSchin error(2, "invalid predicate argument list");
1329da2e3ebdSchin goto eatdirective;
1330da2e3ebdSchin }
1331da2e3ebdSchin break;
1332da2e3ebdSchin tuple:
1333da2e3ebdSchin pp.state |= DEFINITION|NOEXPAND|NOSPACE;
1334da2e3ebdSchin rp = 0;
1335da2e3ebdSchin tp = mac->tuple;
1336da2e3ebdSchin if (!tp && !mac->value)
1337da2e3ebdSchin ppfsm(FSM_MACRO, sym->name);
1338da2e3ebdSchin while ((c = pplex()) && c != '>' && c != '\n')
1339da2e3ebdSchin {
1340da2e3ebdSchin for (; tp; tp = tp->nomatch)
1341da2e3ebdSchin if (streq(tp->token, pp.token))
1342da2e3ebdSchin break;
1343da2e3ebdSchin if (!tp)
1344da2e3ebdSchin {
1345da2e3ebdSchin if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token))))
1346da2e3ebdSchin error(3, "out of space");
1347da2e3ebdSchin strcpy(tp->token, pp.token);
1348da2e3ebdSchin if (rp)
1349da2e3ebdSchin {
1350da2e3ebdSchin tp->nomatch = rp;
1351da2e3ebdSchin rp->nomatch = tp;
1352da2e3ebdSchin }
1353da2e3ebdSchin else
1354da2e3ebdSchin {
1355da2e3ebdSchin tp->nomatch = mac->tuple;
1356da2e3ebdSchin mac->tuple = tp;
1357da2e3ebdSchin }
1358da2e3ebdSchin }
1359da2e3ebdSchin rp = tp;
1360da2e3ebdSchin tp = tp->match;
1361da2e3ebdSchin }
1362da2e3ebdSchin pp.state &= ~NOSPACE;
1363da2e3ebdSchin if (!rp || c != '>')
1364da2e3ebdSchin error(2, "%s: > omitted in tuple macro definition", sym->name);
1365da2e3ebdSchin else
1366da2e3ebdSchin {
1367da2e3ebdSchin n = 2 * MAXTOKEN;
1368da2e3ebdSchin p = v = oldof(0, char, 0, n);
1369da2e3ebdSchin while ((c = pplex()) && c != '\n')
1370da2e3ebdSchin if (p > v || c != ' ')
1371da2e3ebdSchin {
1372da2e3ebdSchin STRCOPY(p, pp.token, s);
1373da2e3ebdSchin if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v)
1374da2e3ebdSchin {
1375da2e3ebdSchin c = p - v;
1376da2e3ebdSchin v = s;
1377da2e3ebdSchin p = v + c;
1378da2e3ebdSchin }
1379da2e3ebdSchin }
1380da2e3ebdSchin while (p > v && *(p - 1) == ' ')
1381da2e3ebdSchin p--;
1382da2e3ebdSchin n = p - v;
1383da2e3ebdSchin tp = newof(0, struct pptuple, 1, n);
1384da2e3ebdSchin strcpy(tp->token, v);
1385da2e3ebdSchin tp->match = rp->match;
1386da2e3ebdSchin rp->match = tp;
1387da2e3ebdSchin }
1388da2e3ebdSchin goto benign;
1389da2e3ebdSchin case WARNING:
1390da2e3ebdSchin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1391da2e3ebdSchin error(1, "#%s: non-standard directive", pp.token);
1392da2e3ebdSchin /*FALLTHROUGH*/
1393da2e3ebdSchin case ERROR:
1394da2e3ebdSchin pp.state &= ~DISABLE;
1395da2e3ebdSchin p = pp.tmpbuf;
1396da2e3ebdSchin while ((c = pplex()) != '\n')
1397da2e3ebdSchin if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN])
1398da2e3ebdSchin {
1399da2e3ebdSchin STRCOPY(p, pp.token, s);
1400da2e3ebdSchin pp.state &= ~NOSPACE;
1401da2e3ebdSchin }
1402da2e3ebdSchin *p = 0;
1403da2e3ebdSchin p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error");
1404da2e3ebdSchin n = (directive == WARNING) ? 1 : 3;
1405da2e3ebdSchin error(n, "%s", p);
1406da2e3ebdSchin break;
1407da2e3ebdSchin case LET:
1408da2e3ebdSchin n2 = error_info.line;
1409da2e3ebdSchin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1410da2e3ebdSchin error(1, "#%s: non-standard directive", pp.token);
1411da2e3ebdSchin if (!(sym = macsym(c = pplex()))) goto eatdirective;
1412da2e3ebdSchin if ((c = pplex()) != '=')
1413da2e3ebdSchin {
1414da2e3ebdSchin error(2, "%s: = expected", sym->name);
1415da2e3ebdSchin goto eatdirective;
1416da2e3ebdSchin }
1417da2e3ebdSchin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC);
1418da2e3ebdSchin mac = sym->macro;
1419da2e3ebdSchin mac->arity = 0;
1420da2e3ebdSchin if (mac->value)
1421da2e3ebdSchin {
1422da2e3ebdSchin if (!(sym->flags & SYM_REDEFINE) && !sym->hidden)
1423da2e3ebdSchin error(1, "%s: redefined", sym->name);
1424da2e3ebdSchin #if MACKEYARGS
1425da2e3ebdSchin if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys);
1426da2e3ebdSchin else
1427da2e3ebdSchin #endif
1428da2e3ebdSchin free(mac->formals);
1429da2e3ebdSchin mac->formals = 0;
1430da2e3ebdSchin n = strlen(mac->value) + 1;
1431da2e3ebdSchin }
1432da2e3ebdSchin else
1433da2e3ebdSchin {
1434da2e3ebdSchin ppfsm(FSM_MACRO, sym->name);
1435da2e3ebdSchin n = 0;
1436da2e3ebdSchin }
1437da2e3ebdSchin n1 = ppexpr(&i1);
1438da2e3ebdSchin if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1);
1439da2e3ebdSchin else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1);
1440da2e3ebdSchin if (n < ++c)
1441da2e3ebdSchin {
1442da2e3ebdSchin if (mac->value) free(mac->value);
1443da2e3ebdSchin mac->value = oldof(0, char, 0, c);
1444da2e3ebdSchin }
1445da2e3ebdSchin strcpy(mac->value, pp.tmpbuf);
1446da2e3ebdSchin sym->flags |= SYM_REDEFINE;
1447da2e3ebdSchin c = (pp.state & NEWLINE) ? '\n' : ' ';
1448da2e3ebdSchin goto benign;
1449da2e3ebdSchin case LINE:
1450da2e3ebdSchin pp.state &= ~DISABLE;
1451da2e3ebdSchin if ((c = pplex()) == '#')
1452da2e3ebdSchin {
1453da2e3ebdSchin c = pplex();
1454da2e3ebdSchin directive = INCLUDE;
1455da2e3ebdSchin }
1456da2e3ebdSchin if (c != T_DECIMAL && c != T_OCTAL)
1457da2e3ebdSchin {
1458da2e3ebdSchin error(1, "#%s: line number expected",