14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1986-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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; 4534887Schin switch (c = pplex()) 4544887Schin { 4554887Schin case T_STRING: 4564887Schin p = pp.token; 4574887Schin do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING); 4584887Schin *pp.token = 0; 4594887Schin pp.token = p; 4604887Schin /*FALLTHROUGH*/ 4614887Schin case T_HEADER: 4624887Schin header: 4634887Schin if (!*pp.token) 4644887Schin { 4654887Schin error(2, "#%s: null file name", dirname(INCLUDE)); 4664887Schin break; 4674887Schin } 4684887Schin if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX))) 4694887Schin error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token); 4704887Schin n = ppsearch(pp.token, c, SEARCH_INCLUDE); 4714887Schin break; 4724887Schin case '<': 4734887Schin /* 4744887Schin * HEADEREXPAND|HEADEREXPANDALL gets us here 4754887Schin */ 4764887Schin 4774887Schin if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0))) 4784887Schin error(3, "out of space"); 4794887Schin pp.state &= ~NOSPACE; 4804887Schin while ((c = pplex()) && c != '>') 4814887Schin { 4824887Schin v = p + 1; 4834887Schin STRCOPY(p, pp.token, s); 4844887Schin if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO) 4854887Schin p--; 4864887Schin } 4874887Schin pp.state |= NOSPACE; 4884887Schin *p++ = 0; 4894887Schin memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf); 4904887Schin c = T_HEADER; 4914887Schin goto header; 4924887Schin default: 4934887Schin error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE)); 4944887Schin goto eatdirective; 4954887Schin } 4964887Schin goto enddirective; 4974887Schin case 0: 4984887Schin { 4994887Schin regmatch_t match[10]; 5004887Schin 5014887Schin /*UNDENT*/ 5024887Schin p = pp.valbuf; 5034887Schin *p++ = '#'; 5044887Schin STRCOPY(p, pp.token, s); 5054887Schin p0 = p; 5064887Schin pp.mode |= EXPOSE; 5074887Schin pp.state |= HEADER; 5084887Schin p6 = getline(p, &pp.valbuf[MAXTOKEN], 0); 5094887Schin pp.state &= ~HEADER; 5104887Schin pp.mode &= ~EXPOSE; 5114887Schin if (!p6) 5124887Schin { 5134887Schin *p0 = 0; 5144887Schin error(2, "%s: directive too long", pp.valbuf); 5154887Schin c = 0; 5164887Schin goto eatdirective; 5174887Schin } 5184887Schin p1 = p2 = p3 = p4 = 0; 5194887Schin p5 = *p ? p + 1 : 0; 5204887Schin checkmap: 5214887Schin i0 = *p0; 5224887Schin p = pp.valbuf; 5234887Schin var.best = 0; 5244887Schin n = 0; 5254887Schin for (map = (struct map*)pp.maps; map; map = map->next) 5264887Schin if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0))) 5274887Schin { 5284887Schin if ((c = match[0].rm_eo - match[0].rm_so) > n) 5294887Schin { 5304887Schin n = c; 5314887Schin var.best = map; 5324887Schin } 5334887Schin } 5344887Schin else if (i1 != REG_NOMATCH) 5354887Schin regfatal(&map->re, 3, i1); 5364887Schin c = '\n'; 5374887Schin if (map = var.best) 5384887Schin { 5394887Schin if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX))) 5404887Schin { 5414887Schin *p0 = 0; 5424887Schin if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA))) 5434887Schin error(1, "%s: non-standard directive", p); 5444887Schin *p0 = i0; 5454887Schin } 5464887Schin if (!(*pp.control & SKIP)) 5474887Schin { 5484887Schin n = 0; 5494887Schin for (edit = map->edit; edit; edit = edit->next) 5504887Schin if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0))) 5514887Schin { 5524887Schin n++; 5534887Schin if (i0 = regsubexec(&edit->re, p, elementsof(match), match)) 5544887Schin regfatal(&edit->re, 3, i0); 5554887Schin p = edit->re.re_sub->re_buf; 5564887Schin if (edit->re.re_sub->re_flags & REG_SUB_STOP) 5574887Schin break; 5584887Schin } 5594887Schin else if (i0 != REG_NOMATCH) 5604887Schin regfatal(&edit->re, 3, i0); 5614887Schin if (n && *p) 5624887Schin { 5634887Schin p1 = s = oldof(0, char, 0, strlen(p) + 32); 5644887Schin while (*s = *p++) s++; 5654887Schin debug((-4, "map: %s", p1)); 5664887Schin *s++ = '\n'; 5674887Schin *s = 0; 5684887Schin error_info.line++; 5694887Schin PUSH_RESCAN(p1); 5704887Schin error_info.line--; 5714887Schin directive = LINE; 5724887Schin } 5734887Schin } 5744887Schin goto donedirective; 5754887Schin } 5764887Schin if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX)))) 5774887Schin { 5784887Schin *p0 = 0; 5794887Schin error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0)); 5804887Schin *p0 = i0; 5814887Schin } 5824887Schin pass: 5834887Schin if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT))) 5844887Schin { 5854887Schin *p0 = 0; 5864887Schin if (p2) *p2 = 0; 5874887Schin if (p4) 5884887Schin { 5894887Schin if (p4 == p5) 5904887Schin { 5914887Schin p5 = strcpy(pp.tmpbuf, p5); 5924887Schin if (p = strchr(p5, MARK)) 5934887Schin { 5944887Schin s = p; 5954887Schin while (*p) 5964887Schin if ((*s++ = *p++) == MARK && *p == MARK) p++; 5974887Schin *s = 0; 5984887Schin } 5994887Schin } 6004887Schin *p4 = 0; 6014887Schin } 6024887Schin if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1)) 6034887Schin { 6044887Schin s = p; 6054887Schin while (p < p6) switch (*s++ = *p++) 6064887Schin { 6074887Schin case 0: 6084887Schin s = p; 6094887Schin break; 6104887Schin case MARK: 6114887Schin p++; 6124887Schin break; 6134887Schin } 6144887Schin *s = 0; 6154887Schin } 6164887Schin (*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0); 6174887Schin emitted = 1; 6184887Schin } 6194887Schin goto donedirective; 6204887Schin 6214887Schin /*INDENT*/ 6224887Schin } 6234887Schin } 6244887Schin if (*pp.control & SKIP) goto eatdirective; 6254887Schin switch (directive) 6264887Schin { 6274887Schin #if MACDEF 6284887Schin case ENDMAC: 6294887Schin c = pplex(); 6304887Schin error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC)); 6314887Schin goto enddirective; 6324887Schin #endif 6334887Schin #if MACDEF 6344887Schin case MACDEF: 6354887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 6364887Schin error(1, "#%s: non-standard directive", pp.token); 6374887Schin /*FALLTHROUGH*/ 6384887Schin #endif 6394887Schin case DEFINE: 6404887Schin n2 = error_info.line; 6414887Schin if ((c = pplex()) == '#' && directive == DEFINE) 6424887Schin goto assertion; 6434887Schin if (c == '<') 6444887Schin { 6454887Schin n = 1; 6464887Schin c = pplex(); 6474887Schin } 6484887Schin else 6494887Schin n = 0; 6504887Schin if (!(sym = macsym(c))) 6514887Schin goto eatdirective; 6524887Schin if (pp.truncate) 6534887Schin ppfsm(FSM_MACRO, pp.token); 6544887Schin mac = sym->macro; 6554887Schin if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value) 6564887Schin goto eatdirective; 6574887Schin if (n) 6584887Schin goto tuple; 6594887Schin old = *mac; 6604887Schin i0 = sym->flags; 6614887Schin sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); 6624887Schin #if MACDEF 6634887Schin if (directive == MACDEF) 6644887Schin sym->flags |= SYM_MULTILINE; 6654887Schin #endif 6664887Schin mac->arity = 0; 6674887Schin mac->formals = 0; 6684887Schin mac->value = 0; 6694887Schin pp.state &= ~NOSPACE; 6704887Schin pp.state |= DEFINITION|NOEXPAND; 6714887Schin switch (c = pplex()) 6724887Schin { 6734887Schin case '(': 6744887Schin sym->flags |= SYM_FUNCTION; 6754887Schin pp.state |= NOSPACE; 6764887Schin #if MACKEYARGS 6774887Schin if (pp.option & KEYARGS) 6784887Schin { 6794887Schin n = 2 * MAXTOKEN; 6804887Schin p = mac->formals = oldof(0, char, 0, n); 6814887Schin if ((c = pplex()) == T_ID) for (;;) 6824887Schin { 6834887Schin if (mac->arity < MAXFORMALS) 6844887Schin { 6854887Schin if (mac->arity) p++; 6864887Schin formargs[mac->arity] = p; 6874887Schin STRAPP(p, pp.token, s); 6884887Schin formvals[mac->arity++] = p1 = p; 6894887Schin if (mac->arity == 1) *p++ = ' '; 6904887Schin *p++ = ' '; 6914887Schin *p = 0; 6924887Schin } 6934887Schin else error(2, "%s: formal argument %s ignored", sym->name, pp.token); 6944887Schin switch (c = pplex()) 6954887Schin { 6964887Schin case '=': 6974887Schin c = pplex(); 6984887Schin break; 6994887Schin case ',': 7004887Schin break; 7014887Schin default: 7024887Schin goto endformals; 7034887Schin } 7044887Schin pp.state &= ~NOSPACE; 7054887Schin p0 = 0; 7064887Schin for (;;) 7074887Schin { 7084887Schin switch (c) 7094887Schin { 7104887Schin case '\n': 7114887Schin goto endformals; 7124887Schin case '(': 7134887Schin p0++; 7144887Schin break; 7154887Schin case ')': 7164887Schin if (!p0--) 7174887Schin { 7184887Schin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0; 7194887Schin goto endformals; 7204887Schin } 7214887Schin break; 7224887Schin case ',': 7234887Schin if (!p0) 7244887Schin { 7254887Schin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0; 7264887Schin goto nextformal; 7274887Schin } 7284887Schin break; 7294887Schin case ' ': 7304887Schin if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue; 7314887Schin break; 7324887Schin } 7334887Schin STRCOPY(p, pp.token, s); 7344887Schin if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals) 7354887Schin { 7364887Schin n1 = s - mac->formals; 7374887Schin for (n = 0; n < mac->arity; n++) 7384887Schin { 7394887Schin formargs[n] += n1; 7404887Schin formvals[n] += n1; 7414887Schin } 7424887Schin c = p - mac->formals; 7434887Schin mac->formals = s; 7444887Schin p = mac->formals + c; 7454887Schin } 7464887Schin c = pplex(); 7474887Schin } 7484887Schin nextformal: 7494887Schin pp.state |= NOSPACE; 7504887Schin if ((c = pplex()) != T_ID) 7514887Schin { 7524887Schin c = ','; 7534887Schin break; 7544887Schin } 7554887Schin } 7564887Schin endformals: /*NOP*/; 7574887Schin } 7584887Schin else 7594887Schin #endif 7604887Schin { 7614887Schin p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1)); 7624887Schin c = pplex(); 7634887Schin #if COMPATIBLE 7644887Schin if ((pp.state & COMPATIBILITY) && c == ',') 7654887Schin { 7664887Schin if ((pp.state & WARN) && !(pp.mode & HOSTED)) 7674887Schin error(1, "%s: macro formal argument expected", sym->name); 7684887Schin while ((c = pplex()) == ','); 7694887Schin } 7704887Schin #endif 7714887Schin for (;;) 7724887Schin { 7734887Schin if (c == T_VARIADIC) 7744887Schin { 7754887Schin if (sym->flags & SYM_VARIADIC) 7764887Schin error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token); 7774887Schin sym->flags |= SYM_VARIADIC; 7784887Schin v = __va_args__; 7794887Schin } 7804887Schin else if (c == T_ID) 7814887Schin { 7824887Schin v = pp.token; 7834887Schin if (sym->flags & SYM_VARIADIC) 7844887Schin error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v); 7854887Schin else if (streq(v, __va_args__)) 7864887Schin error(2, "%s: %s: invalid macro formal argument", sym->name, v); 7874887Schin } 7884887Schin else 7894887Schin break; 7904887Schin if (mac->arity < MAXFORMALS) 7914887Schin { 7924887Schin for (n = 0; n < mac->arity; n++) 7934887Schin if (streq(formargs[n], v)) 7944887Schin error(2, "%s: %s: duplicate macro formal argument", sym->name, v); 7954887Schin formargs[mac->arity++] = p; 7964887Schin STRAPP(p, v, s); 7974887Schin } 7984887Schin else 7994887Schin error(2, "%s: %s: macro formal argument ignored", sym->name, v); 8004887Schin if ((c = pplex()) == ',') 8014887Schin { 8024887Schin c = pplex(); 8034887Schin #if COMPATIBLE 8044887Schin if ((pp.state & COMPATIBILITY) && c == ',') 8054887Schin { 8064887Schin if ((pp.state & WARN) && !(pp.mode & HOSTED)) 8074887Schin error(1, "%s: macro formal argument expected", sym->name); 8084887Schin while ((c = pplex()) == ','); 8094887Schin } 8104887Schin #endif 8114887Schin } 8124887Schin else if (c != T_VARIADIC) 8134887Schin break; 8144887Schin else 8154887Schin { 8164887Schin if (sym->flags & SYM_VARIADIC) 8174887Schin error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token); 8184887Schin sym->flags |= SYM_VARIADIC; 8194887Schin c = pplex(); 8204887Schin break; 8214887Schin } 8224887Schin } 8234887Schin if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals) 8244887Schin { 8254887Schin n1 = s - mac->formals; 8264887Schin for (n = 0; n < mac->arity; n++) 8274887Schin formargs[n] += n1; 8284887Schin mac->formals = s; 8294887Schin } 8304887Schin } 8314887Schin if (!mac->arity) 8324887Schin { 8334887Schin free(mac->formals); 8344887Schin mac->formals = 0; 8354887Schin } 8364887Schin switch (c) 8374887Schin { 8384887Schin case ')': 8394887Schin #if MACKEYARGS 8404887Schin pp.state |= NOEXPAND|NOSPACE; 8414887Schin #else 8424887Schin pp.state |= NOEXPAND; 8434887Schin #endif 8444887Schin c = pplex(); 8454887Schin break; 8464887Schin default: 8474887Schin error(2, "%s: invalid macro formal argument list", sym->name); 8484887Schin if (mac->formals) 8494887Schin { 8504887Schin free(mac->formals); 8514887Schin mac->formals = 0; 8524887Schin mac->arity = 0; 8534887Schin } 8544887Schin free(mac); 8554887Schin sym->macro = 0; 8564887Schin goto eatdirective; 8574887Schin } 8584887Schin pp.state &= ~NOSPACE; 8594887Schin break; 8604887Schin case ' ': 8614887Schin case '\t': 8624887Schin c = pplex(); 8634887Schin break; 8644887Schin } 8654887Schin n = 2 * MAXTOKEN; 8664887Schin #if MACKEYARGS 8674887Schin p1 = p; 8684887Schin #endif 8694887Schin p = mac->value = oldof(0, char, 0, n); 8704887Schin var.type = 0; 8714887Schin n1 = 0; 8724887Schin #if MACDEF 8734887Schin i2 = i3 = 0; 8744887Schin n3 = pp.state; 8754887Schin #endif 8764887Schin if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY) 8774887Schin switch (c) 8784887Schin { 8794887Schin case '+': 8804887Schin case '-': 8814887Schin case '&': 8824887Schin case '|': 8834887Schin case '<': 8844887Schin case '>': 8854887Schin case ':': 8864887Schin case '=': 8874887Schin *p++ = ' '; 8884887Schin break; 8894887Schin } 8904887Schin o = 0; 8914887Schin for (;;) 8924887Schin { 8934887Schin switch (c) 8944887Schin { 8954887Schin case T_ID: 8964887Schin for (c = 0; c < mac->arity; c++) 8974887Schin if (streq(formargs[c], pp.token)) 8984887Schin { 8994887Schin #if COMPATIBLE 9004887Schin if (!(pp.state & COMPATIBILITY)) 9014887Schin #endif 9024887Schin if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' '; 9034887Schin *p++ = MARK; 9044887Schin #if COMPATIBLE 9054887Schin if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C'; 9064887Schin else 9074887Schin #endif 9084887Schin *p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A'; 9094887Schin *p++ = c + ARGOFFSET; 910*8462SApril.Chin@Sun.COM if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX)) && var.type != TOK_TOKCAT && !(var.type & TOK_ID)) 911*8462SApril.Chin@Sun.COM { 912*8462SApril.Chin@Sun.COM s = pp.in->nextchr; 913*8462SApril.Chin@Sun.COM while ((c = *s++) && (c == ' ' || c == '\t')); 914*8462SApril.Chin@Sun.COM if (c == '\n') 915*8462SApril.Chin@Sun.COM c = 0; 916*8462SApril.Chin@Sun.COM else if (c == '*' && *s == ')') 917*8462SApril.Chin@Sun.COM c = ')'; 918*8462SApril.Chin@Sun.COM else if (c == '=' || ppisidig(c) || c == *s || *s == '=') 919*8462SApril.Chin@Sun.COM c = 0; 920*8462SApril.Chin@Sun.COM if (o != '.' && o != T_PTRMEM) 921*8462SApril.Chin@Sun.COM { 922*8462SApril.Chin@Sun.COM if ((var.type & TOK_ID) || o == ' ' || ppisseparate(o)) 923*8462SApril.Chin@Sun.COM o = 0; 924*8462SApril.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 == ')')) 925*8462SApril.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); 926*8462SApril.Chin@Sun.COM } 927*8462SApril.Chin@Sun.COM } 9284887Schin var.type = TOK_FORMAL|TOK_ID; 9294887Schin c = '>'; 9304887Schin goto checkvalue; 9314887Schin } 9324887Schin if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token)) 9334887Schin { 9344887Schin case V_DEFAULT: 9354887Schin case V_EMPTY: 9364887Schin sym->flags |= SYM_EMPTY; 9374887Schin break; 9384887Schin } 9394887Schin else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden) 9404887Schin { 9414887Schin for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev); 9424887Schin p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token); 9434887Schin var.type = TOK_ID; 9444887Schin goto checkvalue; 9454887Schin } 9464887Schin var.type = TOK_ID; 9474887Schin break; 9484887Schin case '#': 9494887Schin var.type = 0; 9504887Schin #if MACDEF 9514887Schin if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break; 9524887Schin #else 9534887Schin if (!(sym->flags & SYM_FUNCTION)) break; 9544887Schin #endif 9554887Schin pp.state |= NOSPACE; 9564887Schin c = pplex(); 9574887Schin if (c == '@') 9584887Schin { 9594887Schin c = pplex(); 9604887Schin i4 = 'S'; 9614887Schin } 9624887Schin else i4 = 'Q'; 9634887Schin pp.state &= ~NOSPACE; 9644887Schin if (c != T_ID) c = mac->arity; 9654887Schin else for (c = 0; c < mac->arity; c++) 9664887Schin if (streq(formargs[c], pp.token)) 9674887Schin break; 9684887Schin if (c >= mac->arity) 9694887Schin { 9704887Schin #if MACDEF 9714887Schin if (sym->flags & SYM_MULTILINE) 9724887Schin { 9734887Schin if (n3 & NEWLINE) 9744887Schin { 9754887Schin pp.state &= ~NOEXPAND; 9764887Schin switch ((int)hashref(pp.dirtab, pp.token)) 9774887Schin { 9784887Schin case ENDMAC: 9794887Schin if (!i2--) goto gotdefinition; 9804887Schin break; 9814887Schin case INCLUDE: 9824887Schin /* PARSE HEADER constant */ 9834887Schin break; 9844887Schin case MACDEF: 9854887Schin i2++; 9864887Schin break; 9874887Schin } 9884887Schin *p++ = '#'; 9894887Schin } 9904887Schin } 9914887Schin else 9924887Schin #endif 9934887Schin #if COMPATIBLE 9944887Schin if (pp.state & COMPATIBILITY) *p++ = '#'; 9954887Schin else 9964887Schin #endif 9974887Schin error(2, "# must precede a formal parameter"); 9984887Schin } 9994887Schin else 10004887Schin { 10014887Schin if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' '; 10024887Schin *p++ = MARK; 10034887Schin *p++ = i4; 10044887Schin *p++ = c + ARGOFFSET; 10054887Schin goto checkvalue; 10064887Schin } 10074887Schin break; 10084887Schin case T_TOKCAT: 10094887Schin if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token); 10104887Schin else 10114887Schin { 10124887Schin if (*(p - 1) == ' ') p--; 10134887Schin if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C'; 10144887Schin } 10154887Schin pp.state |= NOSPACE; 10164887Schin c = pplex(); 10174887Schin pp.state &= ~NOSPACE; 10184887Schin if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT)); 10194887Schin var.type = TOK_TOKCAT; 10204887Schin continue; 10214887Schin case '(': 10224887Schin if (*pp.token == '#') 10234887Schin { 10244887Schin var.type = TOK_BUILTIN; 10254887Schin n1++; 10264887Schin } 10274887Schin else 10284887Schin { 10294887Schin var.type = 0; 10304887Schin if (n1) n1++; 10314887Schin } 10324887Schin break; 10334887Schin case ')': 10344887Schin var.type = 0; 10354887Schin if (n1) n1--; 10364887Schin break; 10374887Schin case T_STRING: 10384887Schin case T_CHARCONST: 10394887Schin pp.state &= ~NOEXPAND; 10404887Schin var.type = 0; 10414887Schin if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND; 10424887Schin #if COMPATIBLE 10434887Schin /*UNDENT*/ 10444887Schin 10454887Schin if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION))) 10464887Schin { 10474887Schin char* v; 10484887Schin 10494887Schin s = pp.token; 10504887Schin for (;;) 10514887Schin { 10524887Schin if (!*s) goto checkvalue; 10534887Schin if (ppisid(*s)) 10544887Schin { 10554887Schin v = s; 10564887Schin while (ppisid(*++s)); 10574887Schin i1 = *s; 10584887Schin *s = 0; 10594887Schin for (c = 0; c < mac->arity; c++) 10604887Schin if (streq(formargs[c], v)) 10614887Schin { 10624887Schin *p++ = MARK; 10634887Schin *p++ = 'C'; 10644887Schin *p++ = c + ARGOFFSET; 10654887Schin if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token) 10664887Schin { 10674887Schin case '"': 10684887Schin error(1, "use the # operator to \"...\" quote macro arguments"); 10694887Schin break; 10704887Schin case '\'': 10714887Schin error(1, "macro arguments should be '...' quoted before substitution"); 10724887Schin break; 10734887Schin } 10744887Schin goto quotearg; 10754887Schin } 10764887Schin STRCOPY2(p, v); 10774887Schin quotearg: 10784887Schin *s = i1; 10794887Schin } 10804887Schin else *p++ = *s++; 10814887Schin } 10824887Schin } 10834887Schin /*INDENT*/ 10844887Schin #endif 10854887Schin break; 10864887Schin case '\n': 10874887Schin #if MACDEF 10884887Schin if (sym->flags & SYM_MULTILINE) 10894887Schin { 10904887Schin if (pp.state & EOF2NL) 10914887Schin { 10924887Schin error_info.line++; 10934887Schin pp.state |= HIDDEN; 10944887Schin pp.hidden++; 10954887Schin var.type = 0; 10964887Schin if (!i3++) 10974887Schin goto checkvalue; 10984887Schin break; 10994887Schin } 11004887Schin pp.state |= EOF2NL; 11014887Schin error(2, "%s: missing #%s", sym->name, dirname(ENDMAC)); 11024887Schin } 11034887Schin #endif 11044887Schin goto gotdefinition; 11054887Schin case 0: 11064887Schin c = '\n'; 11074887Schin goto gotdefinition; 11084887Schin #if COMPATIBLE 11094887Schin case ' ': 11104887Schin if (pp.state & COMPATIBILITY) var.type = 0; 11114887Schin if (pp.option & PRESERVE) break; 11124887Schin if (p > mac->value && *(p - 1) != ' ') *p++ = ' '; 11134887Schin goto checkvalue; 11144887Schin case '\t': 11154887Schin if (var.type & TOK_ID) 11164887Schin { 11174887Schin while ((c = pplex()) == '\t'); 11184887Schin if (c == T_ID) 11194887Schin { 11204887Schin if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C'; 11214887Schin var.type = TOK_TOKCAT; 11224887Schin if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments"); 11234887Schin } 11244887Schin else var.type = 0; 11254887Schin continue; 11264887Schin } 11274887Schin var.type = 0; 11284887Schin if (pp.option & PRESERVE) break; 11294887Schin if (p > mac->value && *(p - 1) != ' ') *p++ = ' '; 11304887Schin goto checkvalue; 11314887Schin #endif 11324887Schin case MARK: 11334887Schin pp.state &= ~NOEXPAND; 11344887Schin /*FALLTHROUGH*/ 11354887Schin 11364887Schin default: 11374887Schin var.type = 0; 11384887Schin break; 11394887Schin } 11404887Schin STRCOPY(p, pp.token, s); 11414887Schin checkvalue: 11424887Schin o = c; 11434887Schin if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value) 11444887Schin { 11454887Schin c = p - mac->value; 11464887Schin mac->value = s; 11474887Schin p = mac->value + c; 11484887Schin } 11494887Schin #if MACDEF 11504887Schin n3 = pp.state; 11514887Schin #endif 11524887Schin c = pplex(); 11534887Schin } 11544887Schin gotdefinition: 11554887Schin while (p > mac->value && *(p - 1) == ' ') p--; 11564887Schin if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY) 11574887Schin switch (o) 11584887Schin { 11594887Schin case '+': 11604887Schin case '-': 11614887Schin case '&': 11624887Schin case '|': 11634887Schin case '<': 11644887Schin case '>': 11654887Schin case ':': 11664887Schin case '=': 11674887Schin *p++ = ' '; 11684887Schin break; 11694887Schin } 11704887Schin *p = 0; 11714887Schin #if MACKEYARGS 11724887Schin if (!mac->arity) /* ok */; 11734887Schin else if (pp.option & KEYARGS) 11744887Schin { 11754887Schin p0 = mac->formals; 11764887Schin mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1); 11774887Schin s = (char*)&mac->formkeys[mac->arity]; 11784887Schin (void)memcpy(s, p0, p1 - p0 + 1); 11794887Schin free(p0); 11804887Schin for (n = 0; n < mac->arity; n++) 11814887Schin { 11824887Schin mac->formkeys[n].name = s + (formargs[n] - p0); 11834887Schin mac->formkeys[n].value = s + (formvals[n] - p0); 11844887Schin } 11854887Schin } 11864887Schin else 11874887Schin #endif 11884887Schin for (n = 1; n < mac->arity; n++) 11894887Schin *(formargs[n] - 1) = ','; 11904887Schin if (old.value) 11914887Schin { 11924887Schin if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined; 11934887Schin if (!old.formals) 11944887Schin { 11954887Schin if (mac->formals) goto redefined; 11964887Schin } 11974887Schin else if (mac->formals) 11984887Schin { 11994887Schin #if MACKEYARGS 12004887Schin if (pp.option & KEYARGS) 12014887Schin { 12024887Schin for (n = 0; n < mac->arity; n++) 12034887Schin if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value)) 12044887Schin goto redefined; 12054887Schin } 12064887Schin else 12074887Schin #endif 12084887Schin if (!streq(mac->formals, old.formals)) goto redefined; 12094887Schin } 12104887Schin #if MACKEYARGS 12114887Schin if (pp.option & KEYARGS) 12124887Schin { 12134887Schin if (mac->formkeys) free(mac->formkeys); 12144887Schin mac->formkeys = old.formkeys; 12154887Schin } 12164887Schin else 12174887Schin #endif 12184887Schin { 12194887Schin if (mac->formals) free(mac->formals); 12204887Schin mac->formals = old.formals; 12214887Schin } 12224887Schin free(mac->value); 12234887Schin mac->value = old.value; 12244887Schin goto benign; 12254887Schin redefined: 12264887Schin if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL)) 12274887Schin error(1, "%s redefined", sym->name); 12284887Schin #if MACKEYARGS 12294887Schin if ((pp.option & KEYARGS) && mac->formkeys) 12304887Schin free(mac->formkeys); 12314887Schin #endif 12324887Schin #if MACKEYARGS 12334887Schin if (!(pp.option & KEYARGS)) 12344887Schin #endif 12354887Schin if (old.formals) free(old.formals); 12364887Schin free(old.value); 12374887Schin } 12384887Schin else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name); 12394887Schin mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0); 12404887Schin 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))) 12414887Schin { 12424887Schin ppsync(); 12434887Schin ppprintf("#%s %s", dirname(DEFINE), sym->name); 12444887Schin if (sym->flags & SYM_FUNCTION) 12454887Schin { 12464887Schin ppputchar('('); 12474887Schin if (mac->formals) 12484887Schin ppprintf("%s", mac->formals); 12494887Schin ppputchar(')'); 12504887Schin } 12514887Schin if ((p = mac->value) && *p) 12524887Schin { 12534887Schin ppputchar(' '); 12544887Schin i0 = 0; 12554887Schin while (n = *p++) 12564887Schin { 12574887Schin if (n != MARK || (n = *p++) == MARK) 12584887Schin { 12594887Schin ppputchar(n); 12604887Schin i0 = ppisid(n); 12614887Schin } 12624887Schin else 12634887Schin { 12644887Schin if (n == 'Q') 12654887Schin ppputchar('#'); 12664887Schin else if (i0) 12674887Schin { 12684887Schin ppputchar('#'); 12694887Schin ppputchar('#'); 12704887Schin } 12714887Schin s = formargs[*p++ - ARGOFFSET]; 12724887Schin while ((n = *s++) && n != ',') 12734887Schin ppputchar(n); 12744887Schin if (ppisid(*p) || *p == MARK) 12754887Schin { 12764887Schin ppputchar('#'); 12774887Schin ppputchar('#'); 12784887Schin } 12794887Schin i0 = 0; 12804887Schin } 12814887Schin ppcheckout(); 12824887Schin } 12834887Schin } 12844887Schin emitted = 1; 12854887Schin } 12864887Schin benign: 12874887Schin if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN; 12884887Schin if (pp.option & FINAL) sym->flags |= SYM_FINAL; 12894887Schin if (pp.mode & INIT) sym->flags |= SYM_INIT; 12904887Schin if (pp.option & INITIAL) sym->flags |= SYM_INITIAL; 12914887Schin if (pp.state & NOEXPAND) sym->flags |= SYM_NOEXPAND; 12924887Schin if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED; 12934887Schin if (pp.mode & READONLY) sym->flags |= SYM_READONLY; 12944887Schin 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); 12954887Schin break; 12964887Schin assertion: 12974887Schin c = pplex(); 12984887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 12994887Schin error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0)); 13004887Schin if (c != T_ID) 13014887Schin { 13024887Schin error(2, "%s: invalid predicate name", pptokstr(pp.token, 0)); 13034887Schin goto eatdirective; 13044887Schin } 13054887Schin switch ((int)hashref(pp.strtab, pp.token)) 13064887Schin { 13074887Schin case X_DEFINED: 13084887Schin case X_EXISTS: 13094887Schin case X_STRCMP: 13104887Schin error(2, "%s is a builtin predicate", pp.token); 13114887Schin goto eatdirective; 13124887Schin case X_SIZEOF: 13134887Schin error(2, "%s cannot be a predicate", pp.token); 13144887Schin goto eatdirective; 13154887Schin } 13164887Schin strcpy(pp.tmpbuf, pp.token); 13174887Schin switch (pppredargs()) 13184887Schin { 13194887Schin case T_ID: 13204887Schin case T_STRING: 13214887Schin assert(directive, pp.tmpbuf, pp.args); 13224887Schin break; 13234887Schin case 0: 13244887Schin assert(directive, pp.tmpbuf, NiL); 13254887Schin break; 13264887Schin default: 13274887Schin error(2, "invalid predicate argument list"); 13284887Schin goto eatdirective; 13294887Schin } 13304887Schin break; 13314887Schin tuple: 13324887Schin pp.state |= DEFINITION|NOEXPAND|NOSPACE; 13334887Schin rp = 0; 13344887Schin tp = mac->tuple; 13354887Schin if (!tp && !mac->value) 13364887Schin ppfsm(FSM_MACRO, sym->name); 13374887Schin while ((c = pplex()) && c != '>' && c != '\n') 13384887Schin { 13394887Schin for (; tp; tp = tp->nomatch) 13404887Schin if (streq(tp->token, pp.token)) 13414887Schin break; 13424887Schin if (!tp) 13434887Schin { 13444887Schin if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token)))) 13454887Schin error(3, "out of space"); 13464887Schin strcpy(tp->token, pp.token); 13474887Schin if (rp) 13484887Schin { 13494887Schin tp->nomatch = rp; 13504887Schin rp->nomatch = tp; 13514887Schin } 13524887Schin else 13534887Schin { 13544887Schin tp->nomatch = mac->tuple; 13554887Schin mac->tuple = tp; 13564887Schin } 13574887Schin } 13584887Schin rp = tp; 13594887Schin tp = tp->match; 13604887Schin } 13614887Schin pp.state &= ~NOSPACE; 13624887Schin if (!rp || c != '>') 13634887Schin error(2, "%s: > omitted in tuple macro definition", sym->name); 13644887Schin else 13654887Schin { 13664887Schin n = 2 * MAXTOKEN; 13674887Schin p = v = oldof(0, char, 0, n); 13684887Schin while ((c = pplex()) && c != '\n') 13694887Schin if (p > v || c != ' ') 13704887Schin { 13714887Schin STRCOPY(p, pp.token, s); 13724887Schin if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v) 13734887Schin { 13744887Schin c = p - v; 13754887Schin v = s; 13764887Schin p = v + c; 13774887Schin } 13784887Schin } 13794887Schin while (p > v && *(p - 1) == ' ') 13804887Schin p--; 13814887Schin n = p - v; 13824887Schin tp = newof(0, struct pptuple, 1, n); 13834887Schin strcpy(tp->token, v); 13844887Schin tp->match = rp->match; 13854887Schin rp->match = tp; 13864887Schin } 13874887Schin goto benign; 13884887Schin case WARNING: 13894887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 13904887Schin error(1, "#%s: non-standard directive", pp.token); 13914887Schin /*FALLTHROUGH*/ 13924887Schin case ERROR: 13934887Schin pp.state &= ~DISABLE; 13944887Schin p = pp.tmpbuf; 13954887Schin while ((c = pplex()) != '\n') 13964887Schin if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN]) 13974887Schin { 13984887Schin STRCOPY(p, pp.token, s); 13994887Schin pp.state &= ~NOSPACE; 14004887Schin } 14014887Schin *p = 0; 14024887Schin p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error"); 14034887Schin n = (directive == WARNING) ? 1 : 3; 14044887Schin error(n, "%s", p); 14054887Schin break; 14064887Schin case LET: 14074887Schin n2 = error_info.line; 14084887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 14094887Schin error(1, "#%s: non-standard directive", pp.token); 14104887Schin if (!(sym = macsym(c = pplex()))) goto eatdirective; 14114887Schin if ((c = pplex()) != '=') 14124887Schin { 14134887Schin error(2, "%s: = expected", sym->name); 14144887Schin goto eatdirective; 14154887Schin } 14164887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC); 14174887Schin mac = sym->macro; 14184887Schin mac->arity = 0; 14194887Schin if (mac->value) 14204887Schin { 14214887Schin if (!(sym->flags & SYM_REDEFINE) && !sym->hidden) 14224887Schin error(1, "%s: redefined", sym->name); 14234887Schin #if MACKEYARGS 14244887Schin if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys); 14254887Schin else 14264887Schin #endif 14274887Schin free(mac->formals); 14284887Schin mac->formals = 0; 14294887Schin n = strlen(mac->value) + 1; 14304887Schin } 14314887Schin else 14324887Schin { 14334887Schin ppfsm(FSM_MACRO, sym->name); 14344887Schin n = 0; 14354887Schin } 14364887Schin n1 = ppexpr(&i1); 14374887Schin if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1); 14384887Schin else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1); 14394887Schin if (n < ++c) 14404887Schin { 14414887Schin if (mac->value) free(mac->value); 14424887Schin mac->value = oldof(0, char, 0, c); 14434887Schin } 14444887Schin strcpy(mac->value, pp.tmpbuf); 14454887Schin sym->flags |= SYM_REDEFINE; 14464887Schin c = (pp.state & NEWLINE) ? '\n' : ' '; 14474887Schin goto benign; 14484887Schin case LINE: 14494887Schin pp.state &= ~DISABLE; 14504887Schin if ((c = pplex()) == '#') 14514887Schin { 14524887Schin c = pplex(); 14534887Schin directive = INCLUDE; 14544887Schin } 14554887Schin if (c != T_DECIMAL && c != T_OCTAL) 14564887Schin { 14574887Schin error(1, "#%s: line number expected", dirname(LINE)); 14584887Schin goto eatdirective; 14594887Schin } 14604887Schin linesync: 14614887Schin n = error_info.line; 14624887Schin error_info.line = strtol(pp.token, NiL, 0); 14634887Schin if (error_info.line == 0 && directive == LINE && (pp.state & STRICT) && !(pp.mode & HOSTED)) 14644887Schin error(1, "#%s: line number should be > 0", dirname(LINE)); 14654887Schin pp.state &= ~DISABLE; 14664887Schin pp.state |= STRIP; 14674887Schin switch (c = pplex()) 14684887Schin { 14694887Schin case T_STRING: 14704887Schin s = error_info.file; 14714887Schin if (*(p = pp.token)) pathcanon(p, 0); 14724887Schin fp = ppsetfile(p); 14734887Schin error_info.file = fp->name; 14744887Schin if (error_info.line == 1) 14754887Schin ppmultiple(fp, INC_TEST); 14764887Schin switch (c = pplex()) 14774887Schin { 14784887Schin case '\n': 14794887Schin break; 14804887Schin case T_DECIMAL: 14814887Schin case T_OCTAL: 14824887Schin if (directive == LINE && (pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 14834887Schin error(1, "#%s: integer file type argument is non-standard", dirname(LINE)); 14844887Schin break; 14854887Schin default: 14864887Schin error(1, "#%s: integer file type argument expected", dirname(LINE)); 14874887Schin break; 14884887Schin } 14894887Schin if (directive == LINE) pp.in->flags &= ~IN_ignoreline; 14904887Schin else if (pp.incref) 14914887Schin { 14924887Schin if (error_info.file != s) 14934887Schin { 14944887Schin switch (*pp.token) 14954887Schin { 14964887Schin case PP_sync_push: 14974887Schin if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); 14984887Schin else (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH); 14994887Schin break; 15004887Schin case PP_sync_pop: 15014887Schin if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); 15024887Schin else (*pp.incref)(s, error_info.file, n - 1, PP_SYNC_POP); 15034887Schin break; 15044887Schin case PP_sync_ignore: 15054887Schin if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); 15064887Schin else 15074887Schin { 15084887Schin (*pp.incref)(s, error_info.file, n, PP_SYNC_IGNORE); 15094887Schin error_info.file = s; 15104887Schin } 15114887Schin break; 15124887Schin default: 15134887Schin if (*s) 15144887Schin { 15154887Schin if (fp == pp.insert) 15164887Schin pp.insert = 0; 15174887Schin else if (error_info.line == 1 && !pp.insert) 15184887Schin (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH); 15194887Schin else 15204887Schin { 15214887Schin if (!pp.insert) pp.insert = ppgetfile(s); 15224887Schin (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT); 15234887Schin } 15244887Schin } 15254887Schin break; 15264887Schin } 15274887Schin } 15284887Schin } 15294887Schin break; 15304887Schin case '\n': 15314887Schin break; 15324887Schin default: 15334887Schin error(1, "#%s: \"file-name\" expected", dirname(LINE)); 15344887Schin break; 15354887Schin } 15364887Schin if (directive == LINE && (pp.in->flags & IN_ignoreline)) 15374887Schin error_info.line = n + 1; 15384887Schin else 15394887Schin { 15404887Schin pp.hidden = 0; 15414887Schin pp.state &= ~HIDDEN; 15424887Schin if (pp.linesync) 15434887Schin { 15444887Schin #if CATSTRINGS 15454887Schin if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE; 15464887Schin else 15474887Schin #endif 15484887Schin { 15494887Schin s = pp.lineid; 15504887Schin n = pp.flags; 15514887Schin if (directive == LINE) 15524887Schin { 15534887Schin pp.flags &= ~PP_linetype; 15544887Schin if (pp.macref) pp.lineid = dirname(LINE); 15554887Schin } 15564887Schin (*pp.linesync)(error_info.line, error_info.file); 15574887Schin pp.flags = n; 15584887Schin pp.lineid = s; 15594887Schin } 15604887Schin } 15614887Schin } 15624887Schin directive = LINE; 15634887Schin break; 15644887Schin case PRAGMA: 15654887Schin /* 15664887Schin * #pragma [STDC] [pass:] [no]option [arg ...] 15674887Schin * 15684887Schin * pragma args are not expanded by default 15694887Schin * 15704887Schin * if STDC is present then it is silently passed on 15714887Schin * 15724887Schin * if pass is pp.pass then the option is used 15734887Schin * and verified but is not passed on 15744887Schin * 15754887Schin * if pass is omitted then the option is passed on 15764887Schin * 15774887Schin * otherwise if pass is non-null and not pp.pass then 15784887Schin * the option is passed on but not used 15794887Schin * 15804887Schin * if the line does not match this form then 15814887Schin * it is passed on unchanged 15824887Schin * 15834887Schin * #directive pass: option [...] 15844887Schin * ^ ^ ^ ^ ^ ^ ^ ^ 15854887Schin * pp.valbuf p0 p1 p2 p3 p4 p5 p6 15864887Schin * 15874887Schin * p? 0 if component omitted 15884887Schin * i0 0 if ``no''option 15894887Schin */ 15904887Schin 15914887Schin p = pp.valbuf; 15924887Schin *p++ = '#'; 15934887Schin STRCOPY(p, pp.token, s); 15944887Schin p0 = p; 15954887Schin if (pp.option & PRAGMAEXPAND) 15964887Schin pp.state &= ~DISABLE; 15974887Schin if (!(p6 = getline(p, &pp.valbuf[MAXTOKEN], !!(pp.option & PRAGMAEXPAND)))) 15984887Schin { 15994887Schin *p0 = 0; 16004887Schin error(2, "%s: directive too long", pp.valbuf); 16014887Schin c = 0; 16024887Schin goto eatdirective; 16034887Schin } 16044887Schin p1 = ++p; 16054887Schin while (ppisid(*p)) 16064887Schin p++; 16074887Schin if (p == p1) 16084887Schin { 16094887Schin p5 = p; 16104887Schin p4 = 0; 16114887Schin p3 = 0; 16124887Schin p2 = 0; 16134887Schin p1 = 0; 16144887Schin } 16154887Schin else if (*p != ':') 16164887Schin { 16174887Schin p5 = *p ? p + (*p == ' ') : 0; 16184887Schin p4 = p; 16194887Schin p3 = p1; 16204887Schin p2 = 0; 16214887Schin p1 = 0; 16224887Schin } 16234887Schin else 16244887Schin { 16254887Schin p2 = p++; 16264887Schin p3 = p; 16274887Schin while (ppisid(*p)) 16284887Schin p++; 16294887Schin if (p == p3) 16304887Schin { 16314887Schin p4 = p1; 16324887Schin p3 = 0; 16334887Schin p2 = 0; 16344887Schin p1 = 0; 16354887Schin } 16364887Schin else 16374887Schin p4 = p; 16384887Schin p5 = *p4 ? p4 + (*p4 == ' ') : 0; 16394887Schin } 16404887Schin if (!p1 && p3 && (p4 - p3) == 4 && strneq(p3, "STDC", 4)) 16414887Schin goto pass; 1642*8462SApril.Chin@Sun.COM if ((pp.state & WARN) && (pp.mode & (HOSTED|RELAX|PEDANTIC)) == PEDANTIC) 16434887Schin error(1, "#%s: non-standard directive", dirname(PRAGMA)); 16444887Schin i0 = !p3 || *p3 != 'n' || *(p3 + 1) != 'o'; 16454887Schin if (!p3) 16464887Schin goto checkmap; 16474887Schin if (p1) 16484887Schin { 16494887Schin *p2 = 0; 16504887Schin n = streq(p1, pp.pass); 16514887Schin *p2 = ':'; 16524887Schin if (!n) 16534887Schin goto checkmap; 16544887Schin } 16554887Schin else 16564887Schin n = 0; 16574887Schin i2 = *p4; 16584887Schin *p4 = 0; 16594887Schin 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)) 16604887Schin i1 = 0; 16614887Schin if ((pp.state & (COMPATIBILITY|STRICT)) == STRICT && !(pp.mode & (HOSTED|RELAX))) 16624887Schin { 16634887Schin if (pp.optflags[i1] & OPT_GLOBAL) 16644887Schin goto donedirective; 16654887Schin if (n || (pp.mode & WARN)) 16664887Schin { 16674887Schin n = 0; 16684887Schin error(1, "#%s: non-standard directive ignored", dirname(PRAGMA)); 16694887Schin } 16704887Schin i1 = 0; 16714887Schin } 16724887Schin if (!n) 16734887Schin { 16744887Schin if (!(pp.optflags[i1] & OPT_GLOBAL)) 16754887Schin { 16764887Schin *p4 = i2; 16774887Schin goto checkmap; 16784887Schin } 16794887Schin if (!(pp.optflags[i1] & OPT_PASS)) 16804887Schin n = 1; 16814887Schin } 16824887Schin else if (!i1) 16834887Schin error(2, "%s: unknown option", p1); 16844887Schin else if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 16854887Schin error(1, "%s: non-standard option", p1); 16864887Schin p = p5; 16874887Schin switch (i1) 16884887Schin { 16894887Schin case X_ALLMULTIPLE: 16904887Schin ppop(PP_MULTIPLE, i0); 16914887Schin break; 16924887Schin case X_ALLPOSSIBLE: 16934887Schin setoption(ALLPOSSIBLE, i0); 16944887Schin break; 16954887Schin case X_BUILTIN: 16964887Schin setmode(BUILTIN, i0); 16974887Schin break; 16984887Schin case X_CATLITERAL: 16994887Schin setmode(CATLITERAL, i0); 17004887Schin if (pp.mode & CATLITERAL) 17014887Schin setoption(STRINGSPLIT, 0); 17024887Schin break; 17034887Schin case X_CDIR: 17044887Schin tokop(PP_CDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); 17054887Schin break; 17064887Schin case X_CHECKPOINT: 17074887Schin #if CHECKPOINT 17084887Schin ppload(p); 17094887Schin #else 17104887Schin error(3, "%s: preprocessor not compiled with checkpoint enabled", p3); 17114887Schin #endif 17124887Schin break; 17134887Schin case X_CHOP: 17144887Schin tokop(PP_CHOP, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); 17154887Schin break; 17164887Schin case X_COMPATIBILITY: 17174887Schin ppop(PP_COMPATIBILITY, i0); 17184887Schin break; 17194887Schin case X_DEBUG: 17204887Schin error_info.trace = i0 ? (p ? -strtol(p, NiL, 0) : -1) : 0; 17214887Schin break; 17224887Schin case X_ELSEIF: 17234887Schin setoption(ELSEIF, i0); 17244887Schin break; 17254887Schin case X_EXTERNALIZE: 17264887Schin setmode(EXTERNALIZE, i0); 17274887Schin break; 17284887Schin case X_FINAL: 17294887Schin setoption(FINAL, i0); 17304887Schin break; 17314887Schin case X_HEADEREXPAND: 17324887Schin setoption(HEADEREXPAND, i0); 17334887Schin break; 17344887Schin case X_HEADEREXPANDALL: 17354887Schin setoption(HEADEREXPANDALL, i0); 17364887Schin break; 17374887Schin case X_HIDE: 17384887Schin case X_NOTE: 17394887Schin PUSH_LINE(p); 17404887Schin /* UNDENT...*/ 17414887Schin while (c = pplex()) 17424887Schin { 17434887Schin if (c != T_ID) error(1, "%s: %s: identifier expected", p3, pp.token); 17444887Schin else if (sym = ppsymset(pp.symtab, pp.token)) 17454887Schin { 17464887Schin if (i1 == X_NOTE) 17474887Schin { 17484887Schin sym->flags &= ~SYM_NOTICED; 17494887Schin ppfsm(FSM_MACRO, sym->name); 17504887Schin } 17514887Schin else if (i0) 17524887Schin { 17534887Schin if (!sym->hidden && !(sym->hidden = newof(0, struct pphide, 1, 0))) 17544887Schin error(3, "out of space"); 17554887Schin if (!sym->macro) 17564887Schin ppfsm(FSM_MACRO, sym->name); 17574887Schin if (!sym->hidden->level++) 17584887Schin { 17594887Schin pp.hiding++; 17604887Schin if (sym->macro && !(sym->flags & (SYM_ACTIVE|SYM_READONLY))) 17614887Schin { 17624887Schin sym->hidden->macro = sym->macro; 17634887Schin sym->macro = 0; 17644887Schin sym->hidden->flags = sym->flags; 17654887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); 17664887Schin } 17674887Schin } 17684887Schin } 17694887Schin else if (sym->hidden) 17704887Schin { 17714887Schin if ((mac = sym->macro) && !(sym->flags & (SYM_ACTIVE|SYM_READONLY))) 17724887Schin { 17734887Schin if (mac->formals) free(mac->formals); 17744887Schin free(mac->value); 17754887Schin free(mac); 17764887Schin sym->macro = 0; 17774887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); 17784887Schin } 17794887Schin if (!--sym->hidden->level) 17804887Schin { 17814887Schin pp.hiding--; 17824887Schin if (sym->hidden->macro) 17834887Schin { 17844887Schin sym->macro = sym->hidden->macro; 17854887Schin sym->flags = sym->hidden->flags; 17864887Schin } 17874887Schin free(sym->hidden); 17884887Schin sym->hidden = 0; 17894887Schin } 17904887Schin } 17914887Schin } 17924887Schin } 17934887Schin /*...INDENT*/ 17944887Schin POP_LINE(); 17954887Schin break; 17964887Schin case X_HOSTDIR: 17974887Schin tokop(PP_HOSTDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); 17984887Schin break; 17994887Schin case X_HOSTED: 18004887Schin setmode(HOSTED, i0); 18014887Schin break; 18024887Schin case X_HOSTEDTRANSITION: 18034887Schin setmode(HOSTEDTRANSITION, i0); 18044887Schin break; 18054887Schin case X_ID: 18064887Schin tokop(PP_ID, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); 18074887Schin break; 18084887Schin case X_IGNORE: 18094887Schin tokop(PP_IGNORE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); 18104887Schin break; 18114887Schin case X_INCLUDE: 18124887Schin tokop(PP_INCLUDE, p3, p, i0, TOKOP_STRING|TOKOP_DUP); 18134887Schin break; 18144887Schin case X_INITIAL: 18154887Schin setoption(INITIAL, i0); 18164887Schin break; 18174887Schin case X_KEYARGS: 18184887Schin ppop(PP_KEYARGS, i0); 18194887Schin break; 18204887Schin case X_LINE: 18214887Schin if (pp.linesync) pp.olinesync = pp.linesync; 18224887Schin pp.linesync = i0 ? pp.olinesync : (PPLINESYNC)0; 18234887Schin break; 18244887Schin case X_LINEBASE: 18254887Schin ppop(PP_LINEBASE, i0); 18264887Schin break; 18274887Schin case X_LINEFILE: 18284887Schin ppop(PP_LINEFILE, i0); 18294887Schin break; 18304887Schin case X_LINEID: 18314887Schin ppop(PP_LINEID, i0 ? p : (char*)0); 18324887Schin break; 18334887Schin case X_LINETYPE: 18344887Schin ppop(PP_LINETYPE, i0 ? (p ? strtol(p, NiL, 0) : 1) : 0); 18354887Schin break; 18364887Schin case X_MACREF: 18374887Schin if (!p) 18384887Schin { 18394887Schin if (i0 && !pp.macref) 18404887Schin { 18414887Schin ppop(PP_LINETYPE, 1); 18424887Schin ppop(PP_MACREF, ppmacref); 18434887Schin } 18444887Schin else error(2, "%s: option cannot be unset", p3); 18454887Schin } 18464887Schin else if (s = strchr(p, ' ')) 18474887Schin { 18484887Schin if (pp.macref && (s = strchr(p, ' '))) 18494887Schin { 18504887Schin *s++ = 0; 18514887Schin c = strtol(s, NiL, 0); 18524887Schin var.type = pp.truncate; 18534887Schin pp.truncate = PPTOKSIZ; 18544887Schin (*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); 18554887Schin pp.truncate = var.type; 18564887Schin } 18574887Schin error_info.line -= 2; 18584887Schin } 18594887Schin break; 18604887Schin case X_MAP: 18614887Schin /*UNDENT*/ 18624887Schin /* 18634887Schin * #pragma pp:map [id ...] "/from/[,/to/]" [ "/old/new/[glnu]" ... ] 18644887Schin */ 18654887Schin 18664887Schin if (!i0) 18674887Schin { 18684887Schin error(2, "%s: option cannot be unset", p3); 18694887Schin goto donedirective; 18704887Schin } 18714887Schin if (!p5) 18724887Schin { 18734887Schin error(2, "%s: address argument expected", p3); 18744887Schin goto donedirective; 18754887Schin } 18764887Schin PUSH_LINE(p5); 18774887Schin while ((c = pplex()) == T_ID) 18784887Schin { 18794887Schin sfsprintf(pp.tmpbuf, MAXTOKEN, "__%s__", s = pp.token); 18804887Schin if (c = (int)hashget(pp.dirtab, s)) 18814887Schin { 18824887Schin hashput(pp.dirtab, 0, 0); 18834887Schin hashput(pp.dirtab, pp.tmpbuf, c); 18844887Schin } 18854887Schin if (c = (int)hashget(pp.strtab, s)) 18864887Schin { 18874887Schin hashput(pp.strtab, 0, 0); 18884887Schin hashput(pp.strtab, pp.tmpbuf, c); 18894887Schin } 18904887Schin } 18914887Schin if (c != T_STRING || !*(s = pp.token)) 18924887Schin { 18934887Schin if (c) 18944887Schin error(2, "%s: %s: address argument expected", p3, pptokstr(pp.token, 0)); 18954887Schin goto eatmap; 18964887Schin } 18974887Schin map = newof(0, struct map, 1, 0); 18984887Schin 18994887Schin /* 19004887Schin * /from/ 19014887Schin */ 19024887Schin 19034887Schin if (i0 = regcomp(&map->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL)) 19044887Schin regfatal(&map->re, 3, i0); 19054887Schin if (*(s += map->re.re_npat)) 19064887Schin { 19074887Schin error(2, "%s: invalid characters after pattern: %s ", p3, s); 19084887Schin goto eatmap; 19094887Schin } 19104887Schin 19114887Schin /* 19124887Schin * /old/new/[flags] 19134887Schin */ 19144887Schin 19154887Schin edit = 0; 19164887Schin while ((c = pplex()) == T_STRING) 19174887Schin { 19184887Schin if (!*(s = pp.token)) 19194887Schin { 19204887Schin error(2, "%s: substitution argument expected", p3); 19214887Schin goto eatmap; 19224887Schin } 19234887Schin if (edit) 19244887Schin edit = edit->next = newof(0, struct edit, 1, 0); 19254887Schin else 19264887Schin edit = map->edit = newof(0, struct edit, 1, 0); 19274887Schin 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))) 19284887Schin s += edit->re.re_npat; 19294887Schin if (i0) 19304887Schin regfatal(&edit->re, 3, i0); 19314887Schin if (*s) 19324887Schin { 19334887Schin error(2, "%s: invalid characters after substitution: %s ", p3, s); 19344887Schin goto eatmap; 19354887Schin } 19364887Schin } 19374887Schin if (c) 19384887Schin { 19394887Schin error(2, "%s: %s: substitution argument expected", p3, pptokstr(pp.token, 0)); 19404887Schin goto eatmap; 19414887Schin } 19424887Schin map->next = (struct map*)pp.maps; 19434887Schin pp.maps = (char*)map; 19444887Schin eatmap: 19454887Schin POP_LINE(); 19464887Schin /*INDENT*/ 19474887Schin break; 19484887Schin case X_MAPINCLUDE: 19494887Schin ppmapinclude(NiL, p5); 19504887Schin break; 19514887Schin case X_MODERN: 19524887Schin setoption(MODERN, i0); 19534887Schin break; 19544887Schin case X_MULTIPLE: 19554887Schin n = 1; 19564887Schin if (pp.in->type == IN_FILE) 19574887Schin ppmultiple(ppsetfile(error_info.file), i0 ? INC_CLEAR : INC_TEST); 19584887Schin break; 19594887Schin case X_NATIVE: 19604887Schin setoption(NATIVE, i0); 19614887Schin break; 19624887Schin case X_OPSPACE: 19634887Schin ppfsm(FSM_OPSPACE, i0 ? p4 : (char*)0); 19644887Schin break; 19654887Schin case X_PASSTHROUGH: 19664887Schin ppop(PP_PASSTHROUGH, i0); 19674887Schin break; 19684887Schin case X_PEDANTIC: 19694887Schin ppop(PP_PEDANTIC, i0); 19704887Schin break; 19714887Schin case X_PLUSCOMMENT: 19724887Schin ppop(PP_PLUSCOMMENT, i0); 19734887Schin break; 19744887Schin case X_PLUSPLUS: 19754887Schin ppop(PP_PLUSPLUS, i0); 19764887Schin break; 19774887Schin case X_PLUSSPLICE: 19784887Schin setoption(PLUSSPLICE, i0); 19794887Schin break; 19804887Schin case X_PRAGMAEXPAND: 19814887Schin setoption(PRAGMAEXPAND, i0); 19824887Schin break; 19834887Schin case X_PRAGMAFLAGS: 19844887Schin tokop(PP_PRAGMAFLAGS, p3, p, i0, 0); 19854887Schin break; 19864887Schin case X_PREDEFINED: 19874887Schin setoption(PREDEFINED, i0); 19884887Schin break; 19894887Schin case X_PREFIX: 19904887Schin setoption(PREFIX, i0); 19914887Schin break; 19924887Schin case X_PRESERVE: 19934887Schin setoption(PRESERVE, i0); 19944887Schin if (pp.option & PRESERVE) 19954887Schin { 19964887Schin setmode(CATLITERAL, 0); 19974887Schin ppop(PP_COMPATIBILITY, 1); 19984887Schin ppop(PP_TRANSITION, 0); 19994887Schin ppop(PP_PLUSCOMMENT, 1); 20004887Schin ppop(PP_SPACEOUT, 1); 20014887Schin setoption(STRINGSPAN, 1); 20024887Schin setoption(STRINGSPLIT, 0); 20034887Schin ppop(PP_HOSTDIR, "-", 1); 20044887Schin } 20054887Schin break; 20064887Schin case X_PROTOTYPED: 20074887Schin /* 20084887Schin * this option doesn't bump the token count 20094887Schin */ 20104887Schin 20114887Schin n = 1; 20124887Schin directive = ENDIF; 20134887Schin #if PROTOTYPE 20144887Schin setoption(PROTOTYPED, i0); 20154887Schin #else 20164887Schin error(1, "preprocessor not compiled with prototype conversion enabled"); 20174887Schin #endif 20184887Schin break; 20194887Schin case X_PROTO: 20204887Schin setoption(NOPROTO, !i0); 20214887Schin break; 20224887Schin case X_QUOTE: 20234887Schin tokop(PP_QUOTE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING); 20244887Schin break; 20254887Schin case X_READONLY: 20264887Schin setmode(READONLY, i0); 20274887Schin break; 20284887Schin case X_REGUARD: 20294887Schin setoption(REGUARD, i0); 20304887Schin break; 20314887Schin case X_RESERVED: 20324887Schin tokop(PP_RESERVED, p3, p, i0, 0); 20334887Schin break; 20344887Schin case X_SPACEOUT: 20354887Schin if (!(pp.state & (COMPATIBILITY|COMPILE))) 20364887Schin ppop(PP_SPACEOUT, i0); 20374887Schin break; 20384887Schin case X_SPLICECAT: 20394887Schin setoption(SPLICECAT, i0); 20404887Schin break; 20414887Schin case X_SPLICESPACE: 20424887Schin setoption(SPLICESPACE, i0); 20434887Schin break; 20444887Schin case X_STANDARD: 20454887Schin tokop(PP_STANDARD, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); 20464887Schin break; 20474887Schin case X_STRICT: 20484887Schin ppop(PP_STRICT, i0); 20494887Schin break; 20504887Schin case X_STRINGSPAN: 20514887Schin setoption(STRINGSPAN, i0); 20524887Schin break; 20534887Schin case X_STRINGSPLIT: 20544887Schin setoption(STRINGSPLIT, i0); 20554887Schin if (pp.option & STRINGSPLIT) 20564887Schin setmode(CATLITERAL, 0); 20574887Schin break; 20584887Schin case X_SYSTEM_HEADER: 20594887Schin if (i0) 20604887Schin { 20614887Schin pp.mode |= HOSTED; 20624887Schin pp.flags |= PP_hosted; 20634887Schin pp.in->flags |= IN_hosted; 20644887Schin } 20654887Schin else 20664887Schin { 20674887Schin pp.mode &= ~HOSTED; 20684887Schin pp.flags &= ~PP_hosted; 20694887Schin pp.in->flags &= ~PP_hosted; 20704887Schin } 20714887Schin break; 20724887Schin case X_TEST: 20734887Schin ppop(PP_TEST, p); 20744887Schin break; 20754887Schin case X_TEXT: 20764887Schin if (!(pp.option & KEEPNOTEXT)) 20774887Schin setstate(NOTEXT, !i0); 20784887Schin break; 20794887Schin case X_TRANSITION: 20804887Schin ppop(PP_TRANSITION, i0); 20814887Schin if (pp.state & TRANSITION) ppop(PP_COMPATIBILITY, i0); 20824887Schin break; 20834887Schin case X_TRUNCATE: 20844887Schin ppop(PP_TRUNCATE, i0 ? (p ? strtol(p, NiL, 0) : TRUNCLENGTH) : 0); 20854887Schin break; 20864887Schin case X_VENDOR: 20874887Schin tokop(PP_VENDOR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP); 20884887Schin break; 20894887Schin case X_VERSION: 20904887Schin if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT)) 20914887Schin { 20924887Schin sfsprintf(pp.tmpbuf, MAXTOKEN, "\"%s\"", pp.version); 20934887Schin (*pp.pragma)(dirname(PRAGMA), pp.pass, p3, pp.tmpbuf, !n); 20944887Schin if (pp.linesync && !n) 20954887Schin (*pp.linesync)(error_info.line, error_info.file); 20964887Schin emitted = 1; 20974887Schin } 20984887Schin break; 20994887Schin case X_WARN: 21004887Schin ppop(PP_WARN, i0); 21014887Schin break; 21024887Schin case X_ZEOF: 21034887Schin setoption(ZEOF, i0); 21044887Schin break; 21054887Schin #if DEBUG 21064887Schin case 0: 21074887Schin case X_INCLUDED: 21084887Schin case X_NOTICED: 21094887Schin case X_OPTION: 21104887Schin case X_STATEMENT: 21114887Schin break; 21124887Schin default: 21134887Schin error(PANIC, "%s: option recognized but not implemented", pp.valbuf); 21144887Schin break; 21154887Schin #endif 21164887Schin } 21174887Schin *p4 = i2; 21184887Schin if (!n) 21194887Schin goto checkmap; 21204887Schin goto donedirective; 21214887Schin case RENAME: 21224887Schin if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX))) 21234887Schin error(1, "#%s: non-standard directive", pp.token); 21244887Schin if ((c = pplex()) != T_ID) 21254887Schin { 21264887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); 21274887Schin goto eatdirective; 21284887Schin } 21294887Schin if (!(sym = pprefmac(pp.token, REF_DELETE)) || !sym->macro) 21304887Schin goto eatdirective; 21314887Schin if (sym->flags & (SYM_ACTIVE|SYM_READONLY)) 21324887Schin { 21334887Schin if (!(pp.option & ALLPOSSIBLE)) 21344887Schin error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active"); 21354887Schin goto eatdirective; 21364887Schin } 21374887Schin if ((c = pplex()) != T_ID) 21384887Schin { 21394887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); 21404887Schin goto eatdirective; 21414887Schin } 21424887Schin var.symbol = pprefmac(pp.token, REF_CREATE); 21434887Schin if (mac = var.symbol->macro) 21444887Schin { 21454887Schin if (var.symbol->flags & (SYM_ACTIVE|SYM_READONLY)) 21464887Schin { 21474887Schin if (!(pp.option & ALLPOSSIBLE)) 21484887Schin error(2, "%s: macro is %s", var.symbol->name, (var.symbol->flags & SYM_READONLY) ? "readonly" : "active"); 21494887Schin goto eatdirective; 21504887Schin } 21514887Schin if (!(pp.mode & HOSTED) || !(var.symbol->flags & SYM_INITIAL)) 21524887Schin error(1, "%s redefined", var.symbol->name); 21534887Schin if (mac->formals) free(mac->formals); 21544887Schin free(mac->value); 21554887Schin free(mac); 21564887Schin } 21574887Schin ppfsm(FSM_MACRO, var.symbol->name); 21584887Schin var.symbol->flags = sym->flags; 21594887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); 21604887Schin var.symbol->macro = sym->macro; 21614887Schin sym->macro = 0; 21624887Schin break; 21634887Schin case UNDEF: 21644887Schin if ((c = pplex()) != T_ID) 21654887Schin { 21664887Schin error(1, "%s: invalid macro name", pptokstr(pp.token, 0)); 21674887Schin goto eatdirective; 21684887Schin } 21694887Schin if (sym = pprefmac(pp.token, REF_DELETE)) 21704887Schin { 21714887Schin if (mac = sym->macro) 21724887Schin { 21734887Schin if (sym->flags & (SYM_ACTIVE|SYM_READONLY)) 21744887Schin { 21754887Schin if (!(pp.option & ALLPOSSIBLE)) 21764887Schin error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active"); 21774887Schin goto eatdirective; 21784887Schin } 21794887Schin if (mac->formals) free(mac->formals); 21804887Schin free(mac->value); 21814887Schin free(mac); 21824887Schin mac = sym->macro = 0; 21834887Schin } 21844887Schin 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))) 21854887Schin { 21864887Schin ppsync(); 21874887Schin ppprintf("#%s %s", dirname(UNDEF), sym->name); 21884887Schin emitted = 1; 21894887Schin } 21904887Schin sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC); 21914887Schin n2 = error_info.line; 21924887Schin goto benign; 21934887Schin } 21944887Schin else pprefmac(pp.token, REF_UNDEF); 21954887Schin break; 21964887Schin #if DEBUG 21974887Schin default: 21984887Schin error(PANIC, "#%s: directive recognized but not implemented", pp.token); 21994887Schin goto eatdirective; 22004887Schin #endif 22014887Schin } 22024887Schin break; 22034887Schin case '\n': 22044887Schin break; 22054887Schin default: 22064887Schin error(1, "%s: invalid directive name", pptokstr(pp.token, 0)); 22074887Schin goto eatdirective; 22084887Schin } 22094887Schin enddirective: 22104887Schin #if COMPATIBLE 22114887Schin if (c != '\n' && !(pp.state & COMPATIBILITY)) 22124887Schin #else 22134887Schin if (c != '\n') 22144887Schin #endif 22154887Schin { 22164887Schin pp.state |= DISABLE|NOSPACE; 22174887Schin if ((c = pplex()) != '\n' && (pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC) 22184887Schin error(1, "%s: invalid characters after directive", pptokstr(pp.token, 0)); 22194887Schin } 22204887Schin eatdirective: 22214887Schin if (c != '\n') 22224887Schin { 22234887Schin pp.state |= DISABLE; 22244887Schin while (pplex() != '\n'); 22254887Schin } 22264887Schin donedirective: 22274887Schin #if _HUH_2002_05_09 22284887Schin if (!(pp.state & EOF2NL)) 22294887Schin error(2, "%s in directive", pptokchr(0)); 22304887Schin #endif 22314887Schin pp.state &= ~RESTORE; 22324887Schin pp.mode &= ~RELAX; 22334887Schin if (!(*pp.control & SKIP)) 22344887Schin { 22354887Schin pp.state |= restore; 22364887Schin switch (directive) 22374887Schin { 22384887Schin case LINE: 22394887Schin return 0; 22404887Schin case INCLUDE: 22414887Schin if (pp.include) 22424887Schin { 22434887Schin error_info.line++; 22444887Schin PUSH_FILE(pp.include, n); 22454887Schin if (!pp.vendor && (pp.found->type & TYPE_VENDOR)) 22464887Schin pp.vendor = 1; 22474887Schin pp.include = 0; 22484887Schin return 0; 22494887Schin } 22504887Schin if (pp.incref) 22514887Schin (*pp.incref)(error_info.file, ppgetfile(pp.path)->name, error_info.line, PP_SYNC_IGNORE); 22524887Schin else if (pp.linesync && pp.macref) 22534887Schin { 22544887Schin pp.flags |= PP_lineignore; 22554887Schin (*pp.linesync)(error_info.line, ppgetfile(pp.path)->name); 22564887Schin } 22574887Schin /*FALLTHROUGH*/ 22584887Schin default: 22594887Schin pp.in->flags |= IN_tokens; 22604887Schin /*FALLTHROUGH*/ 22614887Schin case ENDIF: 22624887Schin error_info.line++; 22634887Schin if (emitted) 22644887Schin { 22654887Schin ppputchar('\n'); 22664887Schin ppcheckout(); 22674887Schin } 22684887Schin else 22694887Schin { 22704887Schin pp.state |= HIDDEN; 22714887Schin pp.hidden++; 22724887Schin } 22734887Schin return 0; 22744887Schin } 22754887Schin } 22764887Schin pp.state |= restore|HIDDEN|SKIPCONTROL; 22774887Schin pp.hidden++; 22784887Schin pp.level++; 22794887Schin error_info.line++; 22804887Schin return 0; 22814887Schin } 22824887Schin 22834887Schin /* 22844887Schin * grow the pp nesting control stack 22854887Schin */ 22864887Schin 22874887Schin void 22884887Schin ppnest(void) 22894887Schin { 22904887Schin register struct ppinstk* ip; 22914887Schin int oz; 22924887Schin int nz; 22934887Schin long adjust; 22944887Schin long* op; 22954887Schin long* np; 22964887Schin 22974887Schin oz = pp.constack; 22984887Schin op = pp.maxcon - oz + 1; 22994887Schin nz = oz * 2; 23004887Schin np = newof(op, long, nz, 0); 23014887Schin if (adjust = (np - op)) 23024887Schin { 23034887Schin ip = pp.in; 23044887Schin do 23054887Schin { 23064887Schin if (ip->control) 23074887Schin ip->control += adjust; 23084887Schin } while (ip = ip->prev); 23094887Schin } 23104887Schin pp.control = np + oz; 23114887Schin pp.constack = nz; 23124887Schin pp.maxcon = np + nz - 1; 23134887Schin } 2314