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