14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1986-2009 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * Glenn Fowler
234887Schin * AT&T Research
244887Schin *
254887Schin * preprocessor macro call
264887Schin */
274887Schin
284887Schin #include "pplib.h"
294887Schin
304887Schin #include <ctype.h>
314887Schin
324887Schin /*
334887Schin * call a macro by pushing its value on the input stream
344887Schin * only the macro token itself has been consumed
354887Schin * -1 returned if macro disabled
364887Schin * 0 returned if tok==0 and sym->mac->value to be copied to output by caller
374887Schin * 1 returned if value pushed on input
384887Schin */
394887Schin
404887Schin int
ppcall(register struct ppsymbol * sym,int tok)414887Schin ppcall(register struct ppsymbol* sym, int tok)
424887Schin {
434887Schin register int c;
444887Schin register char* p;
454887Schin register char* q;
464887Schin register struct ppmacro* mac;
474887Schin int n;
484887Schin int m;
494887Schin int ret;
504887Schin int old_hidden;
514887Schin int last_line;
524887Schin long old_state;
534887Schin char* last_file;
54*10898Sroland.mainz@nrubsig.org char* old_next;
554887Schin char* old_token;
564887Schin struct ppmacstk* mp;
574887Schin struct ppinstk* old_in;
584887Schin struct ppinstk* kp;
594887Schin struct pptuple* tp;
604887Schin
614887Schin ret = -1;
624887Schin sym->flags |= SYM_NOTICED;
634887Schin if (mac = sym->macro)
644887Schin {
654887Schin count(macro);
664887Schin if ((sym->flags & SYM_PREDICATE) && (pp.state & (CONDITIONAL|WARN)) == (CONDITIONAL|WARN))
674887Schin error(1, "%s: macro definition overrides assertion: use #%s ...", sym->name, sym->name);
684887Schin if (sym->flags & SYM_DISABLED)
694887Schin #if COMPATIBLE
704887Schin if ((pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY || !mac->arity)
714887Schin #endif
724887Schin {
734887Schin pp.mode |= MARKMACRO;
744887Schin #if COMPATIBLE
754887Schin if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
764887Schin error(1, "%s: macro recursion inhibited", sym->name);
774887Schin #endif
784887Schin goto disable;
794887Schin }
804887Schin if ((sym->flags & SYM_PREDEFINED) && !(pp.mode & (HOSTED|INACTIVE)))
814887Schin {
824887Schin #if COMPATIBLE
834887Schin if (*sym->name != '_' && !(pp.state & COMPATIBILITY))
844887Schin #else
854887Schin if (*sym->name != '_')
864887Schin #endif
874887Schin {
884887Schin if (pp.state & STRICT)
894887Schin {
904887Schin error(1, "%s: obsolete predefined symbol expansion disabled", sym->name);
914887Schin goto disable;
924887Schin }
934887Schin error(1, "%s: obsolete predefined symbol expanded%s", sym->name, (pp.state & DIRECTIVE) ? "" : " outside of directive");
944887Schin }
954887Schin else if (!(pp.state & DIRECTIVE) && mac->value && (ppisdig(*mac->value) || *mac->value == '#'))
964887Schin error(1, "%s: predefined symbol expanded outside of directive", sym->name);
974887Schin }
984887Schin debug((-5, "macro %s = %s", sym->name, mac->value));
994887Schin if (pp.macref)
1004887Schin (*pp.macref)(sym, error_info.file, error_info.line, (pp.state & CONDITIONAL) ? REF_IF : REF_NORMAL, 0L);
1014887Schin if (tp = mac->tuple)
1024887Schin {
1034887Schin old_state = pp.state;
1044887Schin pp.state |= DEFINITION|NOSPACE;
1054887Schin old_token = pp.token;
1064887Schin n = 2 * MAXTOKEN;
1074887Schin pp.token = p = oldof(0, char, 0, n);
1084887Schin q = p + MAXTOKEN;
1094887Schin *pp.token++ = ' ';
1104887Schin old_hidden = pp.hidden;
1114887Schin while (c = pplex())
1124887Schin {
1134887Schin if (c == '\n')
1144887Schin {
1154887Schin pp.hidden++;
1164887Schin pp.state |= HIDDEN|NEWLINE;
1174887Schin old_state |= HIDDEN|NEWLINE;
1184887Schin error_info.line++;
1194887Schin }
1204887Schin else if (c == '#')
1214887Schin {
1224887Schin ungetchr(c);
1234887Schin break;
1244887Schin }
1254887Schin else
1264887Schin {
1274887Schin for (;;)
1284887Schin {
1294887Schin if (streq(pp.token, tp->token))
1304887Schin {
1314887Schin if (!(tp = tp->match))
1324887Schin break;
1334887Schin if (!tp->nomatch)
1344887Schin {
1354887Schin free(p);
1364887Schin pp.state = old_state;
1374887Schin pp.token = old_token;
1384887Schin PUSH_TUPLE(sym, tp->token);
1394887Schin ret = 1;
1404887Schin goto disable;
1414887Schin }
1424887Schin }
1434887Schin else if (!(tp = tp->nomatch))
1444887Schin break;
1454887Schin }
1464887Schin if (!tp)
1474887Schin {
1484887Schin pp.token = pp.toknxt;
1494887Schin break;
1504887Schin }
1514887Schin }
1524887Schin if ((pp.token = pp.toknxt) > q)
1534887Schin {
1544887Schin c = pp.token - p;
1554887Schin p = newof(p, char, n += MAXTOKEN, 0);
1564887Schin q = p + n - MAXTOKEN;
1574887Schin pp.token = p + c;
1584887Schin }
1594887Schin *pp.token++ = ' ';
1604887Schin }
1614887Schin if (pp.token > p && *(pp.token - 1) == ' ')
1624887Schin pp.token--;
1634887Schin if (pp.hidden != old_hidden)
1644887Schin *pp.token++ = '\n';
1654887Schin else
1664887Schin *pp.token++ = ' ';
1674887Schin *pp.token = 0;
1684887Schin pp.state = old_state;
1694887Schin pp.token = old_token;
1704887Schin if (*p)
1714887Schin PUSH_RESCAN(p);
1724887Schin else
1734887Schin free(p);
1744887Schin if (!mac->value)
1754887Schin goto disable;
1764887Schin }
1774887Schin if (sym->flags & SYM_FUNCTION)
1784887Schin {
1794887Schin /*
1804887Schin * a quick and dirty '(' peek to avoid possibly
1814887Schin * inappropriate ungetchr()'s below
1824887Schin */
1834887Schin
1844887Schin for (p = pp.in->nextchr; isspace(*p); p++);
1854887Schin if ((c = *p) != '(' && c != '/' && c != 0 && c != MARK)
1864887Schin goto disable;
187*10898Sroland.mainz@nrubsig.org old_next = (c == MARK) ? pp.in->nextchr : NiL;
1884887Schin old_token = pp.token;
1894887Schin mp = pp.macp->next;
1904887Schin if ((pp.token = (char*)&mp->arg[mac->arity + 1]) > pp.maxmac)
1914887Schin error(3, "%s: too many nested function-like macros", sym->name);
1924887Schin old_hidden = pp.hidden;
1934887Schin old_state = pp.state;
1944887Schin pp.state |= DEFINITION|FILEPOP|NOSPACE;
1954887Schin while ((c = pplex()) == '\n')
1964887Schin {
1974887Schin pp.hidden++;
1984887Schin pp.state |= HIDDEN|NEWLINE;
1994887Schin old_state |= HIDDEN|NEWLINE;
2004887Schin error_info.line++;
2014887Schin }
2024887Schin if (c != '(')
2034887Schin {
2044887Schin pp.state = old_state;
205*10898Sroland.mainz@nrubsig.org if (old_next)
206*10898Sroland.mainz@nrubsig.org pp.in->nextchr = old_next;
207*10898Sroland.mainz@nrubsig.org else
2084887Schin {
209*10898Sroland.mainz@nrubsig.org if (c)
210*10898Sroland.mainz@nrubsig.org {
211*10898Sroland.mainz@nrubsig.org p = pp.toknxt;
212*10898Sroland.mainz@nrubsig.org while (p > pp.token)
213*10898Sroland.mainz@nrubsig.org ungetchr(*--p);
2144887Schin #if COMPATIBLE
215*10898Sroland.mainz@nrubsig.org if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
216*10898Sroland.mainz@nrubsig.org error(1, "%s: macro arguments omitted", sym->name);
2174887Schin #endif
218*10898Sroland.mainz@nrubsig.org if (c == T_ID && !(pp.state & HIDDEN))
219*10898Sroland.mainz@nrubsig.org ungetchr(' ');
220*10898Sroland.mainz@nrubsig.org }
221*10898Sroland.mainz@nrubsig.org if (pp.hidden != old_hidden)
222*10898Sroland.mainz@nrubsig.org {
223*10898Sroland.mainz@nrubsig.org ungetchr('\n');
224*10898Sroland.mainz@nrubsig.org error_info.line--;
225*10898Sroland.mainz@nrubsig.org if (pp.hidden && !--pp.hidden)
226*10898Sroland.mainz@nrubsig.org pp.state &= ~HIDDEN;
227*10898Sroland.mainz@nrubsig.org }
2284887Schin }
2294887Schin pp.token = old_token;
2304887Schin goto disable;
2314887Schin }
2324887Schin pp.state = old_state;
2334887Schin
2344887Schin /*
2354887Schin * arg[i][-1] is an extra char for each actual i
2364887Schin * for a possible ungetchr('"') during IN_QUOTE
2374887Schin * arg[i][-1]==0 if arg i need not be expanded
2384887Schin * arg[0][-2] holds the actual arg count
2394887Schin */
2404887Schin
2414887Schin c = 0;
2424887Schin m = 0;
2434887Schin n = 0;
2444887Schin mp = pp.macp->next;
2454887Schin p = pp.token = (char*)&mp->arg[mac->arity + 1];
2464887Schin pp.state |= COLLECTING|NOEXPAND;
2474887Schin pp.state &= ~FILEPOP;
2484887Schin sym->flags |= SYM_ACTIVE;
2494887Schin old_in = pp.in;
2504887Schin last_line = error_info.line;
2514887Schin last_file = error_info.file;
2524887Schin mp->line = error_info.line;
2534887Schin #if MACKEYARGS
2544887Schin if (pp.option & KEYARGS)
2554887Schin {
2564887Schin for (c = 0; c < mac->arity; c++)
2574887Schin mp->arg[c] = mac->args.key[c].value + 1;
2584887Schin mp->arg[0]++;
2594887Schin }
2604887Schin else
2614887Schin #endif
2624887Schin {
2634887Schin *++p = ' ';
2644887Schin mp->arg[0] = ++p;
2654887Schin }
2664887Schin #if MACKEYARGS
2674887Schin keyarg:
2684887Schin if (pp.option & KEYARGS)
2694887Schin {
2704887Schin pp.state |= NOSPACE;
2714887Schin switch (pplex())
2724887Schin {
2734887Schin case T_ID:
2744887Schin break;
2754887Schin case ')': /* no actual key args */
2764887Schin if (!(pp.state & NOEXPAND))
2774887Schin pp.state |= NOEXPAND;
2784887Schin for (c = 0; c < mac->arity; c++)
2794887Schin mp->arg[c][-1] = 0;
2804887Schin c = 0;
2814887Schin goto endactuals;
2824887Schin default:
2834887Schin error(3, "%s: invalid keyword macro argument", pp.token);
2844887Schin break;
2854887Schin }
2864887Schin for (c = 0; c < mac->arity; c++)
2874887Schin if (streq(pp.token, mac->args.key[c].name)) break;
2884887Schin if (c >= mac->arity)
2894887Schin error(2, "%s: invalid macro argument keyword", pp.token);
2904887Schin if (pplex() != '=')
2914887Schin error(2, "= expected in keyword macro argument");
2924887Schin pp.state &= ~NOSPACE;
2934887Schin if (!c)
2944887Schin p++;
2954887Schin pp.token = mp->arg[c] = ++p;
2964887Schin }
2974887Schin #endif
2984887Schin for (;;)
2994887Schin {
3004887Schin if ((pp.mactop = pp.token = p) >= pp.maxmac)
3014887Schin error(3, "%s: too many nested function-like macros", sym->name);
3024887Schin switch (pplex())
3034887Schin {
3044887Schin case '(':
3054887Schin n++;
3064887Schin break;
3074887Schin case ')':
3084887Schin if (!n--)
3094887Schin {
3104887Schin if (p > mp->arg[c] && *(p - 1) == ' ')
3114887Schin p--;
3124887Schin if (p > mp->arg[c] && *(p - 1) == '\\')
3134887Schin {
3144887Schin for (q = mp->arg[c]; q < p; q++)
3154887Schin if (*q == '\\')
3164887Schin q++;
3174887Schin if (q > p)
3184887Schin *p++ = '\\';
3194887Schin }
3204887Schin #if MACKEYARGS
3214887Schin *p = 0;
3224887Schin m++;
3234887Schin #endif
3244887Schin goto endactuals;
3254887Schin }
3264887Schin break;
3274887Schin case ',':
3284887Schin if (!n && (m++, (c < mac->arity - 1 || !(sym->flags & SYM_VARIADIC))))
3294887Schin {
3304887Schin if (p > mp->arg[c] && *(p - 1) == ' ')
3314887Schin p--;
3324887Schin *p++ = 0;
3334887Schin if (!(pp.state & NOEXPAND))
3344887Schin pp.state |= NOEXPAND;
3354887Schin else
3364887Schin mp->arg[c][-1] = 0;
3374887Schin #if MACKEYARGS
3384887Schin if (pp.option & KEYARGS)
3394887Schin {
3404887Schin pp.token = p + 1;
3414887Schin goto keyarg;
3424887Schin }
3434887Schin #endif
3444887Schin {
3454887Schin if ((pp.state & STRICT) && p == mp->arg[c])
3464887Schin error(1, "%s: macro call argument %d is null", sym->name, c + 1);
3474887Schin if (c < mac->arity)
3484887Schin c++;
3494887Schin *p++ = ' ';
3504887Schin }
3514887Schin pp.toknxt = mp->arg[c] = p;
3524887Schin }
3534887Schin break;
3544887Schin case 0:
3554887Schin if (pp.in == old_in)
3564887Schin kp = 0;
3574887Schin else
3584887Schin for (kp = pp.in; kp && kp != old_in; kp = kp->prev);
3594887Schin if (!kp)
3604887Schin {
3614887Schin error(
3624887Schin #if COMPATIBLE
3634887Schin (pp.state & COMPATIBILITY) ? 3 :
3644887Schin #endif
3654887Schin 2, "%s: %s in macro argument list", sym->name, pptokchr(0));
3664887Schin goto endactuals;
3674887Schin }
3684887Schin continue;
3694887Schin case '\n':
3704887Schin pp.state |= HIDDEN;
3714887Schin error_info.line++;
3724887Schin pp.hidden++;
3734887Schin /*FALLTHROUGH*/
3744887Schin case ' ':
3754887Schin if (p > mp->arg[c] && *(p - 1) != ' ') *p++ = ' ';
3764887Schin continue;
3774887Schin }
3784887Schin p = pp.toknxt;
3794887Schin if (error_info.line != last_line)
3804887Schin {
3814887Schin SETLINE(p, error_info.line);
3824887Schin last_line = error_info.line;
3834887Schin }
3844887Schin if (error_info.file != last_file)
3854887Schin {
3864887Schin SETFILE(p, error_info.file);
3874887Schin last_file = error_info.file;
3884887Schin }
3894887Schin }
3904887Schin endactuals:
3914887Schin if (pp.state & NOEXPAND)
3924887Schin mp->arg[c][-1] = 0;
3934887Schin pp.token = old_token;
3944887Schin if (pp.in != old_in)
3954887Schin {
3964887Schin for (kp = pp.in; kp && kp != old_in; kp = kp->prev);
3974887Schin if (kp)
3984887Schin error(2, "%s: macro call starts and ends in different files", sym->name);
3994887Schin }
4004887Schin pp.state &= ~(COLLECTING|FILEPOP|NOEXPAND);
4014887Schin sym->flags &= ~SYM_ACTIVE;
4024887Schin #if MACKEYARGS
4034887Schin if (!(pp.option & KEYARGS))
4044887Schin #endif
4054887Schin {
4064887Schin if (p > mp->arg[0] && ++m || (sym->flags & SYM_VARIADIC))
4074887Schin c++;
4084887Schin if (c != mac->arity && !(sym->flags & SYM_EMPTY))
4094887Schin {
4104887Schin n = mac->arity;
4114887Schin if (!(sym->flags & SYM_VARIADIC))
4124887Schin error(1, "%s: %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s");
4134887Schin else if (c < --n)
4144887Schin error(1, "%s: at least %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s");
4154887Schin #if COMPATIBLE
4164887Schin if (!c && (pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
4174887Schin goto disable;
4184887Schin #endif
4194887Schin }
4204887Schin if (!c)
4214887Schin ++c;
4224887Schin while (c < mac->arity)
4234887Schin mp->arg[c++] = (char*)"\0" + 1;
4244887Schin }
4254887Schin mp->arg[0][-2] = m;
4264887Schin *p++ = 0;
4274887Schin nextframe(mp, p);
4284887Schin count(function);
4294887Schin }
4304887Schin if (!tok && (sym->flags & SYM_NOEXPAND))
4314887Schin {
4324887Schin if (sym->flags & SYM_FUNCTION)
4334887Schin popframe(mp);
4344887Schin ret = !mac->size;
4354887Schin }
4364887Schin else if (!(pp.state & HEADER) || (pp.option & HEADEREXPANDALL) || pp.in->type != IN_COPY)
4374887Schin {
4384887Schin if (sym->flags & SYM_MULTILINE)
4394887Schin PUSH_MULTILINE(sym);
4404887Schin else
4414887Schin PUSH_MACRO(sym);
4424887Schin ret = 1;
4434887Schin }
4444887Schin }
4454887Schin disable:
4464887Schin 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))
4474887Schin {
4484887Schin struct ppinstk* inp;
4494887Schin
4504887Schin for (inp = pp.in; inp->type != IN_FILE && inp->prev; inp = inp->prev);
4514887Schin sfsprintf(pp.hidebuf, MAXTOKEN, "_%d_%s_hIDe", inp->index, sym->name);
4524887Schin PUSH_STRING(pp.hidebuf);
4534887Schin ret = 1;
4544887Schin }
4554887Schin pp.state &= ~NEWLINE;
4564887Schin pp.in->flags |= IN_tokens;
4574887Schin count(token);
4584887Schin return ret;
4594887Schin }
460