Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libpp/ppcall.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 macro call
26
*/
27
28
#include "pplib.h"
29
30
#include <ctype.h>
31
32
/*
33
* call a macro by pushing its value on the input stream
34
* only the macro token itself has been consumed
35
* -1 returned if macro disabled
36
* 0 returned if tok==0 and sym->mac->value to be copied to output by caller
37
* 1 returned if value pushed on input
38
*/
39
40
int
41
ppcall(register struct ppsymbol* sym, int tok)
42
{
43
register int c;
44
register char* p;
45
register char* q;
46
register struct ppmacro* mac;
47
int n;
48
int m;
49
int ret;
50
int old_hidden;
51
int last_line;
52
long old_state;
53
char* last_file;
54
char* old_next;
55
char* old_token;
56
struct ppmacstk* mp;
57
struct ppinstk* old_in;
58
struct ppinstk* kp;
59
struct pptuple* tp;
60
61
ret = -1;
62
sym->flags |= SYM_NOTICED;
63
if (mac = sym->macro)
64
{
65
count(macro);
66
if ((sym->flags & SYM_PREDICATE) && (pp.state & (CONDITIONAL|WARN)) == (CONDITIONAL|WARN))
67
error(1, "%s: macro definition overrides assertion: use #%s ...", sym->name, sym->name);
68
if (sym->flags & SYM_DISABLED)
69
#if COMPATIBLE
70
if ((pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY || !mac->arity)
71
#endif
72
{
73
pp.mode |= MARKMACRO;
74
#if COMPATIBLE
75
if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
76
error(1, "%s: macro recursion inhibited", sym->name);
77
#endif
78
goto disable;
79
}
80
if ((sym->flags & SYM_PREDEFINED) && !(pp.mode & (HOSTED|INACTIVE)))
81
{
82
#if COMPATIBLE
83
if (*sym->name != '_' && !(pp.state & COMPATIBILITY))
84
#else
85
if (*sym->name != '_')
86
#endif
87
{
88
if (pp.state & STRICT)
89
{
90
error(1, "%s: obsolete predefined symbol expansion disabled", sym->name);
91
goto disable;
92
}
93
error(1, "%s: obsolete predefined symbol expanded%s", sym->name, (pp.state & DIRECTIVE) ? "" : " outside of directive");
94
}
95
else if (!(pp.state & DIRECTIVE) && mac->value && (ppisdig(*mac->value) || *mac->value == '#'))
96
error(1, "%s: predefined symbol expanded outside of directive", sym->name);
97
}
98
debug((-5, "macro %s = %s", sym->name, mac->value));
99
if (pp.macref)
100
(*pp.macref)(sym, error_info.file, error_info.line, (pp.state & CONDITIONAL) ? REF_IF : REF_NORMAL, 0L);
101
if (tp = mac->tuple)
102
{
103
old_state = pp.state;
104
pp.state |= DEFINITION|NOSPACE;
105
old_token = pp.token;
106
n = 2 * MAXTOKEN;
107
pp.token = p = oldof(0, char, 0, n);
108
q = p + MAXTOKEN;
109
*pp.token++ = ' ';
110
old_hidden = pp.hidden;
111
while (c = pplex())
112
{
113
if (c == '\n')
114
{
115
pp.hidden++;
116
pp.state |= HIDDEN|NEWLINE;
117
old_state |= HIDDEN|NEWLINE;
118
error_info.line++;
119
}
120
else if (c == '#')
121
{
122
ungetchr(c);
123
break;
124
}
125
else
126
{
127
for (;;)
128
{
129
if (streq(pp.token, tp->token))
130
{
131
if (!(tp = tp->match))
132
break;
133
if (!tp->nomatch)
134
{
135
free(p);
136
pp.state = old_state;
137
pp.token = old_token;
138
PUSH_TUPLE(sym, tp->token);
139
ret = 1;
140
goto disable;
141
}
142
}
143
else if (!(tp = tp->nomatch))
144
break;
145
}
146
if (!tp)
147
{
148
pp.token = pp.toknxt;
149
break;
150
}
151
}
152
if ((pp.token = pp.toknxt) > q)
153
{
154
c = pp.token - p;
155
p = newof(p, char, n += MAXTOKEN, 0);
156
q = p + n - MAXTOKEN;
157
pp.token = p + c;
158
}
159
*pp.token++ = ' ';
160
}
161
if (pp.token > p && *(pp.token - 1) == ' ')
162
pp.token--;
163
if (pp.hidden != old_hidden)
164
*pp.token++ = '\n';
165
else
166
*pp.token++ = ' ';
167
*pp.token = 0;
168
pp.state = old_state;
169
pp.token = old_token;
170
if (*p)
171
PUSH_RESCAN(p);
172
else
173
free(p);
174
if (!mac->value)
175
goto disable;
176
}
177
if (sym->flags & SYM_FUNCTION)
178
{
179
/*
180
* a quick and dirty '(' peek to avoid possibly
181
* inappropriate ungetchr()'s below
182
*/
183
184
for (p = pp.in->nextchr; isspace(*p); p++);
185
if ((c = *p) != '(' && c != '/' && c != 0 && c != MARK)
186
goto disable;
187
old_next = (c == MARK) ? pp.in->nextchr : NiL;
188
old_token = pp.token;
189
mp = pp.macp->next;
190
if ((pp.token = (char*)&mp->arg[mac->arity + 1]) > pp.maxmac)
191
error(3, "%s: too many nested function-like macros", sym->name);
192
old_hidden = pp.hidden;
193
old_state = pp.state;
194
pp.state |= DEFINITION|FILEPOP|NOSPACE;
195
while ((c = pplex()) == '\n')
196
{
197
pp.hidden++;
198
pp.state |= HIDDEN|NEWLINE;
199
old_state |= HIDDEN|NEWLINE;
200
error_info.line++;
201
}
202
if (c != '(')
203
{
204
pp.state = old_state;
205
if (old_next)
206
pp.in->nextchr = old_next;
207
else
208
{
209
if (c)
210
{
211
p = pp.toknxt;
212
while (p > pp.token)
213
ungetchr(*--p);
214
#if COMPATIBLE
215
if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
216
error(1, "%s: macro arguments omitted", sym->name);
217
#endif
218
if (c == T_ID && !(pp.state & HIDDEN))
219
ungetchr(' ');
220
}
221
if (pp.hidden != old_hidden)
222
{
223
ungetchr('\n');
224
error_info.line--;
225
if (pp.hidden && !--pp.hidden)
226
pp.state &= ~HIDDEN;
227
}
228
}
229
pp.token = old_token;
230
goto disable;
231
}
232
pp.state = old_state;
233
234
/*
235
* arg[i][-1] is an extra char for each actual i
236
* for a possible ungetchr('"') during IN_QUOTE
237
* arg[i][-1]==0 if arg i need not be expanded
238
* arg[0][-2] holds the actual arg count
239
*/
240
241
c = 0;
242
m = 0;
243
n = 0;
244
mp = pp.macp->next;
245
p = pp.token = (char*)&mp->arg[mac->arity + 1];
246
pp.state |= COLLECTING|NOEXPAND;
247
pp.state &= ~FILEPOP;
248
sym->flags |= SYM_ACTIVE;
249
old_in = pp.in;
250
last_line = error_info.line;
251
last_file = error_info.file;
252
mp->line = error_info.line;
253
#if MACKEYARGS
254
if (pp.option & KEYARGS)
255
{
256
for (c = 0; c < mac->arity; c++)
257
mp->arg[c] = mac->args.key[c].value + 1;
258
mp->arg[0]++;
259
}
260
else
261
#endif
262
{
263
*++p = ' ';
264
mp->arg[0] = ++p;
265
}
266
#if MACKEYARGS
267
keyarg:
268
if (pp.option & KEYARGS)
269
{
270
pp.state |= NOSPACE;
271
switch (pplex())
272
{
273
case T_ID:
274
break;
275
case ')': /* no actual key args */
276
if (!(pp.state & NOEXPAND))
277
pp.state |= NOEXPAND;
278
for (c = 0; c < mac->arity; c++)
279
mp->arg[c][-1] = 0;
280
c = 0;
281
goto endactuals;
282
default:
283
error(3, "%s: invalid keyword macro argument", pp.token);
284
break;
285
}
286
for (c = 0; c < mac->arity; c++)
287
if (streq(pp.token, mac->args.key[c].name)) break;
288
if (c >= mac->arity)
289
error(2, "%s: invalid macro argument keyword", pp.token);
290
if (pplex() != '=')
291
error(2, "= expected in keyword macro argument");
292
pp.state &= ~NOSPACE;
293
if (!c)
294
p++;
295
pp.token = mp->arg[c] = ++p;
296
}
297
#endif
298
for (;;)
299
{
300
if ((pp.mactop = pp.token = p) >= pp.maxmac)
301
error(3, "%s: too many nested function-like macros", sym->name);
302
switch (pplex())
303
{
304
case '(':
305
n++;
306
break;
307
case ')':
308
if (!n--)
309
{
310
if (p > mp->arg[c] && *(p - 1) == ' ')
311
p--;
312
if (p > mp->arg[c] && *(p - 1) == '\\')
313
{
314
for (q = mp->arg[c]; q < p; q++)
315
if (*q == '\\')
316
q++;
317
if (q > p)
318
*p++ = '\\';
319
}
320
#if MACKEYARGS
321
*p = 0;
322
m++;
323
#endif
324
goto endactuals;
325
}
326
break;
327
case ',':
328
if (!n && (m++, (c < mac->arity - 1 || !(sym->flags & SYM_VARIADIC))))
329
{
330
if (p > mp->arg[c] && *(p - 1) == ' ')
331
p--;
332
*p++ = 0;
333
if (!(pp.state & NOEXPAND))
334
pp.state |= NOEXPAND;
335
else
336
mp->arg[c][-1] = 0;
337
#if MACKEYARGS
338
if (pp.option & KEYARGS)
339
{
340
pp.token = p + 1;
341
goto keyarg;
342
}
343
#endif
344
{
345
if ((pp.state & STRICT) && p == mp->arg[c])
346
error(1, "%s: macro call argument %d is null", sym->name, c + 1);
347
if (c < mac->arity)
348
c++;
349
*p++ = ' ';
350
}
351
pp.toknxt = mp->arg[c] = p;
352
}
353
break;
354
case 0:
355
if (pp.in == old_in)
356
kp = 0;
357
else
358
for (kp = pp.in; kp && kp != old_in; kp = kp->prev);
359
if (!kp)
360
{
361
error(
362
#if COMPATIBLE
363
(pp.state & COMPATIBILITY) ? 3 :
364
#endif
365
2, "%s: %s in macro argument list", sym->name, pptokchr(0));
366
goto endactuals;
367
}
368
continue;
369
case '\n':
370
pp.state |= HIDDEN;
371
error_info.line++;
372
pp.hidden++;
373
/*FALLTHROUGH*/
374
case ' ':
375
if (p > mp->arg[c] && *(p - 1) != ' ') *p++ = ' ';
376
continue;
377
}
378
p = pp.toknxt;
379
if (error_info.line != last_line)
380
{
381
SETLINE(p, error_info.line);
382
last_line = error_info.line;
383
}
384
if (error_info.file != last_file)
385
{
386
SETFILE(p, error_info.file);
387
last_file = error_info.file;
388
}
389
}
390
endactuals:
391
if (pp.state & NOEXPAND)
392
mp->arg[c][-1] = 0;
393
pp.token = old_token;
394
if (pp.in != old_in)
395
{
396
for (kp = pp.in; kp && kp != old_in; kp = kp->prev);
397
if (kp)
398
error(2, "%s: macro call starts and ends in different files", sym->name);
399
}
400
pp.state &= ~(COLLECTING|FILEPOP|NOEXPAND);
401
sym->flags &= ~SYM_ACTIVE;
402
#if MACKEYARGS
403
if (!(pp.option & KEYARGS))
404
#endif
405
{
406
if (p > mp->arg[0] && ++m || (sym->flags & SYM_VARIADIC))
407
c++;
408
if (c != (n = mac->arity) && (c > 0 || n > 1) && !(sym->flags & SYM_EMPTY))
409
{
410
if (!(sym->flags & SYM_VARIADIC))
411
error(1, "%s: %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s");
412
else if (c < --n)
413
error(1, "%s: at least %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s");
414
#if COMPATIBLE
415
if (!c && (pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
416
goto disable;
417
#endif
418
}
419
if (!c)
420
++c;
421
while (c < mac->arity)
422
mp->arg[c++] = (char*)"\0" + 1;
423
}
424
mp->arg[0][-2] = m;
425
*p++ = 0;
426
nextframe(mp, p);
427
count(function);
428
}
429
if (!tok && (sym->flags & SYM_NOEXPAND))
430
{
431
if (sym->flags & SYM_FUNCTION)
432
popframe(mp);
433
ret = !mac->size;
434
}
435
else if (!(pp.state & HEADER) || (pp.option & HEADEREXPANDALL) || pp.in->type != IN_COPY)
436
{
437
if (sym->flags & SYM_MULTILINE)
438
PUSH_MULTILINE(sym);
439
else
440
PUSH_MACRO(sym);
441
ret = 1;
442
}
443
}
444
disable:
445
if (ret < 0 && sym->hidden && !(pp.mode & EXPOSE) && !(pp.state & HEADER) && (pp.in->type == IN_FILE || pp.in->type == IN_MACRO || pp.in->type == IN_EXPAND))
446
{
447
struct ppinstk* inp;
448
449
for (inp = pp.in; inp->type != IN_FILE && inp->prev; inp = inp->prev);
450
sfsprintf(pp.hidebuf, MAXTOKEN, "_%d_%s_hIDe", inp->index, sym->name);
451
PUSH_STRING(pp.hidebuf);
452
ret = 1;
453
}
454
pp.state &= ~NEWLINE;
455
pp.in->flags |= IN_tokens;
456
count(token);
457
return ret;
458
}
459
460