14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1986-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 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; 544887Schin char* old_token; 554887Schin struct ppmacstk* mp; 564887Schin struct ppinstk* old_in; 574887Schin struct ppinstk* kp; 584887Schin struct pptuple* tp; 594887Schin 604887Schin ret = -1; 614887Schin sym->flags |= SYM_NOTICED; 624887Schin if (mac = sym->macro) 634887Schin { 644887Schin count(macro); 654887Schin if ((sym->flags & SYM_PREDICATE) && (pp.state & (CONDITIONAL|WARN)) == (CONDITIONAL|WARN)) 664887Schin error(1, "%s: macro definition overrides assertion: use #%s ...", sym->name, sym->name); 674887Schin if (sym->flags & SYM_DISABLED) 684887Schin #if COMPATIBLE 694887Schin if ((pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY || !mac->arity) 704887Schin #endif 714887Schin { 724887Schin pp.mode |= MARKMACRO; 734887Schin #if COMPATIBLE 744887Schin if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) 754887Schin error(1, "%s: macro recursion inhibited", sym->name); 764887Schin #endif 774887Schin goto disable; 784887Schin } 794887Schin if ((sym->flags & SYM_PREDEFINED) && !(pp.mode & (HOSTED|INACTIVE))) 804887Schin { 814887Schin #if COMPATIBLE 824887Schin if (*sym->name != '_' && !(pp.state & COMPATIBILITY)) 834887Schin #else 844887Schin if (*sym->name != '_') 854887Schin #endif 864887Schin { 874887Schin if (pp.state & STRICT) 884887Schin { 894887Schin error(1, "%s: obsolete predefined symbol expansion disabled", sym->name); 904887Schin goto disable; 914887Schin } 924887Schin error(1, "%s: obsolete predefined symbol expanded%s", sym->name, (pp.state & DIRECTIVE) ? "" : " outside of directive"); 934887Schin } 944887Schin else if (!(pp.state & DIRECTIVE) && mac->value && (ppisdig(*mac->value) || *mac->value == '#')) 954887Schin error(1, "%s: predefined symbol expanded outside of directive", sym->name); 964887Schin } 974887Schin debug((-5, "macro %s = %s", sym->name, mac->value)); 984887Schin if (pp.macref) 994887Schin (*pp.macref)(sym, error_info.file, error_info.line, (pp.state & CONDITIONAL) ? REF_IF : REF_NORMAL, 0L); 1004887Schin if (tp = mac->tuple) 1014887Schin { 1024887Schin old_state = pp.state; 1034887Schin pp.state |= DEFINITION|NOSPACE; 1044887Schin old_token = pp.token; 1054887Schin n = 2 * MAXTOKEN; 1064887Schin pp.token = p = oldof(0, char, 0, n); 1074887Schin q = p + MAXTOKEN; 1084887Schin *pp.token++ = ' '; 1094887Schin old_hidden = pp.hidden; 1104887Schin while (c = pplex()) 1114887Schin { 1124887Schin if (c == '\n') 1134887Schin { 1144887Schin pp.hidden++; 1154887Schin pp.state |= HIDDEN|NEWLINE; 1164887Schin old_state |= HIDDEN|NEWLINE; 1174887Schin error_info.line++; 1184887Schin } 1194887Schin else if (c == '#') 1204887Schin { 1214887Schin ungetchr(c); 1224887Schin break; 1234887Schin } 1244887Schin else 1254887Schin { 1264887Schin for (;;) 1274887Schin { 1284887Schin if (streq(pp.token, tp->token)) 1294887Schin { 1304887Schin if (!(tp = tp->match)) 1314887Schin break; 1324887Schin if (!tp->nomatch) 1334887Schin { 1344887Schin free(p); 1354887Schin pp.state = old_state; 1364887Schin pp.token = old_token; 1374887Schin PUSH_TUPLE(sym, tp->token); 1384887Schin ret = 1; 1394887Schin goto disable; 1404887Schin } 1414887Schin } 1424887Schin else if (!(tp = tp->nomatch)) 1434887Schin break; 1444887Schin } 1454887Schin if (!tp) 1464887Schin { 1474887Schin pp.token = pp.toknxt; 1484887Schin break; 1494887Schin } 1504887Schin } 1514887Schin if ((pp.token = pp.toknxt) > q) 1524887Schin { 1534887Schin c = pp.token - p; 1544887Schin p = newof(p, char, n += MAXTOKEN, 0); 1554887Schin q = p + n - MAXTOKEN; 1564887Schin pp.token = p + c; 1574887Schin } 1584887Schin *pp.token++ = ' '; 1594887Schin } 1604887Schin if (pp.token > p && *(pp.token - 1) == ' ') 1614887Schin pp.token--; 1624887Schin if (pp.hidden != old_hidden) 1634887Schin *pp.token++ = '\n'; 1644887Schin else 1654887Schin *pp.token++ = ' '; 1664887Schin *pp.token = 0; 1674887Schin pp.state = old_state; 1684887Schin pp.token = old_token; 1694887Schin if (*p) 1704887Schin PUSH_RESCAN(p); 1714887Schin else 1724887Schin free(p); 1734887Schin if (!mac->value) 1744887Schin goto disable; 1754887Schin } 1764887Schin if (sym->flags & SYM_FUNCTION) 1774887Schin { 1784887Schin /* 1794887Schin * a quick and dirty '(' peek to avoid possibly 1804887Schin * inappropriate ungetchr()'s below 1814887Schin */ 1824887Schin 1834887Schin for (p = pp.in->nextchr; isspace(*p); p++); 1844887Schin if ((c = *p) != '(' && c != '/' && c != 0 && c != MARK) 1854887Schin goto disable; 1864887Schin old_token = pp.token; 1874887Schin mp = pp.macp->next; 1884887Schin if ((pp.token = (char*)&mp->arg[mac->arity + 1]) > pp.maxmac) 1894887Schin error(3, "%s: too many nested function-like macros", sym->name); 1904887Schin old_hidden = pp.hidden; 1914887Schin old_state = pp.state; 1924887Schin pp.state |= DEFINITION|FILEPOP|NOSPACE; 1934887Schin while ((c = pplex()) == '\n') 1944887Schin { 1954887Schin pp.hidden++; 1964887Schin pp.state |= HIDDEN|NEWLINE; 1974887Schin old_state |= HIDDEN|NEWLINE; 1984887Schin error_info.line++; 1994887Schin } 2004887Schin if (c != '(') 2014887Schin { 2024887Schin pp.state = old_state; 2034887Schin if (c) 2044887Schin { 2054887Schin p = pp.toknxt; 2064887Schin while (p > pp.token) 2074887Schin ungetchr(*--p); 2084887Schin #if COMPATIBLE 2094887Schin if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) 2104887Schin error(1, "%s: macro arguments omitted", sym->name); 2114887Schin #endif 2124887Schin if (c == T_ID && !(pp.state & HIDDEN)) 2134887Schin ungetchr(' '); 2144887Schin } 2154887Schin if (pp.hidden != old_hidden) 2164887Schin { 2174887Schin ungetchr('\n'); 2184887Schin error_info.line--; 2194887Schin if (pp.hidden && !--pp.hidden) 2204887Schin pp.state &= ~HIDDEN; 2214887Schin } 2224887Schin pp.token = old_token; 2234887Schin goto disable; 2244887Schin } 2254887Schin pp.state = old_state; 2264887Schin 2274887Schin /* 2284887Schin * arg[i][-1] is an extra char for each actual i 2294887Schin * for a possible ungetchr('"') during IN_QUOTE 2304887Schin * arg[i][-1]==0 if arg i need not be expanded 2314887Schin * arg[0][-2] holds the actual arg count 2324887Schin */ 2334887Schin 2344887Schin c = 0; 2354887Schin m = 0; 2364887Schin n = 0; 2374887Schin mp = pp.macp->next; 2384887Schin p = pp.token = (char*)&mp->arg[mac->arity + 1]; 2394887Schin pp.state |= COLLECTING|NOEXPAND; 2404887Schin pp.state &= ~FILEPOP; 2414887Schin sym->flags |= SYM_ACTIVE; 2424887Schin old_in = pp.in; 2434887Schin last_line = error_info.line; 2444887Schin last_file = error_info.file; 2454887Schin mp->line = error_info.line; 2464887Schin #if MACKEYARGS 2474887Schin if (pp.option & KEYARGS) 2484887Schin { 2494887Schin for (c = 0; c < mac->arity; c++) 2504887Schin mp->arg[c] = mac->args.key[c].value + 1; 2514887Schin mp->arg[0]++; 2524887Schin } 2534887Schin else 2544887Schin #endif 2554887Schin { 2564887Schin *++p = ' '; 2574887Schin mp->arg[0] = ++p; 2584887Schin } 2594887Schin #if MACKEYARGS 2604887Schin keyarg: 2614887Schin if (pp.option & KEYARGS) 2624887Schin { 2634887Schin pp.state |= NOSPACE; 2644887Schin switch (pplex()) 2654887Schin { 2664887Schin case T_ID: 2674887Schin break; 2684887Schin case ')': /* no actual key args */ 2694887Schin if (!(pp.state & NOEXPAND)) 2704887Schin pp.state |= NOEXPAND; 2714887Schin for (c = 0; c < mac->arity; c++) 2724887Schin mp->arg[c][-1] = 0; 2734887Schin c = 0; 2744887Schin goto endactuals; 2754887Schin default: 2764887Schin error(3, "%s: invalid keyword macro argument", pp.token); 2774887Schin break; 2784887Schin } 2794887Schin for (c = 0; c < mac->arity; c++) 2804887Schin if (streq(pp.token, mac->args.key[c].name)) break; 2814887Schin if (c >= mac->arity) 2824887Schin error(2, "%s: invalid macro argument keyword", pp.token); 2834887Schin if (pplex() != '=') 2844887Schin error(2, "= expected in keyword macro argument"); 2854887Schin pp.state &= ~NOSPACE; 2864887Schin if (!c) 2874887Schin p++; 2884887Schin pp.token = mp->arg[c] = ++p; 2894887Schin } 2904887Schin #endif 2914887Schin for (;;) 2924887Schin { 2934887Schin if ((pp.mactop = pp.token = p) >= pp.maxmac) 2944887Schin error(3, "%s: too many nested function-like macros", sym->name); 2954887Schin switch (pplex()) 2964887Schin { 2974887Schin case '(': 2984887Schin n++; 2994887Schin break; 3004887Schin case ')': 3014887Schin if (!n--) 3024887Schin { 3034887Schin if (p > mp->arg[c] && *(p - 1) == ' ') 3044887Schin p--; 3054887Schin if (p > mp->arg[c] && *(p - 1) == '\\') 3064887Schin { 3074887Schin for (q = mp->arg[c]; q < p; q++) 3084887Schin if (*q == '\\') 3094887Schin q++; 3104887Schin if (q > p) 3114887Schin *p++ = '\\'; 3124887Schin } 3134887Schin #if MACKEYARGS 3144887Schin *p = 0; 3154887Schin m++; 3164887Schin #endif 3174887Schin goto endactuals; 3184887Schin } 3194887Schin break; 3204887Schin case ',': 3214887Schin if (!n && (m++, (c < mac->arity - 1 || !(sym->flags & SYM_VARIADIC)))) 3224887Schin { 3234887Schin if (p > mp->arg[c] && *(p - 1) == ' ') 3244887Schin p--; 3254887Schin *p++ = 0; 3264887Schin if (!(pp.state & NOEXPAND)) 3274887Schin pp.state |= NOEXPAND; 3284887Schin else 3294887Schin mp->arg[c][-1] = 0; 3304887Schin #if MACKEYARGS 3314887Schin if (pp.option & KEYARGS) 3324887Schin { 3334887Schin pp.token = p + 1; 3344887Schin goto keyarg; 3354887Schin } 3364887Schin #endif 3374887Schin { 3384887Schin if ((pp.state & STRICT) && p == mp->arg[c]) 3394887Schin error(1, "%s: macro call argument %d is null", sym->name, c + 1); 3404887Schin if (c < mac->arity) 3414887Schin c++; 3424887Schin *p++ = ' '; 3434887Schin } 3444887Schin pp.toknxt = mp->arg[c] = p; 3454887Schin } 3464887Schin break; 3474887Schin case 0: 3484887Schin if (pp.in == old_in) 3494887Schin kp = 0; 3504887Schin else 3514887Schin for (kp = pp.in; kp && kp != old_in; kp = kp->prev); 3524887Schin if (!kp) 3534887Schin { 3544887Schin error( 3554887Schin #if COMPATIBLE 3564887Schin (pp.state & COMPATIBILITY) ? 3 : 3574887Schin #endif 3584887Schin 2, "%s: %s in macro argument list", sym->name, pptokchr(0)); 3594887Schin goto endactuals; 3604887Schin } 3614887Schin continue; 3624887Schin case '\n': 3634887Schin pp.state |= HIDDEN; 3644887Schin error_info.line++; 3654887Schin pp.hidden++; 3664887Schin /*FALLTHROUGH*/ 3674887Schin case ' ': 3684887Schin if (p > mp->arg[c] && *(p - 1) != ' ') *p++ = ' '; 3694887Schin continue; 3704887Schin } 3714887Schin p = pp.toknxt; 3724887Schin if (error_info.line != last_line) 3734887Schin { 3744887Schin SETLINE(p, error_info.line); 3754887Schin last_line = error_info.line; 3764887Schin } 3774887Schin if (error_info.file != last_file) 3784887Schin { 3794887Schin SETFILE(p, error_info.file); 3804887Schin last_file = error_info.file; 3814887Schin } 3824887Schin } 3834887Schin endactuals: 3844887Schin if (pp.state & NOEXPAND) 3854887Schin mp->arg[c][-1] = 0; 3864887Schin pp.token = old_token; 3874887Schin if (pp.in != old_in) 3884887Schin { 3894887Schin for (kp = pp.in; kp && kp != old_in; kp = kp->prev); 3904887Schin if (kp) 3914887Schin error(2, "%s: macro call starts and ends in different files", sym->name); 3924887Schin } 3934887Schin pp.state &= ~(COLLECTING|FILEPOP|NOEXPAND); 3944887Schin sym->flags &= ~SYM_ACTIVE; 3954887Schin #if MACKEYARGS 3964887Schin if (!(pp.option & KEYARGS)) 3974887Schin #endif 3984887Schin { 3994887Schin if (p > mp->arg[0] && ++m || (sym->flags & SYM_VARIADIC)) 4004887Schin c++; 4014887Schin if (c != mac->arity && !(sym->flags & SYM_EMPTY)) 4024887Schin { 4034887Schin n = mac->arity; 4044887Schin if (!(sym->flags & SYM_VARIADIC)) 4054887Schin error(1, "%s: %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s"); 4064887Schin else if (c < --n) 4074887Schin error(1, "%s: at least %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s"); 4084887Schin #if COMPATIBLE 4094887Schin if (!c && (pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT)) 4104887Schin goto disable; 4114887Schin #endif 4124887Schin } 4134887Schin if (!c) 4144887Schin ++c; 4154887Schin while (c < mac->arity) 4164887Schin mp->arg[c++] = (char*)"\0" + 1; 4174887Schin } 4184887Schin mp->arg[0][-2] = m; 4194887Schin *p++ = 0; 4204887Schin nextframe(mp, p); 4214887Schin count(function); 4224887Schin } 4234887Schin if (!tok && (sym->flags & SYM_NOEXPAND)) 4244887Schin { 4254887Schin if (sym->flags & SYM_FUNCTION) 4264887Schin popframe(mp); 4274887Schin ret = !mac->size; 4284887Schin } 4294887Schin else if (!(pp.state & HEADER) || (pp.option & HEADEREXPANDALL) || pp.in->type != IN_COPY) 4304887Schin { 4314887Schin if (sym->flags & SYM_MULTILINE) 4324887Schin PUSH_MULTILINE(sym); 4334887Schin else 4344887Schin PUSH_MACRO(sym); 4354887Schin ret = 1; 4364887Schin } 4374887Schin } 4384887Schin disable: 4394887Schin 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)) 4404887Schin { 4414887Schin struct ppinstk* inp; 4424887Schin 4434887Schin for (inp = pp.in; inp->type != IN_FILE && inp->prev; inp = inp->prev); 4444887Schin sfsprintf(pp.hidebuf, MAXTOKEN, "_%d_%s_hIDe", inp->index, sym->name); 4454887Schin PUSH_STRING(pp.hidebuf); 4464887Schin ret = 1; 4474887Schin } 4484887Schin pp.state &= ~NEWLINE; 4494887Schin pp.in->flags |= IN_tokens; 4504887Schin count(token); 4514887Schin return ret; 4524887Schin } 453