Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libpp/ppcontrol.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1986-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
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
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
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*
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*
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
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
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, 4, 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, 4, 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, 4, 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, 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, 4, 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, 4, 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
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
2317