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