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 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 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* 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* 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 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 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 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