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