|
|
1.1 root 1: /*
2: * n0/expand.c
3: * C preprocessor.
4: * Macro expansion.
5: */
6:
7: #include <time.h>
8: #ifdef vax
9: #include "INC$LIB:cc0.h"
10: #else
11: #include "cc0.h"
12: #endif
13:
14: /*
15: * Expand the string as an actual parameter.
16: * This happens after the list of strings
17: * in the substituted macro has been pushed
18: * onto dstack; expand the string as if it
19: * formed the rest of the source file and
20: * substitute the expanded string back into
21: * the source stream, with the hidden sets of
22: * identifiers augmented by the macro name we
23: * are substituting.
24: */
25: char *argexpand(hide, p) int hide; char *p;
26: {
27: register char *ap, *spshp;
28: register int c;
29:
30: /* Push the parameter as input */
31: dspush(DS_IEOF, NULL);
32: dspush(DS_STRNG, p);
33: /* Save the push buffer */
34: spshp = dpshp;
35: /* Scan the parameter as input */
36: while ((c = get()) >= 0) {
37: switch (ct[c]) {
38: case QUOTE:
39: case STRING:
40: dpshstr(c);
41: continue;
42: case DOT:
43: case CON:
44: dpshnum(c);
45: continue;
46: case ID:
47: if (expand(c))
48: continue;
49: dpshs(id);
50: /* Augment hidden set */
51: dpshc(hideaug(hide, idhide));
52: continue;
53: default:
54: dpshc(c);
55: continue;
56: }
57: }
58: ++dstackp; /* pop IEOF */
59: /* Now pop the expanded string off the push buffer */
60: /* and onto the put buffer */
61: p = dputp;
62: for (ap = spshp; --ap >= dpshp; )
63: dputc(*ap);
64: dputc(0);
65: /* Restore push buffer pointer */
66: dpshp = spshp;
67: /* Return pointer to expanded argument */
68: return p;
69: }
70:
71: /*
72: * Scan and augment the hidden sets in a string.
73: * An in place copy in essence.
74: */
75: char *argpaste(hide, p) int hide; char *p;
76: {
77: register int c;
78: char *sputp;
79: sputp = dputp;
80: dputp = p;
81: dspush(DS_IEOF, NULL);
82: dspush(DS_STRNG, p);
83: while ((c = get()) >= 0) {
84: switch (ct[c]) {
85: case QUOTE:
86: case STRING:
87: dputstr(c);
88: continue;
89: case DOT:
90: case CON:
91: dputnum(c);
92: continue;
93: case ID:
94: getid(c);
95: dputs(id);
96: /* Augment hidden set */
97: dputc(hideaug(hide, idhide));
98: continue;
99: default:
100: dputc(c);
101: continue;
102: }
103: }
104: ++dstackp;
105: dputp = sputp;
106: return p;
107: }
108:
109:
110: /*
111: * Substitute for the macro specified.
112: * Collect the actual parameters into the push buffer,
113: * then reverse them onto the put buffer.
114: * (Collecting the parameters may pop the dstackp.)
115: * Then parse the macro body into the put buffer,
116: * forming a list of literal strings
117: * (with their hidden sets augmented),
118: * # parameters, ## parameters, and
119: * vanilla parameters.
120: * Then scan the list pushed and
121: * recursively expand the vanilla
122: * parameters with argexpand(),
123: * expanding each parameter only once
124: * no matter how many times it appears
125: * in the substituted body.
126: * Then rescan the list pushed again
127: * to augment the hidden sets of ## params.
128: */
129: substitute(tp, sp) TOK *tp; CPPSYM *sp;
130: {
131: register int c, d;
132: register int narg, plev;
133: register char *p, *pp;
134: register DSTACK *dsp;
135: DSTACK *dparamp, *dbodyp, *dbasep;
136: char *cparamp;
137: int tpidhide;
138:
139: /* Install hide set index */
140: tpidhide = hideset(tp);
141:
142: /* Collect parameters */
143: dparamp = dlistp;
144: cparamp = dpshp;
145: if (sp->s_value == XUSERA) {
146: c = getskip();
147: for (narg = 0; c >= 0 && c != ')'; narg += 1) {
148: plev = 0; p = dpshp;
149: while (c >= 0) {
150: switch (ct[c]) {
151: case QUOTE:
152: case STRING:
153: dpshstr(c); c = get(); continue;
154: case LPAREN:
155: plev++; break;
156: case COMMA:
157: if (!plev) goto next; break;
158: case RPAREN:
159: if (!plev) goto next; plev--; break;
160: case SKIP:
161: unget(getskip()); c = ' '; break;
162: case ID:
163: getid(c); dpshs(id); dpshc(idhide);
164: c = get(); continue;
165: case DOT:
166: case CON:
167: dpshnum(c); c = get(); continue;
168: }
169: dpshc(c); c = get();
170: }
171: next: if (narg < sp->s_narg) {
172: if (dpshp < p && dpshp[0] == ' ')
173: ++dpshp;
174: dpshc(0);
175: dslist(DS_PARAM, p);
176: }
177: if (c == ',')
178: c = getskip();
179: }
180: if (c < 0) {
181: cerror("EOF in macro \"%s\" invocation", tp->t_id);
182: tp = NULL;
183: }
184: if (sp->s_narg != narg) {
185: cerror("\"%s\" argument mismatch", tp->t_id);
186: tp = NULL;
187: }
188: if (tp == NULL) {
189: dlistp = dparamp;
190: dpshp = cparamp;
191: return 1;
192: }
193: }
194: /* Copy the parameter strings onto the top of dbuf */
195: dpshp = cparamp;
196: cparamp = dputp;
197: for (dsp = dparamp+sp->s_narg; --dsp >= dparamp; ) {
198: p = dsp->ds_ptr;
199: dsp->ds_ptr = dputp;
200: while (d = *--p) dputc(d);
201: dputc(d);
202: }
203: /* Copy the macro body into dbuf */
204: dbodyp = dlistp;
205: dspush(DS_IEOF, 0);
206: dspush(DS_STRNG, sp->s_body);
207: p = dputp;
208: dsp = dparamp;
209: while ((c = get()) >= 0) {
210: switch (ct[c]) {
211: case QUOTE:
212: case STRING:
213: dputstr(c); continue;
214: case ID:
215: getid(c);
216: dputs(id);
217: dputc(hideaug(tpidhide, idhide));
218: continue;
219: case CON:
220: case DOT:
221: dputnum(c); continue;
222: default:
223: dputc(c); continue;
224: case HIGH0: /* param */
225: c -= ARG0;
226: pp = dsp[c].ds_ptr;
227: if (p != dputp) {
228: dputc(0);
229: dslist(DS_STRNG, p);
230: p = dputp;
231: }
232: c = get();
233: d = get();
234: unget(d);
235: unget(c);
236: if (c == '#' && d == '#')
237: dslist(DS_SHARP2, pp);
238: else
239: dslist(DS_PARAM, pp);
240: continue;
241: case SHARP: /* # or ## */
242: c = get();
243: if (ct[c] == HIGH0) {
244: c -= ARG0;
245: pp = dsp[c].ds_ptr;
246: if (p != dputp) {
247: dputc(0);
248: dslist(DS_STRNG, p);
249: p = dputp;
250: }
251: dslistc(DS_UNGET, '"');
252: dslist(DS_SHARP, pp);
253: dslistc(DS_UNGET, '"');
254: continue;
255: }
256: c = get();
257: if (ct[c] == HIGH0) {
258: c -= ARG0;
259: pp = dsp[c].ds_ptr;
260: if (p != dputp) {
261: dputc(0);
262: dslist(DS_STRNG, p);
263: p = dputp;
264: }
265: dslist(DS_SHARP2, pp);
266: continue;
267: }
268: unget(c);
269: continue;
270: }
271: }
272: if (p != dputp) {
273: dputc(0);
274: dslist(DS_STRNG, p);
275: p = dputp;
276: }
277: ++dstackp; /* Pop IEOF */
278: dbasep = dstackp;
279: dspush(DS_NAME, tp);
280: dspush(DS_DPUTP, cparamp);
281: while (--dlistp >= dbodyp)
282: *--dstackp = *dlistp;
283: dlistp = dparamp;
284: /* Expand parameters and augment their hidden sets */
285: for (dsp = dstackp; dsp < dbasep; dsp += 1) {
286: if (dsp->ds_type == DS_PARAM) {
287: p = argexpand(tpidhide, pp = dsp->ds_ptr);
288: /* Now make all references to pp */
289: /* refer to the expanded version p */
290: for (dparamp = dsp; dsp < dbasep; dsp += 1)
291: if (dsp->ds_type == DS_PARAM
292: && dsp->ds_ptr == pp) {
293: dsp->ds_type = DS_STRNG;
294: dsp->ds_ptr = p;
295: }
296: dsp = dparamp;
297: }
298: }
299: /* Now scan for glued parameters and augment their hidden sets */
300: /* Done in a separate loop since ##param might appear before */
301: /* param itself in the substitution list, and they both refer */
302: /* to the same copy of the parameter in dbuf before argexpand */
303: for (dsp = dstackp; dsp < dbasep; dsp += 1) {
304: if (dsp->ds_type == DS_SHARP2) {
305: p = argpaste(tpidhide, pp = dsp->ds_ptr);
306: for (dparamp = dsp; dsp < dbasep; dsp += 1)
307: if (dsp->ds_type == DS_SHARP2
308: && dsp->ds_ptr == pp) {
309: dsp->ds_type = DS_STRNG;
310: dsp->ds_ptr = p;
311: }
312: dsp = dparamp;
313: }
314: }
315: return 1;
316: }
317:
318: /*
319: * Try macro expansion,
320: * return true if it happened.
321: * Read id[] starting with 'c'
322: * and see if it is defined.
323: * Since this is called for each
324: * identifier read, it should use
325: * minimal registers and defer most
326: * processing to subfunctions.
327: */
328: expand(c) register int c;
329: {
330: char *p;
331: CPPSYM *sp;
332: TOK *tp;
333: extern char *ctime();
334: static char lineno[16];
335:
336: getid(c);
337: tp = idp;
338: if ((sp=idp->t_sym) == NULL
339: || sp->s_slevel != SL_CPP
340: || hidden()) {
341: none_such: if (incpp > 1) { /* Parsing a #if expression */
342: dspush(DS_STRNG, deffalse);
343: return 1;
344: }
345: return 0;
346: }
347:
348: switch ((int)sp->s_value) {
349: case XUSER:
350: return substitute(tp, sp);
351: case XUFILE:
352: unget('"');
353: dspush(DS_UFILE, file);
354: unget('"');
355: return 1;
356: case XUBASE:
357: unget('"');
358: dspush(DS_UFILE, basefile);
359: unget('"');
360: return 1;
361: case XULINE:
362: dspush(DS_STRNG, lineno);
363: sprintf(lineno, "%d", line);
364: return 1;
365: case XUDATE:
366: case XUTIME:
367: p = ctime(&curtime);
368: if (sp->s_value == XUDATE) {
369: p[24] = 0;
370: strcpy(p+11, p+20);
371: p += 4;
372: } else {
373: p[19] = 0;
374: p += 11;
375: }
376: unget('"');
377: dspush(DS_STRNG, p);
378: unget('"');
379: return 1;
380: #if 0
381: /*
382: * ANSI C says __STDC__ should be defined as 0 for a non-ANSI compiler,
383: * but too many sources use #ifdef __STDC__ when they should use #if __STDC__.
384: * This is therefore conditionalized out here and in n0/cc0key.c.
385: */
386: case XUSTDC:
387: dspush(DS_STRNG, deffalse);
388: return 1;
389: #endif
390: case XDEFINED:
391: if (incpp < 2)
392: return 0;
393: if ((c = getnb()) == '(') {
394: if ((c = getnb()) < 0 || ct[c] != ID)
395: goto bad;
396: getid(c);
397: if ((c = getnb()) != ')')
398: goto bad;
399: } else if (ct[c] == ID)
400: getid(c);
401: else {
402: bad: cerror("illegal use of defined");
403: dspush(DS_STRNG, deffalse);
404: return 1;
405: }
406: tp = idp;
407: if ((sp = tp->t_sym) != NULL
408: && sp->s_slevel == SL_CPP
409: && ! hidden())
410: dspush(DS_STRNG, deftrue);
411: else
412: dspush(DS_STRNG, deffalse);
413: return 1;
414: case XUSERA:
415: if (skipto('('))
416: return substitute(tp, sp);
417: goto none_such;
418: default:
419: cbotch("value %d in expand", sp->s_value);
420: }
421: return 0;
422: }
423:
424: /* end of n0/expand.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.