14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1986-2009 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * Glenn Fowler
234887Schin * AT&T Research
244887Schin *
254887Schin * preprocessor control directive support
264887Schin */
274887Schin
284887Schin #include "pplib.h"
294887Schin
304887Schin #include <regex.h>
314887Schin
324887Schin #define TOKOP_DUP (1<<0)
334887Schin #define TOKOP_STRING (1<<1)
344887Schin #define TOKOP_UNSET (1<<2)
354887Schin
364887Schin struct edit
374887Schin {
384887Schin struct edit* next;
394887Schin regex_t re;
404887Schin };
414887Schin
424887Schin struct map
434887Schin {
444887Schin struct map* next;
454887Schin regex_t re;
464887Schin struct edit* edit;
474887Schin };
484887Schin
494887Schin #define RESTORE (COLLECTING|CONDITIONAL|DEFINITION|DIRECTIVE|DISABLE|EOF2NL|HEADER|NOSPACE|NOVERTICAL|PASSEOF|STRIP)
504887Schin
514887Schin /*
524887Schin * common predicate assertion operations
534887Schin * op is DEFINE or UNDEF
544887Schin */
554887Schin
564887Schin static void
assert(int op,char * pred,char * args)574887Schin assert(int op, char* pred, char* args)
584887Schin {
594887Schin register struct pplist* a;
604887Schin register struct ppsymbol* sym;
614887Schin register struct pplist* p;
624887Schin register struct pplist* q;
634887Schin
644887Schin if (!args) switch (op)
654887Schin {
664887Schin case DEFINE:
674887Schin goto mark;
684887Schin case UNDEF:
694887Schin a = 0;
704887Schin goto unmark;
714887Schin }
724887Schin if (a = (struct pplist*)hashget(pp.prdtab, pred))
734887Schin {
744887Schin p = 0;
754887Schin q = a;
764887Schin while (q)
774887Schin {
784887Schin if (streq(q->value, args))
794887Schin {
804887Schin if (op == DEFINE) return;
814887Schin q = q->next;
824887Schin if (p) p->next = q;
834887Schin else a = q;
844887Schin }
854887Schin else
864887Schin {
874887Schin p = q;
884887Schin q = q->next;
894887Schin }
904887Schin }
914887Schin if (op == UNDEF)
924887Schin {
934887Schin unmark:
944887Schin hashput(pp.prdtab, pred, a);
954887Schin if (sym = ppsymref(pp.symtab, pred))
964887Schin sym->flags &= ~SYM_PREDICATE;
974887Schin return;
984887Schin }
994887Schin }
1004887Schin if (op == DEFINE)
1014887Schin {
1024887Schin p = newof(0, struct pplist, 1, 0);
1034887Schin p->next = a;
1044887Schin p->value = strdup(args);
1054887Schin hashput(pp.prdtab, NiL, p);
1064887Schin mark:
1074887Schin if ((pp.state & COMPILE) && pp.truncate) return;
1084887Schin if (sym = ppsymset(pp.symtab, pred))
1094887Schin sym->flags |= SYM_PREDICATE;
1104887Schin }
1114887Schin }
1124887Schin
1134887Schin /*
1144887Schin * tokenize string ppop()
1154887Schin *
1164887Schin * op PP_* op
1174887Schin * name option name
1184887Schin * s string of option values
1194887Schin * n option sense
1204887Schin * flags TOKOP_* flags
1214887Schin */
1224887Schin
1234887Schin static void
tokop(int op,char * name,register char * s,register int n,int flags)1244887Schin tokop(int op, char* name, register char* s, register int n, int flags)
1254887Schin {
1264887Schin register int c;
1274887Schin register char* t;
1284887Schin
1294887Schin if (!(flags & TOKOP_UNSET) && !n) error(2, "%s: option cannot be unset", name);
1304887Schin else if (!s) ppop(op, s, n);
1314887Schin else if (flags & TOKOP_STRING)
1324887Schin {
1334887Schin PUSH_LINE(s);
1344887Schin for (;;)
1354887Schin {
1364887Schin pp.state &= ~NOSPACE;
1374887Schin c = pplex();
1384887Schin pp.state |= NOSPACE;
1394887Schin if (!c) break;
1404887Schin if (c != ' ')
1414887Schin ppop(op, (flags & TOKOP_DUP) ? strdup(pp.token) : pp.token, n);
1424887Schin }
1434887Schin POP_LINE();
1444887Schin }
1454887Schin else do
1464887Schin {
1474887Schin while (*s == ' ') s++;
1484887Schin for (t = s; *t && *t != ' '; t++);
1494887Schin if (*t) *t++ = 0;
1504887Schin else t = 0;
1514887Schin if (*s) ppop(op, (flags & TOKOP_DUP) ? strdup(s) : s, n);
1524887Schin } while (s = t);
1534887Schin }
1544887Schin
1554887Schin /*
1564887Schin * return symbol pointer for next token macro (re)definition
1574887Schin */
1584887Schin
1594887Schin static struct ppsymbol*
macsym(int tok)1604887Schin macsym(int tok)
1614887Schin {
1624887Schin register struct ppsymbol* sym;
1634887Schin
1644887Schin if (tok != T_ID)
1654887Schin {
1664887Schin error(2, "%s: invalid macro name", pptokstr(pp.token, 0));
1674887Schin return 0;
1684887Schin }
1694887Schin sym = pprefmac(pp.token, REF_CREATE);
1704887Schin if ((sym->flags & SYM_FINAL) && (pp.mode & HOSTED)) return 0;
1714887Schin if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
1724887Schin {
1734887Schin if (!(pp.option & ALLPOSSIBLE))
1744887Schin error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
1754887Schin return 0;
1764887Schin }
1774887Schin if (!sym->macro) sym->macro = newof(0, struct ppmacro, 1, 0);
1784887Schin return sym;
1794887Schin }
1804887Schin
1814887Schin /*
1824887Schin * get one space canonical pplex() line, sans '\n', and place in p
1834887Schin * x is max+1 pos in p
1844887Schin * 0 returned if line too large
1854887Schin * otherwise end of p ('\0') returned
1864887Schin */
1874887Schin
1884887Schin static char*
getline(register char * p,char * x,int disable)1894887Schin getline(register char* p, char* x, int disable)
1904887Schin {
1914887Schin register int c;
1924887Schin register char* s;
1934887Schin char* b;
1944887Schin long restore;
1954887Schin
1964887Schin restore = pp.state & (NOSPACE|STRIP);
1974887Schin pp.state &= ~(NEWLINE|NOSPACE|STRIP);
1984887Schin pp.state |= EOF2NL;
1994887Schin b = p;
2004887Schin while ((c = pplex()) != '\n')
2014887Schin {
2024887Schin if (disable)
2034887Schin {
2044887Schin if (c == ' ')
2054887Schin /*ignore*/;
2064887Schin else if (disable == 1)
2074887Schin disable = (c == T_ID && streq(pp.token, pp.pass)) ? 2 : 0;
2084887Schin else
2094887Schin {
2104887Schin disable = 0;
2114887Schin if (c == ':')
2124887Schin pp.state |= DISABLE;
2134887Schin }
2144887Schin }
2154887Schin s = pp.token;
2164887Schin while (*p = *s++)
2174887Schin if (++p >= x)
2184887Schin {
2194887Schin p = 0;
2204887Schin goto done;
2214887Schin }
2224887Schin }
2234887Schin if (p > b && *(p - 1) == ' ')
2244887Schin p--;
2254887Schin if (p >= x)
2264887Schin p = 0;
2274887Schin else
2284887Schin *p = 0;
2294887Schin done:
2304887Schin pp.state &= ~(NOSPACE|STRIP);
2314887Schin pp.state |= restore;
2324887Schin return p;
2334887Schin }
2344887Schin
2354887Schin /*
2364887Schin * regex error handler
2374887Schin */
2384887Schin
2394887Schin void
regfatal(regex_t * p,int level,int code)2404887Schin regfatal(regex_t* p, int level, int code)
2414887Schin {
2424887Schin char buf[128];
2434887Schin
2444887Schin regerror(code, p, buf, sizeof(buf));
2454887Schin regfree(p);
2464887Schin error(level, "regular expression: %s", buf);
2474887Schin }
2484887Schin
2494887Schin /*
2504887Schin * process a single directive line
2514887Schin */
2524887Schin
2534887Schin int
ppcontrol(void)2544887Schin ppcontrol(void)
2554887Schin {
2564887Schin register char* p;
2574887Schin register int c;
2584887Schin register int n;
2594887Schin register char* s;
2604887Schin register struct ppmacro* mac;
2614887Schin register struct ppsymbol* sym;
2624887Schin struct edit* edit;
2634887Schin struct map* map;
2644887Schin struct ppfile* fp;
2654887Schin int o;
2664887Schin int directive;
2674887Schin long restore;
2684887Schin struct pptuple* rp;
2694887Schin struct pptuple* tp;
2704887Schin char* v;
2714887Schin int emitted;
2724887Schin
2734887Schin union
2744887Schin {
2754887Schin struct map* best;
2764887Schin struct ppinstk* inp;
2774887Schin struct pplist* list;
2784887Schin char* string;
2794887Schin struct ppsymbol* symbol;
2804887Schin int type;
2814887Schin PPLINESYNC linesync;
2824887Schin } var;
2834887Schin
2844887Schin static char __va_args__[] = "__VA_ARGS__";
2854887Schin static int i0;
2864887Schin static int i1;
2874887Schin static int i2;
2884887Schin static int i3;
2894887Schin static int i4;
2904887Schin
2914887Schin static long n1;
2924887Schin static long n2;
2934887Schin static long n3;
2944887Schin
2954887Schin static char* p0;
2964887Schin static char* p1;
2974887Schin static char* p2;
2984887Schin static char* p3;
2994887Schin static char* p4;
3004887Schin static char* p5;
3014887Schin static char* p6;
3024887Schin
3034887Schin static struct ppmacro old;
3044887Schin static char* formargs[MAXFORMALS];
3054887Schin #if MACKEYARGS
3064887Schin static char* formvals[MAXFORMALS];
3074887Schin #endif
3084887Schin
3094887Schin emitted = 0;
3104887Schin if (pp.state & SKIPCONTROL) pp.level--;
3114887Schin restore = (pp.state & RESTORE)|NEWLINE;
3124887Schin if (pp.state & PASSTHROUGH) restore |= DISABLE;
3134887Schin else restore &= ~DISABLE;
3144887Schin pp.state &= ~(NEWLINE|RESTORE|SKIPCONTROL);
3154887Schin pp.state |= DIRECTIVE|DISABLE|EOF2NL|NOSPACE|NOVERTICAL;
3164887Schin #if COMPATIBLE
3174887Schin if ((pp.state & (COMPATIBILITY|STRICT)) == COMPATIBILITY || (pp.mode & HOSTED)) pp.state &= ~NOVERTICAL;
3184887Schin #else
3194887Schin if (pp.mode & HOSTED) pp.state &= ~NOVERTICAL;
3204887Schin #endif
3214887Schin switch (c = pplex())
3224887Schin {
3234887Schin case T_DECIMAL:
3244887Schin case T_OCTAL:
3254887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
3264887Schin error(1, "# <line> [ \"<file>\" [ <type> ] ]: non-standard directive");
3274887Schin directive = INCLUDE;
3284887Schin goto linesync;
3294887Schin case T_ID:
3304887Schin switch (directive = (int)hashref(pp.dirtab, pp.token))
3314887Schin {
3324887Schin case ELIF:
3334887Schin else_if:
3344887Schin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
3354887Schin goto eatdirective;
3364887Schin if (pp.control <= pp.in->control)
3374887Schin {
3384887Schin error(2, "no matching #%s for #%s", dirname(IF), dirname(ELIF));
3394887Schin goto eatdirective;
3404887Schin }
3414887Schin if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
3424887Schin if (*pp.control & HADELSE)
3434887Schin {
3444887Schin error(2, "invalid #%s after #%s", dirname(ELIF), dirname(ELSE));
3454887Schin *pp.control |= SKIP;
3464887Schin goto eatdirective;
3474887Schin }
3484887Schin if (*pp.control & KEPT)
3494887Schin {
3504887Schin *pp.control |= SKIP;
3514887Schin goto eatdirective;
3524887Schin }
3534887Schin if (directive == IFDEF || directive == IFNDEF)
3544887Schin {
3554887Schin *pp.control &= ~SKIP;
3564887Schin goto else_ifdef;
3574887Schin }
3584887Schin conditional:
3594887Schin if (ppexpr(&i1))
3604887Schin {
3614887Schin *pp.control &= ~SKIP;
3624887Schin *pp.control |= KEPT;
3634887Schin }
3644887Schin else *pp.control |= SKIP;
3654887Schin c = (pp.state & NEWLINE) ? '\n' : ' ';
3664887Schin goto eatdirective;
3674887Schin case ELSE:
3684887Schin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
3694887Schin goto eatdirective;
3704887Schin if ((pp.option & ELSEIF) && (c = pplex()) == T_ID && ((n = (int)hashref(pp.dirtab, pp.token)) == IF || n == IFDEF || n == IFNDEF))
3714887Schin {
3724887Schin error(1, "#%s %s is non-standard -- use #%s", dirname(directive), dirname(n), dirname(ELIF));
3734887Schin directive = n;
3744887Schin goto else_if;
3754887Schin }
3764887Schin if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ELSE));
3774887Schin else
3784887Schin {
3794887Schin if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
3804887Schin if (!(*pp.control & KEPT))
3814887Schin {
3824887Schin *pp.control &= ~SKIP;
3834887Schin *pp.control |= HADELSE|KEPT;
3844887Schin }
3854887Schin else
3864887Schin {
3874887Schin if (*pp.control & HADELSE) error(2, "more than one #%s for #%s", dirname(ELSE), dirname(IF));
3884887Schin *pp.control |= HADELSE|SKIP;
3894887Schin }
3904887Schin }
3914887Schin goto enddirective;
3924887Schin case ENDIF:
3934887Schin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
3944887Schin goto eatdirective;
3954887Schin if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ENDIF));
3964887Schin else if (--pp.control == pp.in->control && pp.in->symbol)
3974887Schin {
3984887Schin if (pp.in->flags & IN_endguard) pp.in->flags |= IN_noguard;
3994887Schin else
4004887Schin {
4014887Schin pp.in->flags &= ~IN_tokens;
4024887Schin pp.in->flags |= IN_endguard;
4034887Schin }
4044887Schin }
4054887Schin goto enddirective;
4064887Schin case IF:
4074887Schin case IFDEF:
4084887Schin case IFNDEF:
4094887Schin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
4104887Schin goto eatdirective;
4114887Schin pushcontrol();
4124887Schin SETIFBLOCK(pp.control);
4134887Schin if (*pp.control & SKIP)
4144887Schin {
4154887Schin *pp.control |= KEPT;
4164887Schin goto eatdirective;
4174887Schin }
4184887Schin if (directive == IF) goto conditional;
4194887Schin else_ifdef:
4204887Schin if ((c = pplex()) == T_ID)
4214887Schin {
4224887Schin sym = pprefmac(pp.token, REF_IF);
4234887Schin if (directive == IFNDEF && pp.control == pp.in->control + 1)
4244887Schin {
4254887Schin if (pp.in->flags & (IN_defguard|IN_endguard))
4264887Schin pp.in->flags |= IN_noguard;
4274887Schin else
4284887Schin {
4294887Schin pp.in->flags |= IN_defguard;
4304887Schin if (!(pp.in->flags & IN_tokens))
4314887Schin pp.in->symbol = sym ? sym : pprefmac(pp.token, REF_CREATE);
4324887Schin }
4334887Schin }
4344887Schin }
4354887Schin else
4364887Schin {
4374887Schin sym = 0;
4384887Schin if (!(pp.mode & HOSTED))
4394887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
4404887Schin }
4414887Schin *pp.control |= ((sym != 0) == (directive == IFDEF)) ? KEPT : SKIP;
4424887Schin goto enddirective;
4434887Schin case INCLUDE:
4444887Schin if (*pp.control & SKIP)
4454887Schin {
4464887Schin pp.state |= HEADER;
4474887Schin c = pplex();
4484887Schin pp.state &= ~HEADER;
4494887Schin goto eatdirective;
4504887Schin }
4514887Schin pp.state &= ~DISABLE;
4524887Schin pp.state |= HEADER|STRIP;
453*10898Sroland.mainz@nrubsig.org pp.in->flags |= IN_noguard;
4544887Schin switch (c = pplex())
4554887Schin {
4564887Schin case T_STRING:
4574887Schin p = pp.token;
4584887Schin do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING);
4594887Schin *pp.token = 0;
4604887Schin pp.token = p;
4614887Schin /*FALLTHROUGH*/
4624887Schin case T_HEADER:
4634887Schin header:
4644887Schin if (!*pp.token)
4654887Schin {
4664887Schin error(2, "#%s: null file name", dirname(INCLUDE));
4674887Schin break;
4684887Schin }
4694887Schin if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX)))
4704887Schin error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token);
4714887Schin n = ppsearch(pp.token, c, SEARCH_INCLUDE);
4724887Schin break;
4734887Schin case '<':
4744887Schin /*
4754887Schin * HEADEREXPAND|HEADEREXPANDALL gets us here
4764887Schin */
4774887Schin
4784887Schin if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0)))
4794887Schin error(3, "out of space");
4804887Schin pp.state &= ~NOSPACE;
4814887Schin while ((c = pplex()) && c != '>')
4824887Schin {
4834887Schin v = p + 1;
4844887Schin STRCOPY(p, pp.token, s);
4854887Schin if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO)
4864887Schin p--;
4874887Schin }
4884887Schin pp.state |= NOSPACE;
4894887Schin *p++ = 0;
4904887Schin memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf);
4914887Schin c = T_HEADER;
4924887Schin goto header;
4934887Schin default:
4944887Schin error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE));
4954887Schin goto eatdirective;
4964887Schin }
4974887Schin goto enddirective;
4984887Schin case 0:
4994887Schin {
5004887Schin regmatch_t match[10];
5014887Schin
5024887Schin /*UNDENT*/
5034887Schin p = pp.valbuf;
5044887Schin *p++ = '#';
5054887Schin STRCOPY(p, pp.token, s);
5064887Schin p0 = p;
5074887Schin pp.mode |= EXPOSE;
5084887Schin pp.state |= HEADER;
5094887Schin p6 = getline(p, &pp.valbuf[MAXTOKEN], 0);
5104887Schin pp.state &= ~HEADER;
5114887Schin pp.mode &= ~EXPOSE;
5124887Schin if (!p6)
5134887Schin {
5144887Schin *p0 = 0;
5154887Schin error(2, "%s: directive too long", pp.valbuf);
5164887Schin c = 0;
5174887Schin goto eatdirective;
5184887Schin }
5194887Schin p1 = p2 = p3 = p4 = 0;
5204887Schin p5 = *p ? p + 1 : 0;
5214887Schin checkmap:
5224887Schin i0 = *p0;
5234887Schin p = pp.valbuf;
5244887Schin var.best = 0;
5254887Schin n = 0;
5264887Schin for (map = (struct map*)pp.maps; map; map = map->next)
5274887Schin if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0)))
5284887Schin {
5294887Schin if ((c = match[0].rm_eo - match[0].rm_so) > n)
5304887Schin {
5314887Schin n = c;
5324887Schin var.best = map;
5334887Schin }
5344887Schin }
5354887Schin else if (i1 != REG_NOMATCH)
5364887Schin regfatal(&map->re, 3, i1);
5374887Schin c = '\n';
5384887Schin if (map = var.best)
5394887Schin {
5404887Schin if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX)))
5414887Schin {
5424887Schin *p0 = 0;
5434887Schin if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA)))
5444887Schin error(1, "%s: non-standard directive", p);
5454887Schin *p0 = i0;
5464887Schin }
5474887Schin if (!(*pp.control & SKIP))
5484887Schin {
5494887Schin n = 0;
5504887Schin for (edit = map->edit; edit; edit = edit->next)
5514887Schin if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0)))
5524887Schin {
5534887Schin n++;
5544887Schin if (i0 = regsubexec(&edit->re, p, elementsof(match), match))
5554887Schin regfatal(&edit->re, 3, i0);
5564887Schin p = edit->re.re_sub->re_buf;
5574887Schin if (edit->re.re_sub->re_flags & REG_SUB_STOP)
5584887Schin break;
5594887Schin }
5604887Schin else if (i0 != REG_NOMATCH)
5614887Schin regfatal(&edit->re, 3, i0);
5624887Schin if (n && *p)
5634887Schin {
5644887Schin p1 = s = oldof(0, char, 0, strlen(p) + 32);
5654887Schin while (*s = *p++) s++;
5664887Schin debug((-4, "map: %s", p1));
5674887Schin *s++ = '\n';
5684887Schin *s = 0;
5694887Schin error_info.line++;
5704887Schin PUSH_RESCAN(p1);
5714887Schin error_info.line--;
5724887Schin directive = LINE;
5734887Schin }
5744887Schin }
5754887Schin goto donedirective;
5764887Schin }
5774887Schin if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX))))
5784887Schin {
5794887Schin *p0 = 0;
5804887Schin error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0));
5814887Schin *p0 = i0;
5824887Schin }
5834887Schin pass:
5844887Schin if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT)))
5854887Schin {
5864887Schin *p0 = 0;
5874887Schin if (p2) *p2 = 0;
5884887Schin if (p4)
5894887Schin {
5904887Schin if (p4 == p5)
5914887Schin {
5924887Schin p5 = strcpy(pp.tmpbuf, p5);
5934887Schin if (p = strchr(p5, MARK))
5944887Schin {
5954887Schin s = p;
5964887Schin while (*p)
5974887Schin if ((*s++ = *p++) == MARK && *p == MARK) p++;
5984887Schin *s = 0;
5994887Schin }
6004887Schin }
6014887Schin *p4 = 0;
6024887Schin }
6034887Schin if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1))
6044887Schin {
6054887Schin s = p;
6064887Schin while (p < p6) switch (*s++ = *p++)
6074887Schin {
6084887Schin case 0:
6094887Schin s = p;
6104887Schin break;
6114887Schin case MARK:
6124887Schin p++;
6134887Schin break;
6144887Schin }
6154887Schin *s = 0;
6164887Schin }
6174887Schin (*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0);
6184887Schin emitted = 1;
6194887Schin }
6204887Schin goto donedirective;
6214887Schin
6224887Schin /*INDENT*/
6234887Schin }
6244887Schin }
6254887Schin if (*pp.control & SKIP) goto eatdirective;
6264887Schin switch (directive)
6274887Schin {
6284887Schin #if MACDEF
6294887Schin case ENDMAC:
6304887Schin c = pplex();
6314887Schin error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC));
6324887Schin goto enddirective;
6334887Schin #endif
6344887Schin #if MACDEF
6354887Schin case MACDEF:
6364887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
6374887Schin error(1, "#%s: non-standard directive", pp.token);
6384887Schin /*FALLTHROUGH*/
6394887Schin #endif
6404887Schin case DEFINE:
6414887Schin n2 = error_info.line;
6424887Schin if ((c = pplex()) == '#' && directive == DEFINE)
6434887Schin goto assertion;
6444887Schin if (c == '<')
6454887Schin {
6464887Schin n = 1;
6474887Schin c = pplex();
6484887Schin }
6494887Schin else
6504887Schin n = 0;
6514887Schin if (!(sym = macsym(c)))
6524887Schin goto eatdirective;
6534887Schin if (pp.truncate)
6544887Schin ppfsm(FSM_MACRO, pp.token);
6554887Schin mac = sym->macro;
6564887Schin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value)
6574887Schin goto eatdirective;
6584887Schin if (n)
6594887Schin goto tuple;
6604887Schin old = *mac;
6614887Schin i0 = sym->flags;
6624887Schin sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
6634887Schin #if MACDEF
6644887Schin if (directive == MACDEF)
6654887Schin sym->flags |= SYM_MULTILINE;
6664887Schin #endif
6674887Schin mac->arity = 0;
6684887Schin mac->formals = 0;
6694887Schin mac->value = 0;
6704887Schin pp.state &= ~NOSPACE;
6714887Schin pp.state |= DEFINITION|NOEXPAND;
6724887Schin switch (c = pplex())
6734887Schin {
6744887Schin case '(':
6754887Schin sym->flags |= SYM_FUNCTION;
6764887Schin pp.state |= NOSPACE;
6774887Schin #if MACKEYARGS
6784887Schin if (pp.option & KEYARGS)
6794887Schin {
6804887Schin n = 2 * MAXTOKEN;
6814887Schin p = mac->formals = oldof(0, char, 0, n);
6824887Schin if ((c = pplex()) == T_ID) for (;;)
6834887Schin {
6844887Schin if (mac->arity < MAXFORMALS)
6854887Schin {
6864887Schin if (mac->arity) p++;
6874887Schin formargs[mac->arity] = p;
6884887Schin STRAPP(p, pp.token, s);
6894887Schin formvals[mac->arity++] = p1 = p;
6904887Schin if (mac->arity == 1) *p++ = ' ';
6914887Schin *p++ = ' ';
6924887Schin *p = 0;
6934887Schin }
6944887Schin else error(2, "%s: formal argument %s ignored", sym->name, pp.token);
6954887Schin switch (c = pplex())
6964887Schin {
6974887Schin case '=':
6984887Schin c = pplex();
6994887Schin break;
7004887Schin case ',':
7014887Schin break;
7024887Schin default:
7034887Schin goto endformals;
7044887Schin }
7054887Schin pp.state &= ~NOSPACE;
7064887Schin p0 = 0;
7074887Schin for (;;)
7084887Schin {
7094887Schin switch (c)
7104887Schin {
7114887Schin case '\n':
7124887Schin goto endformals;
7134887Schin case '(':
7144887Schin p0++;
7154887Schin break;
7164887Schin case ')':
7174887Schin if (!p0--)
7184887Schin {
7194887Schin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
7204887Schin goto endformals;
7214887Schin }
7224887Schin break;
7234887Schin case ',':
7244887Schin if (!p0)
7254887Schin {
7264887Schin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
7274887Schin goto nextformal;
7284887Schin }
7294887Schin break;
7304887Schin case ' ':
7314887Schin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue;
7324887Schin break;
7334887Schin }
7344887Schin STRCOPY(p, pp.token, s);
7354887Schin if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals)
7364887Schin {
7374887Schin n1 = s - mac->formals;
7384887Schin for (n = 0; n < mac->arity; n++)
7394887Schin {
7404887Schin formargs[n] += n1;
7414887Schin formvals[n] += n1;
7424887Schin }
7434887Schin c = p - mac->formals;
7444887Schin mac->formals = s;
7454887Schin p = mac->formals + c;
7464887Schin }
7474887Schin c = pplex();
7484887Schin }
7494887Schin nextformal:
7504887Schin pp.state |= NOSPACE;
7514887Schin if ((c = pplex()) != T_ID)
7524887Schin {
7534887Schin c = ',';
7544887Schin break;
7554887Schin }
7564887Schin }
7574887Schin endformals: /*NOP*/;
7584887Schin }
7594887Schin else
7604887Schin #endif
7614887Schin {
7624887Schin p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1));
7634887Schin c = pplex();
7644887Schin #if COMPATIBLE
7654887Schin if ((pp.state & COMPATIBILITY) && c == ',')
7664887Schin {
7674887Schin if ((pp.state & WARN) && !(pp.mode & HOSTED))
7684887Schin error(1, "%s: macro formal argument expected", sym->name);
7694887Schin while ((c = pplex()) == ',');
7704887Schin }
7714887Schin #endif
7724887Schin for (;;)
7734887Schin {
7744887Schin if (c == T_VARIADIC)
7754887Schin {
7764887Schin if (sym->flags & SYM_VARIADIC)
7774887Schin error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
7784887Schin sym->flags |= SYM_VARIADIC;
7794887Schin v = __va_args__;
7804887Schin }
7814887Schin else if (c == T_ID)
7824887Schin {
7834887Schin v = pp.token;
7844887Schin if (sym->flags & SYM_VARIADIC)
7854887Schin error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v);
7864887Schin else if (streq(v, __va_args__))
7874887Schin error(2, "%s: %s: invalid macro formal argument", sym->name, v);
7884887Schin }
7894887Schin else
7904887Schin break;
7914887Schin if (mac->arity < MAXFORMALS)
7924887Schin {
7934887Schin for (n = 0; n < mac->arity; n++)
7944887Schin if (streq(formargs[n], v))
7954887Schin error(2, "%s: %s: duplicate macro formal argument", sym->name, v);
7964887Schin formargs[mac->arity++] = p;
7974887Schin STRAPP(p, v, s);
7984887Schin }
7994887Schin else
8004887Schin error(2, "%s: %s: macro formal argument ignored", sym->name, v);
8014887Schin if ((c = pplex()) == ',')
8024887Schin {
8034887Schin c = pplex();
8044887Schin #if COMPATIBLE
8054887Schin if ((pp.state & COMPATIBILITY) && c == ',')
8064887Schin {
8074887Schin if ((pp.state & WARN) && !(pp.mode & HOSTED))
8084887Schin error(1, "%s: macro formal argument expected", sym->name);
8094887Schin while ((c = pplex()) == ',');
8104887Schin }
8114887Schin #endif
8124887Schin }
8134887Schin else if (c != T_VARIADIC)
8144887Schin break;
8154887Schin else
8164887Schin {
8174887Schin if (sym->flags & SYM_VARIADIC)
8184887Schin error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
8194887Schin sym->flags |= SYM_VARIADIC;
8204887Schin c = pplex();
8214887Schin break;
8224887Schin }
8234887Schin }
8244887Schin if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals)
8254887Schin {
8264887Schin n1 = s - mac->formals;
8274887Schin for (n = 0; n < mac->arity; n++)
8284887Schin formargs[n] += n1;
8294887Schin mac->formals = s;
8304887Schin }
8314887Schin }
8324887Schin if (!mac->arity)
8334887Schin {
8344887Schin free(mac->formals);
8354887Schin mac->formals = 0;
8364887Schin }
8374887Schin switch (c)
8384887Schin {
8394887Schin case ')':
8404887Schin #if MACKEYARGS
8414887Schin pp.state |= NOEXPAND|NOSPACE;
8424887Schin #else
8434887Schin pp.state |= NOEXPAND;
8444887Schin #endif
8454887Schin c = pplex();
8464887Schin break;
8474887Schin default:
8484887Schin error(2, "%s: invalid macro formal argument list", sym->name);
8494887Schin if (mac->formals)
8504887Schin {
8514887Schin free(mac->formals);
8524887Schin mac->formals = 0;
8534887Schin mac->arity = 0;
8544887Schin }
8554887Schin free(mac);
8564887Schin sym->macro = 0;
8574887Schin goto eatdirective;
8584887Schin }
8594887Schin pp.state &= ~NOSPACE;
8604887Schin break;
8614887Schin case ' ':
8624887Schin case '\t':
8634887Schin c = pplex();
8644887Schin break;
8654887Schin }
8664887Schin n = 2 * MAXTOKEN;
8674887Schin #if MACKEYARGS
8684887Schin p1 = p;
8694887Schin #endif
8704887Schin p = mac->value = oldof(0, char, 0, n);
8714887Schin var.type = 0;
8724887Schin n1 = 0;
8734887Schin #if MACDEF
8744887Schin i2 = i3 = 0;
8754887Schin n3 = pp.state;
8764887Schin #endif
8774887Schin if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
8784887Schin switch (c)
8794887Schin {
8804887Schin case '+':
8814887Schin case '-':
8824887Schin case '&':
8834887Schin case '|':
8844887Schin case '<':
8854887Schin case '>':
8864887Schin case ':':
8874887Schin case '=':
8884887Schin *p++ = ' ';
8894887Schin break;
8904887Schin }
8914887Schin o = 0;
8924887Schin for (;;)
8934887Schin {
8944887Schin switch (c)
8954887Schin {
8964887Schin case T_ID:
8974887Schin for (c = 0; c < mac->arity; c++)
8984887Schin if (streq(formargs[c], pp.token))
8994887Schin {
9004887Schin #if COMPATIBLE
9014887Schin if (!(pp.state & COMPATIBILITY))
9024887Schin #endif
9034887Schin if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' ';
9044887Schin *p++ = MARK;
9054887Schin #if COMPATIBLE
9064887Schin if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C';
9074887Schin else
9084887Schin #endif
9094887Schin *p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A';
9104887Schin *p++ = c + ARGOFFSET;
9118462SApril.Chin@Sun.COM if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX)) && var.type != TOK_TOKCAT && !(var.type & TOK_ID))
9128462SApril.Chin@Sun.COM {
9138462SApril.Chin@Sun.COM s = pp.in->nextchr;
9148462SApril.Chin@Sun.COM while ((c = *s++) && (c == ' ' || c == '\t'));
9158462SApril.Chin@Sun.COM if (c == '\n')
9168462SApril.Chin@Sun.COM c = 0;
9178462SApril.Chin@Sun.COM else if (c == '*' && *s == ')')
9188462SApril.Chin@Sun.COM c = ')';
9198462SApril.Chin@Sun.COM else if (c == '=' || ppisidig(c) || c == *s || *s == '=')
9208462SApril.Chin@Sun.COM c = 0;
9218462SApril.Chin@Sun.COM if (o != '.' && o != T_PTRMEM)
9228462SApril.Chin@Sun.COM {
9238462SApril.Chin@Sun.COM if ((var.type & TOK_ID) || o == ' ' || ppisseparate(o))
9248462SApril.Chin@Sun.COM o = 0;
9258462SApril.Chin@Sun.COM if (!((o == 0 || o == '(' || o == ')' || o == '[' || o == ']' || o == ',' || o == '|' || o == ';' || o == '{' || o == '}') && (c == '(' || c == ')' || c == '[' || c == ']' || c == ',' || c == '|' || c == ';' || c == '}' || c == 0)) && !(o == '*' && c == ')'))
9268462SApril.Chin@Sun.COM 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);
9278462SApril.Chin@Sun.COM }
9288462SApril.Chin@Sun.COM }
9294887Schin var.type = TOK_FORMAL|TOK_ID;
9304887Schin c = '>';
9314887Schin goto checkvalue;
9324887Schin }
9334887Schin if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token))
9344887Schin {
9354887Schin case V_DEFAULT:
9364887Schin case V_EMPTY:
9374887Schin sym->flags |= SYM_EMPTY;
9384887Schin break;
9394887Schin }
9404887Schin else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden)
9414887Schin {
9424887Schin for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev);
9434887Schin p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token);
9444887Schin var.type = TOK_ID;
9454887Schin goto checkvalue;
9464887Schin }
9474887Schin var.type = TOK_ID;
9484887Schin break;
9494887Schin case '#':
9504887Schin var.type = 0;
9514887Schin #if MACDEF
9524887Schin if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break;
9534887Schin #else
9544887Schin if (!(sym->flags & SYM_FUNCTION)) break;
9554887Schin #endif
9564887Schin pp.state |= NOSPACE;
9574887Schin c = pplex();
9584887Schin if (c == '@')
9594887Schin {
9604887Schin c = pplex();
9614887Schin i4 = 'S';
9624887Schin }
9634887Schin else i4 = 'Q';
9644887Schin pp.state &= ~NOSPACE;
9654887Schin if (c != T_ID) c = mac->arity;
9664887Schin else for (c = 0; c < mac->arity; c++)
9674887Schin if (streq(formargs[c], pp.token))
9684887Schin break;
9694887Schin if (c >= mac->arity)
9704887Schin {
9714887Schin #if MACDEF
9724887Schin if (sym->flags & SYM_MULTILINE)
9734887Schin {
9744887Schin if (n3 & NEWLINE)
9754887Schin {
9764887Schin pp.state &= ~NOEXPAND;
9774887Schin switch ((int)hashref(pp.dirtab, pp.token))
9784887Schin {
9794887Schin case ENDMAC:
9804887Schin if (!i2--) goto gotdefinition;
9814887Schin break;
9824887Schin case INCLUDE:
9834887Schin /* PARSE HEADER constant */
9844887Schin break;
9854887Schin case MACDEF:
9864887Schin i2++;
9874887Schin break;
9884887Schin }
9894887Schin *p++ = '#';
9904887Schin }
9914887Schin }
9924887Schin else
9934887Schin #endif
9944887Schin #if COMPATIBLE
9954887Schin if (pp.state & COMPATIBILITY) *p++ = '#';
9964887Schin else
9974887Schin #endif
9984887Schin error(2, "# must precede a formal parameter");
9994887Schin }
10004887Schin else
10014887Schin {
10024887Schin if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' ';
10034887Schin *p++ = MARK;
10044887Schin *p++ = i4;
10054887Schin *p++ = c + ARGOFFSET;
10064887Schin goto checkvalue;
10074887Schin }
10084887Schin break;
10094887Schin case T_TOKCAT:
10104887Schin if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token);
10114887Schin else
10124887Schin {
10134887Schin if (*(p - 1) == ' ') p--;
10144887Schin if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
10154887Schin }
10164887Schin pp.state |= NOSPACE;
10174887Schin c = pplex();
10184887Schin pp.state &= ~NOSPACE;
10194887Schin if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT));
10204887Schin var.type = TOK_TOKCAT;
10214887Schin continue;
10224887Schin case '(':
10234887Schin if (*pp.token == '#')
10244887Schin {
10254887Schin var.type = TOK_BUILTIN;
10264887Schin n1++;
10274887Schin }
10284887Schin else
10294887Schin {
10304887Schin var.type = 0;
10314887Schin if (n1) n1++;
10324887Schin }
10334887Schin break;
10344887Schin case ')':
10354887Schin var.type = 0;
10364887Schin if (n1) n1--;
10374887Schin break;
10384887Schin case T_STRING:
10394887Schin case T_CHARCONST:
10404887Schin pp.state &= ~NOEXPAND;
10414887Schin var.type = 0;
10424887Schin if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND;
10434887Schin #if COMPATIBLE
10444887Schin /*UNDENT*/
10454887Schin
10464887Schin if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION)))
10474887Schin {
10484887Schin char* v;
10494887Schin
10504887Schin s = pp.token;
10514887Schin for (;;)
10524887Schin {
10534887Schin if (!*s) goto checkvalue;
10544887Schin if (ppisid(*s))
10554887Schin {
10564887Schin v = s;
10574887Schin while (ppisid(*++s));
10584887Schin i1 = *s;
10594887Schin *s = 0;
10604887Schin for (c = 0; c < mac->arity; c++)
10614887Schin if (streq(formargs[c], v))
10624887Schin {
10634887Schin *p++ = MARK;
10644887Schin *p++ = 'C';
10654887Schin *p++ = c + ARGOFFSET;
10664887Schin if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token)
10674887Schin {
10684887Schin case '"':
10694887Schin error(1, "use the # operator to \"...\" quote macro arguments");
10704887Schin break;
10714887Schin case '\'':
10724887Schin error(1, "macro arguments should be '...' quoted before substitution");
10734887Schin break;
10744887Schin }
10754887Schin goto quotearg;
10764887Schin }
10774887Schin STRCOPY2(p, v);
10784887Schin quotearg:
10794887Schin *s = i1;
10804887Schin }
10814887Schin else *p++ = *s++;
10824887Schin }
10834887Schin }
10844887Schin /*INDENT*/
10854887Schin #endif
10864887Schin break;
10874887Schin case '\n':
10884887Schin #if MACDEF
10894887Schin if (sym->flags & SYM_MULTILINE)
10904887Schin {
10914887Schin if (pp.state & EOF2NL)
10924887Schin {
10934887Schin error_info.line++;
10944887Schin pp.state |= HIDDEN;
10954887Schin pp.hidden++;
10964887Schin var.type = 0;
10974887Schin if (!i3++)
10984887Schin goto checkvalue;
10994887Schin break;
11004887Schin }
11014887Schin pp.state |= EOF2NL;
11024887Schin error(2, "%s: missing #%s", sym->name, dirname(ENDMAC));
11034887Schin }
11044887Schin #endif
11054887Schin goto gotdefinition;
11064887Schin case 0:
11074887Schin c = '\n';
11084887Schin goto gotdefinition;
11094887Schin #if COMPATIBLE
11104887Schin case ' ':
11114887Schin if (pp.state & COMPATIBILITY) var.type = 0;
11124887Schin if (pp.option & PRESERVE) break;
11134887Schin if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
11144887Schin goto checkvalue;
11154887Schin case '\t':
11164887Schin if (var.type & TOK_ID)
11174887Schin {
11184887Schin while ((c = pplex()) == '\t');
11194887Schin if (c == T_ID)
11204887Schin {
11214887Schin if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
11224887Schin var.type = TOK_TOKCAT;
11234887Schin if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments");
11244887Schin }
11254887Schin else var.type = 0;
11264887Schin continue;
11274887Schin }
11284887Schin var.type = 0;
11294887Schin if (pp.option & PRESERVE) break;
11304887Schin if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
11314887Schin goto checkvalue;
11324887Schin #endif
11334887Schin case MARK:
11344887Schin pp.state &= ~NOEXPAND;
11354887Schin /*FALLTHROUGH*/
11364887Schin
11374887Schin default:
11384887Schin var.type = 0;
11394887Schin break;
11404887Schin }
11414887Schin STRCOPY(p, pp.token, s);
11424887Schin checkvalue:
11434887Schin o = c;
11444887Schin if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value)
11454887Schin {
11464887Schin c = p - mac->value;
11474887Schin mac->value = s;
11484887Schin p = mac->value + c;
11494887Schin }
11504887Schin #if MACDEF
11514887Schin n3 = pp.state;
11524887Schin #endif
11534887Schin c = pplex();
11544887Schin }
11554887Schin gotdefinition:
11564887Schin while (p > mac->value && *(p - 1) == ' ') p--;
11574887Schin if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
11584887Schin switch (o)
11594887Schin {
11604887Schin case '+':
11614887Schin case '-':
11624887Schin case '&':
11634887Schin case '|':
11644887Schin case '<':
11654887Schin case '>':
11664887Schin case ':':
11674887Schin case '=':
11684887Schin *p++ = ' ';
11694887Schin break;
11704887Schin }
11714887Schin *p = 0;
11724887Schin #if MACKEYARGS
11734887Schin if (!mac->arity) /* ok */;
11744887Schin else if (pp.option & KEYARGS)
11754887Schin {
11764887Schin p0 = mac->formals;
11774887Schin mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1);
11784887Schin s = (char*)&mac->formkeys[mac->arity];
11794887Schin (void)memcpy(s, p0, p1 - p0 + 1);
11804887Schin free(p0);
11814887Schin for (n = 0; n < mac->arity; n++)
11824887Schin {
11834887Schin mac->formkeys[n].name = s + (formargs[n] - p0);
11844887Schin mac->formkeys[n].value = s + (formvals[n] - p0);
11854887Schin }
11864887Schin }
11874887Schin else
11884887Schin #endif
11894887Schin for (n = 1; n < mac->arity; n++)
11904887Schin *(formargs[n] - 1) = ',';
11914887Schin if (old.value)
11924887Schin {
11934887Schin if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined;
11944887Schin if (!old.formals)
11954887Schin {
11964887Schin if (mac->formals) goto redefined;
11974887Schin }
11984887Schin else if (mac->formals)
11994887Schin {
12004887Schin #if MACKEYARGS
12014887Schin if (pp.option & KEYARGS)
12024887Schin {
12034887Schin for (n = 0; n < mac->arity; n++)
12044887Schin if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value))
12054887Schin goto redefined;
12064887Schin }
12074887Schin else
12084887Schin #endif
12094887Schin if (!streq(mac->formals, old.formals)) goto redefined;
12104887Schin }
12114887Schin #if MACKEYARGS
12124887Schin if (pp.option & KEYARGS)
12134887Schin {
12144887Schin if (mac->formkeys) free(mac->formkeys);
12154887Schin mac->formkeys = old.formkeys;
12164887Schin }
12174887Schin else
12184887Schin #endif
12194887Schin {
12204887Schin if (mac->formals) free(mac->formals);
12214887Schin mac->formals = old.formals;
12224887Schin }
12234887Schin free(mac->value);
12244887Schin mac->value = old.value;
12254887Schin goto benign;
12264887Schin redefined:
12274887Schin if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL))
12284887Schin error(1, "%s redefined", sym->name);
12294887Schin #if MACKEYARGS
12304887Schin if ((pp.option & KEYARGS) && mac->formkeys)
12314887Schin free(mac->formkeys);
12324887Schin #endif
12334887Schin #if MACKEYARGS
12344887Schin if (!(pp.option & KEYARGS))
12354887Schin #endif
12364887Schin if (old.formals) free(old.formals);
12374887Schin free(old.value);
12384887Schin }
12394887Schin else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name);
12404887Schin mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0);
12414887Schin 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)))
12424887Schin {
12434887Schin ppsync();
12444887Schin ppprintf("#%s %s", dirname(DEFINE), sym->name);
12454887Schin if (sym->flags & SYM_FUNCTION)
12464887Schin {
12474887Schin ppputchar('(');
12484887Schin if (mac->formals)
12494887Schin ppprintf("%s", mac->formals);
12504887Schin ppputchar(')');
12514887Schin }
12524887Schin if ((p = mac->value) && *p)
12534887Schin {
12544887Schin ppputchar(' ');
12554887Schin i0 = 0;
12564887Schin while (n = *p++)
12574887Schin {
12584887Schin if (n != MARK || (n = *p++) == MARK)
12594887Schin {
12604887Schin ppputchar(n);
12614887Schin i0 = ppisid(n);
12624887Schin }
12634887Schin else
12644887Schin {
12654887Schin if (n == 'Q')
12664887Schin ppputchar('#');
12674887Schin else if (i0)
12684887Schin {
12694887Schin ppputchar('#');
12704887Schin ppputchar('#');
12714887Schin }
12724887Schin s = formargs[*p++ - ARGOFFSET];
12734887Schin while ((n = *s++) && n != ',')
12744887Schin ppputchar(n);
12754887Schin if (ppisid(*p) || *p == MARK)
12764887Schin {
12774887Schin ppputchar('#');
12784887Schin ppputchar('#');
12794887Schin }
12804887Schin i0 = 0;
12814887Schin }
12824887Schin ppcheckout();
12834887Schin }
12844887Schin }
12854887Schin emitted = 1;
12864887Schin }
12874887Schin benign:
12884887Schin if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN;
12894887Schin if (pp.option & FINAL) sym->flags |= SYM_FINAL;
12904887Schin if (pp.mode & INIT) sym->flags |= SYM_INIT;
12914887Schin if (pp.option & INITIAL) sym->flags |= SYM_INITIAL;
12924887Schin if (pp.state & NOEXPAND) sym->flags |= SYM_NOEXPAND;
12934887Schin if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED;
12944887Schin if (pp.mode & READONLY) sym->flags |= SYM_READONLY;
12954887Schin 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);
12964887Schin break;
12974887Schin assertion:
12984887Schin c = pplex();
12994887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
13004887Schin error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0));
13014887Schin if (c != T_ID)
13024887Schin {
13034887Schin error(2, "%s: invalid predicate name", pptokstr(pp.token, 0));
13044887Schin goto eatdirective;
13054887Schin }
13064887Schin switch ((int)hashref(pp.strtab, pp.token))
13074887Schin {
13084887Schin case X_DEFINED:
13094887Schin case X_EXISTS:
13104887Schin case X_STRCMP:
13114887Schin error(2, "%s is a builtin predicate", pp.token);
13124887Schin goto eatdirective;
13134887Schin case X_SIZEOF:
13144887Schin error(2, "%s cannot be a predicate", pp.token);
13154887Schin goto eatdirective;
13164887Schin }
13174887Schin strcpy(pp.tmpbuf, pp.token);
13184887Schin switch (pppredargs())
13194887Schin {
13204887Schin case T_ID:
13214887Schin case T_STRING:
13224887Schin assert(directive, pp.tmpbuf, pp.args);
13234887Schin break;
13244887Schin case 0:
13254887Schin assert(directive, pp.tmpbuf, NiL);
13264887Schin break;
13274887Schin default:
13284887Schin error(2, "invalid predicate argument list");
13294887Schin goto eatdirective;
13304887Schin }
13314887Schin break;
13324887Schin tuple:
13334887Schin pp.state |= DEFINITION|NOEXPAND|NOSPACE;
13344887Schin rp = 0;
13354887Schin tp = mac->tuple;
13364887Schin if (!tp && !mac->value)
13374887Schin ppfsm(FSM_MACRO, sym->name);
13384887Schin while ((c = pplex()) && c != '>' && c != '\n')
13394887Schin {
13404887Schin for (; tp; tp = tp->nomatch)
13414887Schin if (streq(tp->token, pp.token))
13424887Schin break;
13434887Schin if (!tp)
13444887Schin {
13454887Schin if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token))))
13464887Schin error(3, "out of space");
13474887Schin strcpy(tp->token, pp.token);
13484887Schin if (rp)
13494887Schin {
13504887Schin tp->nomatch = rp;
13514887Schin rp->nomatch = tp;
13524887Schin }
13534887Schin else
13544887Schin {
13554887Schin tp->nomatch = mac->tuple;
13564887Schin mac->tuple = tp;
13574887Schin }
13584887Schin }
13594887Schin rp = tp;
13604887Schin tp = tp->match;
13614887Schin }
13624887Schin pp.state &= ~NOSPACE;
13634887Schin if (!rp || c != '>')
13644887Schin error(2, "%s: > omitted in tuple macro definition", sym->name);
13654887Schin else
13664887Schin {
13674887Schin n = 2 * MAXTOKEN;
13684887Schin p = v = oldof(0, char, 0, n);
13694887Schin while ((c = pplex()) && c != '\n')
13704887Schin if (p > v || c != ' ')
13714887Schin {
13724887Schin STRCOPY(p, pp.token, s);
13734887Schin if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v)
13744887Schin {
13754887Schin c = p - v;
13764887Schin v = s;
13774887Schin p = v + c;
13784887Schin }
13794887Schin }
13804887Schin while (p > v && *(p - 1) == ' ')
13814887Schin p--;
13824887Schin n = p - v;
13834887Schin tp = newof(0, struct pptuple, 1, n);
13844887Schin strcpy(tp->token, v);
13854887Schin tp->match = rp->match;
13864887Schin rp->match = tp;
13874887Schin }
13884887Schin goto benign;
13894887Schin case WARNING:
13904887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
13914887Schin error(1, "#%s: non-standard directive", pp.token);
13924887Schin /*FALLTHROUGH*/
13934887Schin case ERROR:
13944887Schin pp.state &= ~DISABLE;
13954887Schin p = pp.tmpbuf;
13964887Schin while ((c = pplex()) != '\n')
13974887Schin if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN])
13984887Schin {
13994887Schin STRCOPY(p, pp.token, s);
14004887Schin pp.state &= ~NOSPACE;
14014887Schin }
14024887Schin *p = 0;
14034887Schin p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error");
14044887Schin n = (directive == WARNING) ? 1 : 3;
14054887Schin error(n, "%s", p);
14064887Schin break;
14074887Schin case LET:
14084887Schin n2 = error_info.line;
14094887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
14104887Schin error(1, "#%s: non-standard directive", pp.token);
14114887Schin if (!(sym = macsym(c = pplex()))) goto eatdirective;
14124887Schin if ((c = pplex()) != '=')
14134887Schin {
14144887Schin error(2, "%s: = expected", sym->name);
14154887Schin goto eatdirective;
14164887Schin }
14174887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC);
14184887Schin mac = sym->macro;
14194887Schin mac->arity = 0;
14204887Schin if (mac->value)
14214887Schin {
14224887Schin if (!(sym->flags & SYM_REDEFINE) && !sym->hidden)
14234887Schin error(1, "%s: redefined", sym->name);
14244887Schin #if MACKEYARGS
14254887Schin if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys);
14264887Schin else
14274887Schin #endif
14284887Schin free(mac->formals);
14294887Schin mac->formals = 0;
14304887Schin n = strlen(mac->value) + 1;
14314887Schin }
14324887Schin else
14334887Schin {
14344887Schin ppfsm(FSM_MACRO, sym->name);
14354887Schin n = 0;
14364887Schin }
14374887Schin n1 = ppexpr(&i1);
14384887Schin if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1);
14394887Schin else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1);
14404887Schin if (n < ++c)
14414887Schin {
14424887Schin if (mac->value) free(mac->value);
14434887Schin mac->value = oldof(0, char, 0, c);
14444887Schin }
14454887Schin strcpy(mac->value, pp.tmpbuf);
14464887Schin sym->flags |= SYM_REDEFINE;
14474887Schin c = (pp.state & NEWLINE) ? '\n' : ' ';
14484887Schin goto benign;
14494887Schin case LINE:
14504887Schin pp.state &= ~DISABLE;
14514887Schin if ((c = pplex()) == '#')
14524887Schin {
14534887Schin c = pplex();
14544887Schin directive = INCLUDE;
14554887Schin }
14564887Schin if (c != T_DECIMAL && c != T_OCTAL)
14574887Schin {
14584887Schin error(1, "#%s: line number expected", dirname(LINE));
14594887Schin goto eatdirective;
14604887Schin }
14614887Schin linesync:
14624887Schin n = error_info.line;
14634887Schin error_info.line = strtol(pp.token, NiL, 0);
14644887Schin if (error_info.line == 0 && directive == LINE && (pp.state & STRICT) && !(pp.mode & HOSTED))
14654887Schin error(1, "#%s: line number should be > 0", dirname(LINE));
14664887Schin pp.state &= ~DISABLE;
14674887Schin pp.state |= STRIP;
14684887Schin switch (c = pplex())
14694887Schin {
14704887Schin case T_STRING:
14714887Schin s = error_info.file;
1472*10898Sroland.mainz@nrubsig.org if (*(p = pp.token))
1473*10898Sroland.mainz@nrubsig.org pathcanon(p, 0);
14744887Schin fp = ppsetfile(p);
14754887Schin error_info.file = fp->name;
14764887Schin if (error_info.line == 1)
1477*10898Sroland.mainz@nrubsig.org ppmultiple(fp, INC_IGNORE);
14784887Schin switch (c = pplex())
14794887Schin {
14804887Schin case '\n':
14814887Schin break;
14824887Schin case T_DECIMAL:
14834887Schin case T_OCTAL:
14844887Schin if (directive == LINE && (pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
14854887Schin error(1, "#%s: integer file type argument is non-standard", dirname(LINE));
14864887Schin break;
14874887Schin default:
14884887Schin error(1, "#%s: integer file type argument expected", dirname(LINE));
14894887Schin break;
14904887Schin }
14914887Schin if (directive == LINE) pp.in->flags &= ~IN_ignoreline;
14924887Schin else if (pp.incref)
14934887Schin {
14944887Schin if (error_info.file != s)
14954887Schin {
14964887Schin switch (*pp.token)
14974887Schin {
14984887Schin case PP_sync_push:
14994887Schin if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15004887Schin else (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
15014887Schin break;
15024887Schin case PP_sync_pop:
15034887Schin if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15044887Schin else (*pp.incref)(s, error_info.file, n - 1, PP_SYNC_POP);
15054887Schin break;
15064887Schin case PP_sync_ignore:
15074887Schin if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15084887Schin else
15094887Schin {
15104887Schin (*pp.incref)(s, error_info.file, n, PP_SYNC_IGNORE);
15114887Schin error_info.file = s;
15124887Schin }
15134887Schin break;
15144887Schin default:
15154887Schin if (*s)
15164887Schin {
15174887Schin if (fp == pp.insert)
15184887Schin pp.insert = 0;
15194887Schin else if (error_info.line == 1 && !pp.insert)
15204887Schin (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
15214887Schin else
15224887Schin {
15234887Schin if (!pp.insert) pp.insert = ppgetfile(s);
15244887Schin (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15254887Schin }
15264887Schin }
15274887Schin break;
15284887Schin }
15294887Schin }
15304887Schin }
15314887Schin break;
15324887Schin case '\n':
15334887Schin break;
15344887Schin default:
15354887Schin error(1, "#%s: \"file-name\" expected", dirname(LINE));
15364887Schin break;
15374887Schin }
15384887Schin if (directive == LINE && (pp.in->flags & IN_ignoreline))
15394887Schin error_info.line = n + 1;
15404887Schin else
15414887Schin {
15424887Schin pp.hidden = 0;
15434887Schin pp.state &= ~HIDDEN;
15444887Schin if (pp.linesync)
15454887Schin {
15464887Schin #if CATSTRINGS
15474887Schin if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
15484887Schin else
15494887Schin #endif
15504887Schin {
15514887Schin s = pp.lineid;
15524887Schin n = pp.flags;
15534887Schin if (directive == LINE)
15544887Schin {
15554887Schin pp.flags &= ~PP_linetype;
15564887Schin if (pp.macref) pp.lineid = dirname(LINE);
15574887Schin }
15584887Schin (*pp.linesync)(error_info.line, error_info.file);
15594887Schin pp.flags = n;
15604887Schin pp.lineid = s;
15614887Schin }
15624887Schin }
15634887Schin }
15644887Schin directive = LINE;
15654887Schin break;
15664887Schin case PRAGMA:
15674887Schin /*
15684887Schin * #pragma [STDC] [pass:] [no]option [arg ...]
15694887Schin *
15704887Schin * pragma args are not expanded by default
15714887Schin *
15724887Schin * if STDC is present then it is silently passed on
15734887Schin *
15744887Schin * if pass is pp.pass then the option is used
15754887Schin * and verified but is not passed on
15764887Schin *
15774887Schin * if pass is omitted then the option is passed on
15784887Schin *
15794887Schin * otherwise if pass is non-null and not pp.pass then
15804887Schin * the option is passed on but not used
15814887Schin *
15824887Schin * if the line does not match this form then
15834887Schin * it is passed on unchanged
15844887Schin *
15854887Schin * #directive pass: option [...]
15864887Schin * ^ ^ ^ ^ ^ ^ ^ ^
15874887Schin * pp.valbuf p0 p1 p2 p3 p4 p5 p6
15884887Schin *
15894887Schin * p? 0 if component omitted
15904887Schin * i0 0 if ``no''option
15914887Schin */
15924887Schin
15934887Schin p = pp.valbuf;
15944887Schin *p++ = '#';
15954887Schin STRCOPY(p, pp.token, s);
15964887Schin p0 = p;
15974887Schin if (pp.option & PRAGMAEXPAND)
15984887Schin pp.state &= ~DISABLE;
15994887Schin if (!(p6 = getline(p, &pp.valbuf[MAXTOKEN], !!(pp.option & PRAGMAEXPAND))))
16004887Schin {
16014887Schin *p0 = 0;
16024887Schin error(2, "%s: directive too long", pp.valbuf);
16034887Schin c = 0;
16044887Schin goto eatdirective;
16054887Schin }
16064887Schin p1 = ++p;
16074887Schin while (ppisid(*p))
16084887Schin p++;
16094887Schin if (p == p1)
16104887Schin {
16114887Schin p5 = p;
16124887Schin p4 = 0;
16134887Schin p3 = 0;
16144887Schin p2 = 0;
16154887Schin p1 = 0;
16164887Schin }
16174887Schin else if (*p != ':')
16184887Schin {
16194887Schin p5 = *p ? p + (*p == ' ') : 0;
16204887Schin p4 = p;
16214887Schin p3 = p1;
16224887Schin p2 = 0;
16234887Schin p1 = 0;
16244887Schin }
16254887Schin else
16264887Schin {
16274887Schin p2 = p++;
16284887Schin p3 = p;
16294887Schin while (ppisid(*p))
16304887Schin p++;
16314887Schin if (p == p3)
16324887Schin {
16334887Schin p4 = p1;
16344887Schin p3 = 0;
16354887Schin p2 = 0;
16364887Schin p1 = 0;
16374887Schin }
16384887Schin else
16394887Schin p4 = p;
16404887Schin p5 = *p4 ? p4 + (*p4 == ' ') : 0;
16414887Schin }
16424887Schin if (!p1 && p3 && (p4 - p3) == 4 && strneq(p3, "STDC", 4))
16434887Schin goto pass;
16448462SApril.Chin@Sun.COM if ((pp.state & WARN) && (pp.mode & (HOSTED|RELAX|PEDANTIC)) == PEDANTIC)
16454887Schin error(1, "#%s: non-standard directive", dirname(PRAGMA));
16464887Schin i0 = !p3 || *p3 != 'n' || *(p3 + 1) != 'o';
16474887Schin if (!p3)
16484887Schin goto checkmap;
16494887Schin if (p1)
16504887Schin {
16514887Schin *p2 = 0;
16524887Schin n = streq(p1, pp.pass);
16534887Schin *p2 = ':';
16544887Schin if (!n)
16554887Schin goto checkmap;
16564887Schin }
16574887Schin else
16584887Schin n = 0;
16594887Schin i2 = *p4;
16604887Schin *p4 = 0;
16614887Schin 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))
16624887Schin i1 = 0;
16634887Schin if ((pp.state & (COMPATIBILITY|STRICT)) == STRICT && !(pp.mode & (HOSTED|RELAX)))
16644887Schin {
16654887Schin if (pp.optflags[i1] & OPT_GLOBAL)
16664887Schin goto donedirective;
16674887Schin if (n || (pp.mode & WARN))
16684887Schin {
16694887Schin n = 0;
16704887Schin error(1, "#%s: non-standard directive ignored", dirname(PRAGMA));
16714887Schin }
16724887Schin i1 = 0;
16734887Schin }
16744887Schin if (!n)
16754887Schin {
16764887Schin if (!(pp.optflags[i1] & OPT_GLOBAL))
16774887Schin {
16784887Schin *p4 = i2;
16794887Schin goto checkmap;
16804887Schin }
16814887Schin if (!(pp.optflags[i1] & OPT_PASS))
16824887Schin n = 1;
16834887Schin }
16844887Schin else if (!i1)
16854887Schin error(2, "%s: unknown option", p1);
16864887Schin else if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
16874887Schin error(1, "%s: non-standard option", p1);
16884887Schin p = p5;
16894887Schin switch (i1)
16904887Schin {
16914887Schin case X_ALLMULTIPLE:
16924887Schin ppop(PP_MULTIPLE, i0);
16934887Schin break;
16944887Schin case X_ALLPOSSIBLE:
16954887Schin setoption(ALLPOSSIBLE, i0);
16964887Schin break;
16974887Schin case X_BUILTIN:
16984887Schin setmode(BUILTIN, i0);
16994887Schin break;
17004887Schin case X_CATLITERAL:
17014887Schin setmode(CATLITERAL, i0);
17024887Schin if (pp.mode & CATLITERAL)
17034887Schin setoption(STRINGSPLIT, 0);
17044887Schin break;
17054887Schin case X_CDIR:
17064887Schin tokop(PP_CDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
17074887Schin break;
17084887Schin case X_CHECKPOINT:
17094887Schin #if CHECKPOINT
17104887Schin ppload(p);
17114887Schin #else
17124887Schin error(3, "%s: preprocessor not compiled with checkpoint enabled", p3);
17134887Schin #endif
17144887Schin break;
17154887Schin case X_CHOP:
17164887Schin tokop(PP_CHOP, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
17174887Schin break;
17184887Schin case X_COMPATIBILITY:
17194887Schin ppop(PP_COMPATIBILITY, i0);
17204887Schin break;
17214887Schin case X_DEBUG:
17224887Schin error_info.trace = i0 ? (p ? -strtol(p, NiL, 0) : -1) : 0;
17234887Schin break;
17244887Schin case X_ELSEIF:
17254887Schin setoption(ELSEIF, i0);
17264887Schin break;
17274887Schin case X_EXTERNALIZE:
17284887Schin setmode(EXTERNALIZE, i0);
17294887Schin break;
17304887Schin case X_FINAL:
17314887Schin setoption(FINAL, i0);
17324887Schin break;
17334887Schin case X_HEADEREXPAND:
17344887Schin setoption(HEADEREXPAND, i0);
17354887Schin break;
17364887Schin case X_HEADEREXPANDALL:
17374887Schin setoption(HEADEREXPANDALL, i0);
17384887Schin break;
17394887Schin case X_HIDE:
17404887Schin case X_NOTE:
17414887Schin PUSH_LINE(p);
17424887Schin /* UNDENT...*/
17434887Schin while (c = pplex())
17444887Schin {
17454887Schin if (c != T_ID) error(1, "%s: %s: identifier expected", p3, pp.token);
17464887Schin else if (sym = ppsymset(pp.symtab, pp.token))
17474887Schin {
17484887Schin if (i1 == X_NOTE)
17494887Schin {
17504887Schin sym->flags &= ~SYM_NOTICED;
17514887Schin ppfsm(FSM_MACRO, sym->name);
17524887Schin }
17534887Schin else if (i0)
17544887Schin {
17554887Schin if (!sym->hidden && !(sym->hidden = newof(0, struct pphide, 1, 0)))
17564887Schin error(3, "out of space");
17574887Schin if (!sym->macro)
17584887Schin ppfsm(FSM_MACRO, sym->name);
17594887Schin if (!sym->hidden->level++)
17604887Schin {
17614887Schin pp.hiding++;
17624887Schin if (sym->macro && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
17634887Schin {
17644887Schin sym->hidden->macro = sym->macro;
17654887Schin sym->macro = 0;
17664887Schin sym->hidden->flags = sym->flags;
17674887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
17684887Schin }
17694887Schin }
17704887Schin }
17714887Schin else if (sym->hidden)
17724887Schin {
17734887Schin if ((mac = sym->macro) && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
17744887Schin {
17754887Schin if (mac->formals) free(mac->formals);
17764887Schin free(mac->value);
17774887Schin free(mac);
17784887Schin sym->macro = 0;
17794887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
17804887Schin }
17814887Schin if (!--sym->hidden->level)
17824887Schin {
17834887Schin pp.hiding--;
17844887Schin if (sym->hidden->macro)
17854887Schin {
17864887Schin sym->macro = sym->hidden->macro;
17874887Schin sym->flags = sym->hidden->flags;
17884887Schin }
17894887Schin free(sym->hidden);
17904887Schin sym->hidden = 0;
17914887Schin }
17924887Schin }
17934887Schin }
17944887Schin }
17954887Schin /*...INDENT*/
17964887Schin POP_LINE();
17974887Schin break;
17984887Schin case X_HOSTDIR:
17994887Schin tokop(PP_HOSTDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
18004887Schin break;
18014887Schin case X_HOSTED:
18024887Schin setmode(HOSTED, i0);
18034887Schin break;
18044887Schin case X_HOSTEDTRANSITION:
18054887Schin setmode(HOSTEDTRANSITION, i0);
18064887Schin break;
18074887Schin case X_ID:
18084887Schin tokop(PP_ID, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
18094887Schin break;
18104887Schin case X_IGNORE:
18114887Schin tokop(PP_IGNORE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
18124887Schin break;
18134887Schin case X_INCLUDE:
18144887Schin tokop(PP_INCLUDE, p3, p, i0, TOKOP_STRING|TOKOP_DUP);
18154887Schin break;
18164887Schin case X_INITIAL:
18174887Schin setoption(INITIAL, i0);
18184887Schin break;
18194887Schin case X_KEYARGS:
18204887Schin ppop(PP_KEYARGS, i0);
18214887Schin break;
18224887Schin case X_LINE:
18234887Schin if (pp.linesync) pp.olinesync = pp.linesync;
18244887Schin pp.linesync = i0 ? pp.olinesync : (PPLINESYNC)0;
18254887Schin break;
18264887Schin case X_LINEBASE:
18274887Schin ppop(PP_LINEBASE, i0);
18284887Schin break;
18294887Schin case X_LINEFILE:
18304887Schin ppop(PP_LINEFILE, i0);
18314887Schin break;
18324887Schin case X_LINEID:
18334887Schin ppop(PP_LINEID, i0 ? p : (char*)0);
18344887Schin break;
18354887Schin case X_LINETYPE:
18364887Schin ppop(PP_LINETYPE, i0 ? (p ? strtol(p, NiL, 0) : 1) : 0);
18374887Schin break;
18384887Schin case X_MACREF:
18394887Schin if (!p)
18404887Schin {
18414887Schin if (i0 && !pp.macref)
18424887Schin {
18434887Schin ppop(PP_LINETYPE, 1);
18444887Schin ppop(PP_MACREF, ppmacref);
18454887Schin }
18464887Schin else error(2, "%s: option cannot be unset", p3);
18474887Schin }
18484887Schin else if (s = strchr(p, ' '))
18494887Schin {
18504887Schin if (pp.macref && (s = strchr(p, ' ')))
18514887Schin {
18524887Schin *s++ = 0;
18534887Schin c = strtol(s, NiL, 0);
18544887Schin var.type = pp.truncate;
18554887Schin pp.truncate = PPTOKSIZ;
18564887Schin (*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);
18574887Schin pp.truncate = var.type;
18584887Schin }
18594887Schin error_info.line -= 2;
18604887Schin }
18614887Schin break;
18624887Schin case X_MAP:
18634887Schin /*UNDENT*/
18644887Schin /*
18654887Schin * #pragma pp:map [id ...] "/from/[,/to/]" [ "/old/new/[glnu]" ... ]
18664887Schin */
18674887Schin
18684887Schin if (!i0)
18694887Schin {
18704887Schin error(2, "%s: option cannot be unset", p3);
18714887Schin goto donedirective;
18724887Schin }
18734887Schin if (!p5)
18744887Schin {
18754887Schin error(2, "%s: address argument expected", p3);
18764887Schin goto donedirective;
18774887Schin }
18784887Schin PUSH_LINE(p5);
18794887Schin while ((c = pplex()) == T_ID)
18804887Schin {
18814887Schin sfsprintf(pp.tmpbuf, MAXTOKEN, "__%s__", s = pp.token);
18824887Schin if (c = (int)hashget(pp.dirtab, s))
18834887Schin {
18844887Schin hashput(pp.dirtab, 0, 0);
18854887Schin hashput(pp.dirtab, pp.tmpbuf, c);
18864887Schin }
18874887Schin if (c = (int)hashget(pp.strtab, s))
18884887Schin {
18894887Schin hashput(pp.strtab, 0, 0);
18904887Schin hashput(pp.strtab, pp.tmpbuf, c);
18914887Schin }
18924887Schin }
18934887Schin if (c != T_STRING || !*(s = pp.token))
18944887Schin {
18954887Schin if (c)
18964887Schin error(2, "%s: %s: address argument expected", p3, pptokstr(pp.token, 0));
18974887Schin goto eatmap;
18984887Schin }
18994887Schin map = newof(0, struct map, 1, 0);
19004887Schin
19014887Schin /*
19024887Schin * /from/
19034887Schin */
19044887Schin
19054887Schin if (i0 = regcomp(&map->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL))
19064887Schin regfatal(&map->re, 3, i0);
19074887Schin if (*(s += map->re.re_npat))
19084887Schin {
19094887Schin error(2, "%s: invalid characters after pattern: %s ", p3, s);
19104887Schin goto eatmap;
19114887Schin }
19124887Schin
19134887Schin /*
19144887Schin * /old/new/[flags]
19154887Schin */
19164887Schin
19174887Schin edit = 0;
19184887Schin while ((c = pplex()) == T_STRING)
19194887Schin {
19204887Schin if (!*(s = pp.token))
19214887Schin {
19224887Schin error(2, "%s: substitution argument expected", p3);
19234887Schin goto eatmap;
19244887Schin }
19254887Schin if (edit)
19264887Schin edit = edit->next = newof(0, struct edit, 1, 0);
19274887Schin else
19284887Schin edit = map->edit = newof(0, struct edit, 1, 0);
19294887Schin 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)))
19304887Schin s += edit->re.re_npat;
19314887Schin if (i0)
19324887Schin regfatal(&edit->re, 3, i0);
19334887Schin if (*s)
19344887Schin {
19354887Schin error(2, "%s: invalid characters after substitution: %s ", p3, s);
19364887Schin goto eatmap;
19374887Schin }
19384887Schin }
19394887Schin if (c)
19404887Schin {
19414887Schin error(2, "%s: %s: substitution argument expected", p3, pptokstr(pp.token, 0));
19424887Schin goto eatmap;
19434887Schin }
19444887Schin map->next = (struct map*)pp.maps;
19454887Schin pp.maps = (char*)map;
19464887Schin eatmap:
19474887Schin POP_LINE();
19484887Schin /*INDENT*/
19494887Schin break;
19504887Schin case X_MAPINCLUDE:
19514887Schin ppmapinclude(NiL, p5);
19524887Schin break;
19534887Schin case X_MODERN:
19544887Schin setoption(MODERN, i0);
19554887Schin break;
19564887Schin case X_MULTIPLE:
19574887Schin n = 1;
1958*10898Sroland.mainz@nrubsig.org if (pp.in->type == IN_FILE || pp.in->type == IN_RESCAN)
1959*10898Sroland.mainz@nrubsig.org ppmultiple(ppsetfile(error_info.file), i0 ? INC_CLEAR : INC_IGNORE);
19604887Schin break;
19614887Schin case X_NATIVE:
19624887Schin setoption(NATIVE, i0);
19634887Schin break;
19644887Schin case X_OPSPACE:
19654887Schin ppfsm(FSM_OPSPACE, i0 ? p4 : (char*)0);
19664887Schin break;
19674887Schin case X_PASSTHROUGH:
19684887Schin ppop(PP_PASSTHROUGH, i0);
19694887Schin break;
19704887Schin case X_PEDANTIC:
19714887Schin ppop(PP_PEDANTIC, i0);
19724887Schin break;
19734887Schin case X_PLUSCOMMENT:
19744887Schin ppop(PP_PLUSCOMMENT, i0);
19754887Schin break;
19764887Schin case X_PLUSPLUS:
19774887Schin ppop(PP_PLUSPLUS, i0);
19784887Schin break;
19794887Schin case X_PLUSSPLICE:
19804887Schin setoption(PLUSSPLICE, i0);
19814887Schin break;
19824887Schin case X_PRAGMAEXPAND:
19834887Schin setoption(PRAGMAEXPAND, i0);
19844887Schin break;
19854887Schin case X_PRAGMAFLAGS:
19864887Schin tokop(PP_PRAGMAFLAGS, p3, p, i0, 0);
19874887Schin break;
19884887Schin case X_PREDEFINED:
19894887Schin setoption(PREDEFINED, i0);
19904887Schin break;
19914887Schin case X_PREFIX:
19924887Schin setoption(PREFIX, i0);
19934887Schin break;
19944887Schin case X_PRESERVE:
19954887Schin setoption(PRESERVE, i0);
19964887Schin if (pp.option & PRESERVE)
19974887Schin {
19984887Schin setmode(CATLITERAL, 0);
19994887Schin ppop(PP_COMPATIBILITY, 1);
20004887Schin ppop(PP_TRANSITION, 0);
20014887Schin ppop(PP_PLUSCOMMENT, 1);
20024887Schin ppop(PP_SPACEOUT, 1);
20034887Schin setoption(STRINGSPAN, 1);
20044887Schin setoption(STRINGSPLIT, 0);
20054887Schin ppop(PP_HOSTDIR, "-", 1);
20064887Schin }
20074887Schin break;
20084887Schin case X_PROTOTYPED:
20094887Schin /*
20104887Schin * this option doesn't bump the token count
20114887Schin */
20124887Schin
20134887Schin n = 1;
20144887Schin directive = ENDIF;
20154887Schin #if PROTOTYPE
20164887Schin setoption(PROTOTYPED, i0);
20174887Schin #else
20184887Schin error(1, "preprocessor not compiled with prototype conversion enabled");
20194887Schin #endif
20204887Schin break;
20214887Schin case X_PROTO:
20224887Schin setoption(NOPROTO, !i0);
20234887Schin break;
20244887Schin case X_QUOTE:
20254887Schin tokop(PP_QUOTE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
20264887Schin break;
20274887Schin case X_READONLY:
20284887Schin setmode(READONLY, i0);
20294887Schin break;
20304887Schin case X_REGUARD:
20314887Schin setoption(REGUARD, i0);
20324887Schin break;
20334887Schin case X_RESERVED:
20344887Schin tokop(PP_RESERVED, p3, p, i0, 0);
20354887Schin break;
20364887Schin case X_SPACEOUT:
20374887Schin if (!(pp.state & (COMPATIBILITY|COMPILE)))
20384887Schin ppop(PP_SPACEOUT, i0);
20394887Schin break;
20404887Schin case X_SPLICECAT:
20414887Schin setoption(SPLICECAT, i0);
20424887Schin break;
20434887Schin case X_SPLICESPACE:
20444887Schin setoption(SPLICESPACE, i0);
20454887Schin break;
20464887Schin case X_STANDARD:
20474887Schin tokop(PP_STANDARD, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
20484887Schin break;
20494887Schin case X_STRICT:
20504887Schin ppop(PP_STRICT, i0);
20514887Schin break;
20524887Schin case X_STRINGSPAN:
20534887Schin setoption(STRINGSPAN, i0);
20544887Schin break;
20554887Schin case X_STRINGSPLIT:
20564887Schin setoption(STRINGSPLIT, i0);
20574887Schin if (pp.option & STRINGSPLIT)
20584887Schin setmode(CATLITERAL, 0);
20594887Schin break;
20604887Schin case X_SYSTEM_HEADER:
20614887Schin if (i0)
20624887Schin {
20634887Schin pp.mode |= HOSTED;
20644887Schin pp.flags |= PP_hosted;
20654887Schin pp.in->flags |= IN_hosted;
20664887Schin }
20674887Schin else
20684887Schin {
20694887Schin pp.mode &= ~HOSTED;
20704887Schin pp.flags &= ~PP_hosted;
20714887Schin pp.in->flags &= ~PP_hosted;
20724887Schin }
20734887Schin break;
20744887Schin case X_TEST:
20754887Schin ppop(PP_TEST, p);
20764887Schin break;
20774887Schin case X_TEXT:
20784887Schin if (!(pp.option & KEEPNOTEXT))
20794887Schin setstate(NOTEXT, !i0);
20804887Schin break;
20814887Schin case X_TRANSITION:
20824887Schin ppop(PP_TRANSITION, i0);
20834887Schin if (pp.state & TRANSITION) ppop(PP_COMPATIBILITY, i0);
20844887Schin break;
20854887Schin case X_TRUNCATE:
20864887Schin ppop(PP_TRUNCATE, i0 ? (p ? strtol(p, NiL, 0) : TRUNCLENGTH) : 0);
20874887Schin break;
20884887Schin case X_VENDOR:
20894887Schin tokop(PP_VENDOR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
20904887Schin break;
20914887Schin case X_VERSION:
20924887Schin if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT))
20934887Schin {
20944887Schin sfsprintf(pp.tmpbuf, MAXTOKEN, "\"%s\"", pp.version);
20954887Schin (*pp.pragma)(dirname(PRAGMA), pp.pass, p3, pp.tmpbuf, !n);
20964887Schin if (pp.linesync && !n)
20974887Schin (*pp.linesync)(error_info.line, error_info.file);
20984887Schin emitted = 1;
20994887Schin }
21004887Schin break;
21014887Schin case X_WARN:
21024887Schin ppop(PP_WARN, i0);
21034887Schin break;
21044887Schin case X_ZEOF:
21054887Schin setoption(ZEOF, i0);
21064887Schin break;
21074887Schin #if DEBUG
21084887Schin case 0:
21094887Schin case X_INCLUDED:
21104887Schin case X_NOTICED:
21114887Schin case X_OPTION:
21124887Schin case X_STATEMENT:
21134887Schin break;
21144887Schin default:
21154887Schin error(PANIC, "%s: option recognized but not implemented", pp.valbuf);
21164887Schin break;
21174887Schin #endif
21184887Schin }
21194887Schin *p4 = i2;
21204887Schin if (!n)
21214887Schin goto checkmap;
21224887Schin goto donedirective;
21234887Schin case RENAME:
21244887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
21254887Schin error(1, "#%s: non-standard directive", pp.token);
21264887Schin if ((c = pplex()) != T_ID)
21274887Schin {
21284887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
21294887Schin goto eatdirective;
21304887Schin }
21314887Schin if (!(sym = pprefmac(pp.token, REF_DELETE)) || !sym->macro)
21324887Schin goto eatdirective;
21334887Schin if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
21344887Schin {
21354887Schin if (!(pp.option & ALLPOSSIBLE))
21364887Schin error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
21374887Schin goto eatdirective;
21384887Schin }
21394887Schin if ((c = pplex()) != T_ID)
21404887Schin {
21414887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
21424887Schin goto eatdirective;
21434887Schin }
21444887Schin var.symbol = pprefmac(pp.token, REF_CREATE);
21454887Schin if (mac = var.symbol->macro)
21464887Schin {
21474887Schin if (var.symbol->flags & (SYM_ACTIVE|SYM_READONLY))
21484887Schin {
21494887Schin if (!(pp.option & ALLPOSSIBLE))
21504887Schin error(2, "%s: macro is %s", var.symbol->name, (var.symbol->flags & SYM_READONLY) ? "readonly" : "active");
21514887Schin goto eatdirective;
21524887Schin }
21534887Schin if (!(pp.mode & HOSTED) || !(var.symbol->flags & SYM_INITIAL))
21544887Schin error(1, "%s redefined", var.symbol->name);
21554887Schin if (mac->formals) free(mac->formals);
21564887Schin free(mac->value);
21574887Schin free(mac);
21584887Schin }
21594887Schin ppfsm(FSM_MACRO, var.symbol->name);
21604887Schin var.symbol->flags = sym->flags;
21614887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
21624887Schin var.symbol->macro = sym->macro;
21634887Schin sym->macro = 0;
21644887Schin break;
21654887Schin case UNDEF:
21664887Schin if ((c = pplex()) != T_ID)
21674887Schin {
21684887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
21694887Schin goto eatdirective;
21704887Schin }
21714887Schin if (sym = pprefmac(pp.token, REF_DELETE))
21724887Schin {
21734887Schin if (mac = sym->macro)
21744887Schin {
21754887Schin if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
21764887Schin {
21774887Schin if (!(pp.option & ALLPOSSIBLE))
21784887Schin error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
21794887Schin goto eatdirective;
21804887Schin }
21814887Schin if (mac->formals) free(mac->formals);
21824887Schin free(mac->value);
21834887Schin free(mac);
21844887Schin mac = sym->macro = 0;
21854887Schin }
21864887Schin 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)))
21874887Schin {
21884887Schin ppsync();
21894887Schin ppprintf("#%s %s", dirname(UNDEF), sym->name);
21904887Schin emitted = 1;
21914887Schin }
21924887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
21934887Schin n2 = error_info.line;
21944887Schin goto benign;
21954887Schin }
21964887Schin else pprefmac(pp.token, REF_UNDEF);
21974887Schin break;
21984887Schin #if DEBUG
21994887Schin default:
22004887Schin error(PANIC, "#%s: directive recognized but not implemented", pp.token);
22014887Schin goto eatdirective;
22024887Schin #endif
22034887Schin }
22044887Schin break;
22054887Schin case '\n':
22064887Schin break;
22074887Schin default:
22084887Schin error(1, "%s: invalid directive name", pptokstr(pp.token, 0));
22094887Schin goto eatdirective;
22104887Schin }
22114887Schin enddirective:
22124887Schin #if COMPATIBLE
22134887Schin if (c != '\n' && !(pp.state & COMPATIBILITY))
22144887Schin #else
22154887Schin if (c != '\n')
22164887Schin #endif
22174887Schin {
22184887Schin pp.state |= DISABLE|NOSPACE;
22194887Schin if ((c = pplex()) != '\n' && (pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC)
22204887Schin error(1, "%s: invalid characters after directive", pptokstr(pp.token, 0));
22214887Schin }
22224887Schin eatdirective:
22234887Schin if (c != '\n')
22244887Schin {
22254887Schin pp.state |= DISABLE;
22264887Schin while (pplex() != '\n');
22274887Schin }
22284887Schin donedirective:
22294887Schin #if _HUH_2002_05_09
22304887Schin if (!(pp.state & EOF2NL))
22314887Schin error(2, "%s in directive", pptokchr(0));
22324887Schin #endif
22334887Schin pp.state &= ~RESTORE;
22344887Schin pp.mode &= ~RELAX;
22354887Schin if (!(*pp.control & SKIP))
22364887Schin {
22374887Schin pp.state |= restore;
22384887Schin switch (directive)
22394887Schin {
22404887Schin case LINE:
22414887Schin return 0;
22424887Schin case INCLUDE:
22434887Schin if (pp.include)
22444887Schin {
22454887Schin error_info.line++;
22464887Schin PUSH_FILE(pp.include, n);
22474887Schin if (!pp.vendor && (pp.found->type & TYPE_VENDOR))
22484887Schin pp.vendor = 1;
22494887Schin pp.include = 0;
22504887Schin return 0;
22514887Schin }
22524887Schin if (pp.incref)
22534887Schin (*pp.incref)(error_info.file, ppgetfile(pp.path)->name, error_info.line, PP_SYNC_IGNORE);
22544887Schin else if (pp.linesync && pp.macref)
22554887Schin {
22564887Schin pp.flags |= PP_lineignore;
22574887Schin (*pp.linesync)(error_info.line, ppgetfile(pp.path)->name);
22584887Schin }
22594887Schin /*FALLTHROUGH*/
22604887Schin default:
22614887Schin pp.in->flags |= IN_tokens;
22624887Schin /*FALLTHROUGH*/
22634887Schin case ENDIF:
22644887Schin error_info.line++;
22654887Schin if (emitted)
22664887Schin {
22674887Schin ppputchar('\n');
22684887Schin ppcheckout();
22694887Schin }
22704887Schin else
22714887Schin {
22724887Schin pp.state |= HIDDEN;
22734887Schin pp.hidden++;
22744887Schin }
22754887Schin return 0;
22764887Schin }
22774887Schin }
22784887Schin pp.state |= restore|HIDDEN|SKIPCONTROL;
22794887Schin pp.hidden++;
22804887Schin pp.level++;
22814887Schin error_info.line++;
22824887Schin return 0;
22834887Schin }
22844887Schin
22854887Schin /*
22864887Schin * grow the pp nesting control stack
22874887Schin */
22884887Schin
22894887Schin void
ppnest(void)22904887Schin ppnest(void)
22914887Schin {
22924887Schin register struct ppinstk* ip;
22934887Schin int oz;
22944887Schin int nz;
22954887Schin long adjust;
22964887Schin long* op;
22974887Schin long* np;
22984887Schin
22994887Schin oz = pp.constack;
23004887Schin op = pp.maxcon - oz + 1;
23014887Schin nz = oz * 2;
23024887Schin np = newof(op, long, nz, 0);
23034887Schin if (adjust = (np - op))
23044887Schin {
23054887Schin ip = pp.in;
23064887Schin do
23074887Schin {
23084887Schin if (ip->control)
23094887Schin ip->control += adjust;
23104887Schin } while (ip = ip->prev);
23114887Schin }
23124887Schin pp.control = np + oz;
23134887Schin pp.constack = nz;
23144887Schin pp.maxcon = np + nz - 1;
23154887Schin }
2316