13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <stdio.h> 43e12c5d1SDavid du Colombier #include "cpp.h" 53e12c5d1SDavid du Colombier 63e12c5d1SDavid du Colombier /* 73e12c5d1SDavid du Colombier * do a macro definition. tp points to the name being defined in the line 83e12c5d1SDavid du Colombier */ 93e12c5d1SDavid du Colombier void 103e12c5d1SDavid du Colombier dodefine(Tokenrow *trp) 113e12c5d1SDavid du Colombier { 123e12c5d1SDavid du Colombier Token *tp; 133e12c5d1SDavid du Colombier Nlist *np; 143e12c5d1SDavid du Colombier Tokenrow *def, *args; 15*3b56890dSDavid du Colombier int dots; 163e12c5d1SDavid du Colombier 17*3b56890dSDavid du Colombier dots = 0; 183e12c5d1SDavid du Colombier tp = trp->tp+1; 193e12c5d1SDavid du Colombier if (tp>=trp->lp || tp->type!=NAME) { 203e12c5d1SDavid du Colombier error(ERROR, "#defined token is not a name"); 213e12c5d1SDavid du Colombier return; 223e12c5d1SDavid du Colombier } 233e12c5d1SDavid du Colombier np = lookup(tp, 1); 243e12c5d1SDavid du Colombier if (np->flag&ISUNCHANGE) { 253e12c5d1SDavid du Colombier error(ERROR, "#defined token %t can't be redefined", tp); 263e12c5d1SDavid du Colombier return; 273e12c5d1SDavid du Colombier } 283e12c5d1SDavid du Colombier /* collect arguments */ 293e12c5d1SDavid du Colombier tp += 1; 303e12c5d1SDavid du Colombier args = NULL; 313e12c5d1SDavid du Colombier if (tp<trp->lp && tp->type==LP && tp->wslen==0) { 323e12c5d1SDavid du Colombier /* macro with args */ 333e12c5d1SDavid du Colombier int narg = 0; 343e12c5d1SDavid du Colombier tp += 1; 353e12c5d1SDavid du Colombier args = new(Tokenrow); 363e12c5d1SDavid du Colombier maketokenrow(2, args); 373e12c5d1SDavid du Colombier if (tp->type!=RP) { 383e12c5d1SDavid du Colombier int err = 0; 393e12c5d1SDavid du Colombier for (;;) { 403e12c5d1SDavid du Colombier Token *atp; 41*3b56890dSDavid du Colombier if (tp->type == ELLIPS) 42*3b56890dSDavid du Colombier dots++; 43*3b56890dSDavid du Colombier else if (tp->type!=NAME) { 443e12c5d1SDavid du Colombier err++; 453e12c5d1SDavid du Colombier break; 463e12c5d1SDavid du Colombier } 473e12c5d1SDavid du Colombier if (narg>=args->max) 483e12c5d1SDavid du Colombier growtokenrow(args); 493e12c5d1SDavid du Colombier for (atp=args->bp; atp<args->lp; atp++) 503e12c5d1SDavid du Colombier if (atp->len==tp->len 513e12c5d1SDavid du Colombier && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0) 523e12c5d1SDavid du Colombier error(ERROR, "Duplicate macro argument"); 533e12c5d1SDavid du Colombier *args->lp++ = *tp; 543e12c5d1SDavid du Colombier narg++; 553e12c5d1SDavid du Colombier tp += 1; 563e12c5d1SDavid du Colombier if (tp->type==RP) 573e12c5d1SDavid du Colombier break; 58*3b56890dSDavid du Colombier if (dots) 59*3b56890dSDavid du Colombier error(ERROR, "arguments after '...' in macro"); 603e12c5d1SDavid du Colombier if (tp->type!=COMMA) { 613e12c5d1SDavid du Colombier err++; 623e12c5d1SDavid du Colombier break; 633e12c5d1SDavid du Colombier } 643e12c5d1SDavid du Colombier tp += 1; 653e12c5d1SDavid du Colombier } 663e12c5d1SDavid du Colombier if (err) { 673e12c5d1SDavid du Colombier error(ERROR, "Syntax error in macro parameters"); 683e12c5d1SDavid du Colombier return; 693e12c5d1SDavid du Colombier } 703e12c5d1SDavid du Colombier } 713e12c5d1SDavid du Colombier tp += 1; 723e12c5d1SDavid du Colombier } 733e12c5d1SDavid du Colombier trp->tp = tp; 743e12c5d1SDavid du Colombier if (((trp->lp)-1)->type==NL) 753e12c5d1SDavid du Colombier trp->lp -= 1; 763e12c5d1SDavid du Colombier def = normtokenrow(trp); 773e12c5d1SDavid du Colombier if (np->flag&ISDEFINED) { 783e12c5d1SDavid du Colombier if (comparetokens(def, np->vp) 793e12c5d1SDavid du Colombier || (np->ap==NULL) != (args==NULL) 803e12c5d1SDavid du Colombier || np->ap && comparetokens(args, np->ap)) 81219b2ee8SDavid du Colombier error(ERROR, "Macro redefinition of %t", trp->bp+2); 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier if (args) { 843e12c5d1SDavid du Colombier Tokenrow *tap; 853e12c5d1SDavid du Colombier tap = normtokenrow(args); 863e12c5d1SDavid du Colombier dofree(args->bp); 873e12c5d1SDavid du Colombier args = tap; 883e12c5d1SDavid du Colombier } 893e12c5d1SDavid du Colombier np->ap = args; 903e12c5d1SDavid du Colombier np->vp = def; 913e12c5d1SDavid du Colombier np->flag |= ISDEFINED; 92*3b56890dSDavid du Colombier if(dots) 93*3b56890dSDavid du Colombier np->flag |= ISVARMAC; 943e12c5d1SDavid du Colombier } 953e12c5d1SDavid du Colombier 963e12c5d1SDavid du Colombier /* 973e12c5d1SDavid du Colombier * Definition received via -D or -U 983e12c5d1SDavid du Colombier */ 993e12c5d1SDavid du Colombier void 1003e12c5d1SDavid du Colombier doadefine(Tokenrow *trp, int type) 1013e12c5d1SDavid du Colombier { 1023e12c5d1SDavid du Colombier Nlist *np; 1039a747e4fSDavid du Colombier static unsigned char one[] = "1"; 1049a747e4fSDavid du Colombier static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, one }}; 105bd389b36SDavid du Colombier static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 }; 1063e12c5d1SDavid du Colombier 1073e12c5d1SDavid du Colombier trp->tp = trp->bp; 1083e12c5d1SDavid du Colombier if (type=='U') { 1093e12c5d1SDavid du Colombier if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME) 1103e12c5d1SDavid du Colombier goto syntax; 1113e12c5d1SDavid du Colombier if ((np = lookup(trp->tp, 0)) == NULL) 1123e12c5d1SDavid du Colombier return; 1133e12c5d1SDavid du Colombier np->flag &= ~ISDEFINED; 1143e12c5d1SDavid du Colombier return; 1153e12c5d1SDavid du Colombier } 1163e12c5d1SDavid du Colombier if (trp->tp >= trp->lp || trp->tp->type!=NAME) 1173e12c5d1SDavid du Colombier goto syntax; 1183e12c5d1SDavid du Colombier np = lookup(trp->tp, 1); 1193e12c5d1SDavid du Colombier np->flag |= ISDEFINED; 1203e12c5d1SDavid du Colombier trp->tp += 1; 1213e12c5d1SDavid du Colombier if (trp->tp >= trp->lp || trp->tp->type==END) { 1223e12c5d1SDavid du Colombier np->vp = &onetr; 1233e12c5d1SDavid du Colombier return; 1243e12c5d1SDavid du Colombier } 1253e12c5d1SDavid du Colombier if (trp->tp->type!=ASGN) 1263e12c5d1SDavid du Colombier goto syntax; 1273e12c5d1SDavid du Colombier trp->tp += 1; 1283e12c5d1SDavid du Colombier if ((trp->lp-1)->type == END) 1293e12c5d1SDavid du Colombier trp->lp -= 1; 1303e12c5d1SDavid du Colombier np->vp = normtokenrow(trp); 1313e12c5d1SDavid du Colombier return; 1323e12c5d1SDavid du Colombier syntax: 1333e12c5d1SDavid du Colombier error(FATAL, "Illegal -D or -U argument %r", trp); 1343e12c5d1SDavid du Colombier } 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier /* 1373e12c5d1SDavid du Colombier * Do macro expansion in a row of tokens. 1383e12c5d1SDavid du Colombier * Flag is NULL if more input can be gathered. 1393e12c5d1SDavid du Colombier */ 1403e12c5d1SDavid du Colombier void 1413e12c5d1SDavid du Colombier expandrow(Tokenrow *trp, char *flag) 1423e12c5d1SDavid du Colombier { 1433e12c5d1SDavid du Colombier Token *tp; 1443e12c5d1SDavid du Colombier Nlist *np; 1453e12c5d1SDavid du Colombier 1463e12c5d1SDavid du Colombier if (flag) 1473e12c5d1SDavid du Colombier setsource(flag, -1, ""); 1483e12c5d1SDavid du Colombier for (tp = trp->tp; tp<trp->lp; ) { 1493e12c5d1SDavid du Colombier if (tp->type!=NAME 1503e12c5d1SDavid du Colombier || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0 1513e12c5d1SDavid du Colombier || (np = lookup(tp, 0))==NULL 1523e12c5d1SDavid du Colombier || (np->flag&(ISDEFINED|ISMAC))==0 1533e12c5d1SDavid du Colombier || tp->hideset && checkhideset(tp->hideset, np)) { 1543e12c5d1SDavid du Colombier tp++; 1553e12c5d1SDavid du Colombier continue; 1563e12c5d1SDavid du Colombier } 1573e12c5d1SDavid du Colombier trp->tp = tp; 158bd389b36SDavid du Colombier if (np->val==KDEFINED) { 159bd389b36SDavid du Colombier tp->type = DEFINED; 160bd389b36SDavid du Colombier if ((tp+1)<trp->lp && (tp+1)->type==NAME) 161bd389b36SDavid du Colombier (tp+1)->type = NAME1; 162bd389b36SDavid du Colombier else if ((tp+3)<trp->lp && (tp+1)->type==LP 163bd389b36SDavid du Colombier && (tp+2)->type==NAME && (tp+3)->type==RP) 164bd389b36SDavid du Colombier (tp+2)->type = NAME1; 165bd389b36SDavid du Colombier else 166bd389b36SDavid du Colombier error(ERROR, "Incorrect syntax for `defined'"); 167bd389b36SDavid du Colombier tp++; 168bd389b36SDavid du Colombier continue; 169bd389b36SDavid du Colombier } 1703e12c5d1SDavid du Colombier if (np->flag&ISMAC) 1713e12c5d1SDavid du Colombier builtin(trp, np->val); 1723e12c5d1SDavid du Colombier else { 1733e12c5d1SDavid du Colombier expand(trp, np); 1743e12c5d1SDavid du Colombier } 1753e12c5d1SDavid du Colombier tp = trp->tp; 1763e12c5d1SDavid du Colombier } 1773e12c5d1SDavid du Colombier if (flag) 1783e12c5d1SDavid du Colombier unsetsource(); 1793e12c5d1SDavid du Colombier } 1803e12c5d1SDavid du Colombier 1813e12c5d1SDavid du Colombier /* 1823e12c5d1SDavid du Colombier * Expand the macro whose name is np, at token trp->tp, in the tokenrow. 1833e12c5d1SDavid du Colombier * Return trp->tp at the first token next to be expanded 1843e12c5d1SDavid du Colombier * (ordinarily the beginning of the expansion) 1853e12c5d1SDavid du Colombier */ 1863e12c5d1SDavid du Colombier void 1873e12c5d1SDavid du Colombier expand(Tokenrow *trp, Nlist *np) 1883e12c5d1SDavid du Colombier { 1893e12c5d1SDavid du Colombier Tokenrow ntr; 1903e12c5d1SDavid du Colombier int ntokc, narg, i; 1913e12c5d1SDavid du Colombier Token *tp; 1923e12c5d1SDavid du Colombier Tokenrow *atr[NARG+1]; 1933e12c5d1SDavid du Colombier int hs; 194bd389b36SDavid du Colombier 1953e12c5d1SDavid du Colombier copytokenrow(&ntr, np->vp); /* copy macro value */ 1963e12c5d1SDavid du Colombier if (np->ap==NULL) /* parameterless */ 1973e12c5d1SDavid du Colombier ntokc = 1; 1983e12c5d1SDavid du Colombier else { 199*3b56890dSDavid du Colombier ntokc = gatherargs(trp, atr, (np->flag&ISVARMAC) ? rowlen(np->ap) : 0, &narg); 2003e12c5d1SDavid du Colombier if (narg<0) { /* not actually a call (no '(') */ 20180ee5cbfSDavid du Colombier /* error(WARNING, "%d %r\n", narg, trp); */ 20280ee5cbfSDavid du Colombier /* gatherargs has already pushed trp->tr to the next token */ 2033e12c5d1SDavid du Colombier return; 2043e12c5d1SDavid du Colombier } 2053e12c5d1SDavid du Colombier if (narg != rowlen(np->ap)) { 2063e12c5d1SDavid du Colombier error(ERROR, "Disagreement in number of macro arguments"); 2073e12c5d1SDavid du Colombier trp->tp->hideset = newhideset(trp->tp->hideset, np); 2083e12c5d1SDavid du Colombier trp->tp += ntokc; 2093e12c5d1SDavid du Colombier return; 2103e12c5d1SDavid du Colombier } 2113e12c5d1SDavid du Colombier substargs(np, &ntr, atr); /* put args into replacement */ 2123e12c5d1SDavid du Colombier for (i=0; i<narg; i++) { 2133e12c5d1SDavid du Colombier dofree(atr[i]->bp); 2143e12c5d1SDavid du Colombier dofree(atr[i]); 2153e12c5d1SDavid du Colombier } 2163e12c5d1SDavid du Colombier } 2173e12c5d1SDavid du Colombier doconcat(&ntr); /* execute ## operators */ 2183e12c5d1SDavid du Colombier hs = newhideset(trp->tp->hideset, np); 2193e12c5d1SDavid du Colombier for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */ 2203e12c5d1SDavid du Colombier if (tp->type==NAME) { 2213e12c5d1SDavid du Colombier if (tp->hideset==0) 2223e12c5d1SDavid du Colombier tp->hideset = hs; 2233e12c5d1SDavid du Colombier else 2243e12c5d1SDavid du Colombier tp->hideset = unionhideset(tp->hideset, hs); 2253e12c5d1SDavid du Colombier } 2263e12c5d1SDavid du Colombier } 2273e12c5d1SDavid du Colombier ntr.tp = ntr.bp; 2283e12c5d1SDavid du Colombier insertrow(trp, ntokc, &ntr); 2293e12c5d1SDavid du Colombier trp->tp -= rowlen(&ntr); 2303e12c5d1SDavid du Colombier dofree(ntr.bp); 2313e12c5d1SDavid du Colombier return; 2323e12c5d1SDavid du Colombier } 2333e12c5d1SDavid du Colombier 2343e12c5d1SDavid du Colombier /* 2353e12c5d1SDavid du Colombier * Gather an arglist, starting in trp with tp pointing at the macro name. 2363e12c5d1SDavid du Colombier * Return total number of tokens passed, stash number of args found. 2373e12c5d1SDavid du Colombier * trp->tp is not changed relative to the tokenrow. 2383e12c5d1SDavid du Colombier */ 2393e12c5d1SDavid du Colombier int 240*3b56890dSDavid du Colombier gatherargs(Tokenrow *trp, Tokenrow **atr, int dots, int *narg) 2413e12c5d1SDavid du Colombier { 2423e12c5d1SDavid du Colombier int parens = 1; 2433e12c5d1SDavid du Colombier int ntok = 0; 2443e12c5d1SDavid du Colombier Token *bp, *lp; 2453e12c5d1SDavid du Colombier Tokenrow ttr; 2463e12c5d1SDavid du Colombier int ntokp; 2477dd7cddfSDavid du Colombier int needspace; 2483e12c5d1SDavid du Colombier 2493e12c5d1SDavid du Colombier *narg = -1; /* means that there is no macro call */ 2503e12c5d1SDavid du Colombier /* look for the ( */ 2513e12c5d1SDavid du Colombier for (;;) { 2523e12c5d1SDavid du Colombier trp->tp++; 2533e12c5d1SDavid du Colombier ntok++; 2543e12c5d1SDavid du Colombier if (trp->tp >= trp->lp) { 2553e12c5d1SDavid du Colombier gettokens(trp, 0); 2563e12c5d1SDavid du Colombier if ((trp->lp-1)->type==END) { 25780ee5cbfSDavid du Colombier /* error(WARNING, "reach END\n"); */ 2583e12c5d1SDavid du Colombier trp->lp -= 1; 25980ee5cbfSDavid du Colombier if (*narg>=0) 2603e12c5d1SDavid du Colombier trp->tp -= ntok; 2613e12c5d1SDavid du Colombier return ntok; 2623e12c5d1SDavid du Colombier } 2633e12c5d1SDavid du Colombier } 2643e12c5d1SDavid du Colombier if (trp->tp->type==LP) 2653e12c5d1SDavid du Colombier break; 2663e12c5d1SDavid du Colombier if (trp->tp->type!=NL) 2673e12c5d1SDavid du Colombier return ntok; 2683e12c5d1SDavid du Colombier } 2693e12c5d1SDavid du Colombier *narg = 0; 2703e12c5d1SDavid du Colombier ntok++; 2713e12c5d1SDavid du Colombier ntokp = ntok; 2723e12c5d1SDavid du Colombier trp->tp++; 2733e12c5d1SDavid du Colombier /* search for the terminating ), possibly extending the row */ 2747dd7cddfSDavid du Colombier needspace = 0; 2753e12c5d1SDavid du Colombier while (parens>0) { 2763e12c5d1SDavid du Colombier if (trp->tp >= trp->lp) 2773e12c5d1SDavid du Colombier gettokens(trp, 0); 2787dd7cddfSDavid du Colombier if (needspace) { 2797dd7cddfSDavid du Colombier needspace = 0; 2807dd7cddfSDavid du Colombier makespace(trp); 2817dd7cddfSDavid du Colombier } 2823e12c5d1SDavid du Colombier if (trp->tp->type==END) { 2833e12c5d1SDavid du Colombier trp->lp -= 1; 2843e12c5d1SDavid du Colombier trp->tp -= ntok; 2853e12c5d1SDavid du Colombier error(ERROR, "EOF in macro arglist"); 2863e12c5d1SDavid du Colombier return ntok; 2873e12c5d1SDavid du Colombier } 2883e12c5d1SDavid du Colombier if (trp->tp->type==NL) { 2893e12c5d1SDavid du Colombier trp->tp += 1; 2903e12c5d1SDavid du Colombier adjustrow(trp, -1); 2913e12c5d1SDavid du Colombier trp->tp -= 1; 2923e12c5d1SDavid du Colombier makespace(trp); 2937dd7cddfSDavid du Colombier needspace = 1; 2943e12c5d1SDavid du Colombier continue; 2953e12c5d1SDavid du Colombier } 2963e12c5d1SDavid du Colombier if (trp->tp->type==LP) 2973e12c5d1SDavid du Colombier parens++; 2983e12c5d1SDavid du Colombier else if (trp->tp->type==RP) 2993e12c5d1SDavid du Colombier parens--; 3003e12c5d1SDavid du Colombier trp->tp++; 3013e12c5d1SDavid du Colombier ntok++; 3023e12c5d1SDavid du Colombier } 3033e12c5d1SDavid du Colombier trp->tp -= ntok; 3043e12c5d1SDavid du Colombier /* Now trp->tp won't move underneath us */ 3053e12c5d1SDavid du Colombier lp = bp = trp->tp+ntokp; 3063e12c5d1SDavid du Colombier for (; parens>=0; lp++) { 3073e12c5d1SDavid du Colombier if (lp->type == LP) { 3083e12c5d1SDavid du Colombier parens++; 3093e12c5d1SDavid du Colombier continue; 3103e12c5d1SDavid du Colombier } 3113e12c5d1SDavid du Colombier if (lp->type==RP) 3123e12c5d1SDavid du Colombier parens--; 3133e12c5d1SDavid du Colombier if (lp->type==DSHARP) 3143e12c5d1SDavid du Colombier lp->type = DSHARP1; /* ## not special in arg */ 315*3b56890dSDavid du Colombier if ((lp->type==COMMA && parens==0) || (parens<0 && (lp-1)->type!=LP)) { 316*3b56890dSDavid du Colombier if (lp->type == COMMA && dots && *narg == dots-1) 317*3b56890dSDavid du Colombier continue; 3183e12c5d1SDavid du Colombier if (*narg>=NARG-1) 3193e12c5d1SDavid du Colombier error(FATAL, "Sorry, too many macro arguments"); 3203e12c5d1SDavid du Colombier ttr.bp = ttr.tp = bp; 3213e12c5d1SDavid du Colombier ttr.lp = lp; 3223e12c5d1SDavid du Colombier atr[(*narg)++] = normtokenrow(&ttr); 3233e12c5d1SDavid du Colombier bp = lp+1; 3243e12c5d1SDavid du Colombier } 3253e12c5d1SDavid du Colombier } 3263e12c5d1SDavid du Colombier return ntok; 3273e12c5d1SDavid du Colombier } 3283e12c5d1SDavid du Colombier 3293e12c5d1SDavid du Colombier /* 3303e12c5d1SDavid du Colombier * substitute the argument list into the replacement string 3313e12c5d1SDavid du Colombier * This would be simple except for ## and # 3323e12c5d1SDavid du Colombier */ 3333e12c5d1SDavid du Colombier void 3343e12c5d1SDavid du Colombier substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr) 3353e12c5d1SDavid du Colombier { 3363e12c5d1SDavid du Colombier Tokenrow tatr; 3373e12c5d1SDavid du Colombier Token *tp; 3383e12c5d1SDavid du Colombier int ntok, argno; 3393e12c5d1SDavid du Colombier 3403e12c5d1SDavid du Colombier for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) { 3413e12c5d1SDavid du Colombier if (rtr->tp->type==SHARP) { /* string operator */ 3423e12c5d1SDavid du Colombier tp = rtr->tp; 3433e12c5d1SDavid du Colombier rtr->tp += 1; 3443e12c5d1SDavid du Colombier if ((argno = lookuparg(np, rtr->tp))<0) { 3453e12c5d1SDavid du Colombier error(ERROR, "# not followed by macro parameter"); 3463e12c5d1SDavid du Colombier continue; 3473e12c5d1SDavid du Colombier } 3483e12c5d1SDavid du Colombier ntok = 1 + (rtr->tp - tp); 3493e12c5d1SDavid du Colombier rtr->tp = tp; 3503e12c5d1SDavid du Colombier insertrow(rtr, ntok, stringify(atr[argno])); 3513e12c5d1SDavid du Colombier continue; 3523e12c5d1SDavid du Colombier } 3533e12c5d1SDavid du Colombier if (rtr->tp->type==NAME 3543e12c5d1SDavid du Colombier && (argno = lookuparg(np, rtr->tp)) >= 0) { 3557dd7cddfSDavid du Colombier if (rtr->tp < rtr->bp) 3567dd7cddfSDavid du Colombier error(ERROR, "access out of bounds"); 3573e12c5d1SDavid du Colombier if ((rtr->tp+1)->type==DSHARP 358bd389b36SDavid du Colombier || rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP) 3593e12c5d1SDavid du Colombier insertrow(rtr, 1, atr[argno]); 3603e12c5d1SDavid du Colombier else { 3613e12c5d1SDavid du Colombier copytokenrow(&tatr, atr[argno]); 3623e12c5d1SDavid du Colombier expandrow(&tatr, "<macro>"); 3633e12c5d1SDavid du Colombier insertrow(rtr, 1, &tatr); 3643e12c5d1SDavid du Colombier dofree(tatr.bp); 3653e12c5d1SDavid du Colombier } 3663e12c5d1SDavid du Colombier continue; 3673e12c5d1SDavid du Colombier } 3683e12c5d1SDavid du Colombier rtr->tp++; 3693e12c5d1SDavid du Colombier } 3703e12c5d1SDavid du Colombier } 3713e12c5d1SDavid du Colombier 3723e12c5d1SDavid du Colombier /* 3733e12c5d1SDavid du Colombier * Evaluate the ## operators in a tokenrow 3743e12c5d1SDavid du Colombier */ 3753e12c5d1SDavid du Colombier void 3763e12c5d1SDavid du Colombier doconcat(Tokenrow *trp) 3773e12c5d1SDavid du Colombier { 3783e12c5d1SDavid du Colombier Token *ltp, *ntp; 3793e12c5d1SDavid du Colombier Tokenrow ntr; 3803e12c5d1SDavid du Colombier int len; 3813e12c5d1SDavid du Colombier 3823e12c5d1SDavid du Colombier for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) { 3833e12c5d1SDavid du Colombier if (trp->tp->type==DSHARP1) 3843e12c5d1SDavid du Colombier trp->tp->type = DSHARP; 3853e12c5d1SDavid du Colombier else if (trp->tp->type==DSHARP) { 3863e12c5d1SDavid du Colombier char tt[128]; 3873e12c5d1SDavid du Colombier ltp = trp->tp-1; 3883e12c5d1SDavid du Colombier ntp = trp->tp+1; 3893e12c5d1SDavid du Colombier if (ltp<trp->bp || ntp>=trp->lp) { 3903e12c5d1SDavid du Colombier error(ERROR, "## occurs at border of replacement"); 3913e12c5d1SDavid du Colombier continue; 3923e12c5d1SDavid du Colombier } 3933e12c5d1SDavid du Colombier len = ltp->len + ntp->len; 3943e12c5d1SDavid du Colombier strncpy((char*)tt, (char*)ltp->t, ltp->len); 3953e12c5d1SDavid du Colombier strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len); 3963e12c5d1SDavid du Colombier tt[len] = '\0'; 3973e12c5d1SDavid du Colombier setsource("<##>", -1, tt); 3983e12c5d1SDavid du Colombier maketokenrow(3, &ntr); 3993e12c5d1SDavid du Colombier gettokens(&ntr, 1); 4003e12c5d1SDavid du Colombier unsetsource(); 4013e12c5d1SDavid du Colombier if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS) 4023e12c5d1SDavid du Colombier error(WARNING, "Bad token %r produced by ##", &ntr); 4033e12c5d1SDavid du Colombier ntr.lp = ntr.bp+1; 4043e12c5d1SDavid du Colombier trp->tp = ltp; 4053e12c5d1SDavid du Colombier makespace(&ntr); 4063e12c5d1SDavid du Colombier insertrow(trp, (ntp-ltp)+1, &ntr); 4073e12c5d1SDavid du Colombier dofree(ntr.bp); 4083e12c5d1SDavid du Colombier trp->tp--; 4093e12c5d1SDavid du Colombier } 4103e12c5d1SDavid du Colombier } 4113e12c5d1SDavid du Colombier } 4123e12c5d1SDavid du Colombier 4133e12c5d1SDavid du Colombier /* 4143e12c5d1SDavid du Colombier * tp is a potential parameter name of macro mac; 4153e12c5d1SDavid du Colombier * look it up in mac's arglist, and if found, return the 4163e12c5d1SDavid du Colombier * corresponding index in the argname array. Return -1 if not found. 4173e12c5d1SDavid du Colombier */ 4183e12c5d1SDavid du Colombier int 4193e12c5d1SDavid du Colombier lookuparg(Nlist *mac, Token *tp) 4203e12c5d1SDavid du Colombier { 4213e12c5d1SDavid du Colombier Token *ap; 4223e12c5d1SDavid du Colombier 4233e12c5d1SDavid du Colombier if (tp->type!=NAME || mac->ap==NULL) 4243e12c5d1SDavid du Colombier return -1; 425*3b56890dSDavid du Colombier if((mac->flag & ISVARMAC) && strcmp((char*)tp->t, "__VA_ARGS__") == 0) 426*3b56890dSDavid du Colombier return rowlen(mac->ap) - 1; 4273e12c5d1SDavid du Colombier for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) { 4283e12c5d1SDavid du Colombier if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0) 4293e12c5d1SDavid du Colombier return ap - mac->ap->bp; 4303e12c5d1SDavid du Colombier } 4313e12c5d1SDavid du Colombier return -1; 4323e12c5d1SDavid du Colombier } 4333e12c5d1SDavid du Colombier 4343e12c5d1SDavid du Colombier /* 4353e12c5d1SDavid du Colombier * Return a quoted version of the tokenrow (from # arg) 4363e12c5d1SDavid du Colombier */ 4373e12c5d1SDavid du Colombier #define STRLEN 512 4383e12c5d1SDavid du Colombier Tokenrow * 4393e12c5d1SDavid du Colombier stringify(Tokenrow *vp) 4403e12c5d1SDavid du Colombier { 4413e12c5d1SDavid du Colombier static Token t = { STRING }; 4423e12c5d1SDavid du Colombier static Tokenrow tr = { &t, &t, &t+1, 1 }; 4433e12c5d1SDavid du Colombier Token *tp; 4443e12c5d1SDavid du Colombier uchar s[STRLEN]; 4453e12c5d1SDavid du Colombier uchar *sp = s, *cp; 4463e12c5d1SDavid du Colombier int i, instring; 4473e12c5d1SDavid du Colombier 4483e12c5d1SDavid du Colombier *sp++ = '"'; 4493e12c5d1SDavid du Colombier for (tp = vp->bp; tp < vp->lp; tp++) { 4503e12c5d1SDavid du Colombier instring = tp->type==STRING || tp->type==CCON; 4513e12c5d1SDavid du Colombier if (sp+2*tp->len >= &s[STRLEN-10]) { 4523e12c5d1SDavid du Colombier error(ERROR, "Stringified macro arg is too long"); 4533e12c5d1SDavid du Colombier break; 4543e12c5d1SDavid du Colombier } 4553e12c5d1SDavid du Colombier if (tp->wslen && (tp->flag&XPWS)==0) 4563e12c5d1SDavid du Colombier *sp++ = ' '; 4573e12c5d1SDavid du Colombier for (i=0, cp=tp->t; i<tp->len; i++) { 4583e12c5d1SDavid du Colombier if (instring && (*cp=='"' || *cp=='\\')) 4593e12c5d1SDavid du Colombier *sp++ = '\\'; 4603e12c5d1SDavid du Colombier *sp++ = *cp++; 4613e12c5d1SDavid du Colombier } 4623e12c5d1SDavid du Colombier } 4633e12c5d1SDavid du Colombier *sp++ = '"'; 4643e12c5d1SDavid du Colombier *sp = '\0'; 4653e12c5d1SDavid du Colombier sp = s; 4663e12c5d1SDavid du Colombier t.len = strlen((char*)sp); 4673e12c5d1SDavid du Colombier t.t = newstring(sp, t.len, 0); 4683e12c5d1SDavid du Colombier return &tr; 4693e12c5d1SDavid du Colombier } 4703e12c5d1SDavid du Colombier 4713e12c5d1SDavid du Colombier /* 4723e12c5d1SDavid du Colombier * expand a builtin name 4733e12c5d1SDavid du Colombier */ 4743e12c5d1SDavid du Colombier void 4753e12c5d1SDavid du Colombier builtin(Tokenrow *trp, int biname) 4763e12c5d1SDavid du Colombier { 4773e12c5d1SDavid du Colombier char *op; 4783e12c5d1SDavid du Colombier Token *tp; 4793e12c5d1SDavid du Colombier Source *s; 4803e12c5d1SDavid du Colombier 4813e12c5d1SDavid du Colombier tp = trp->tp; 4823e12c5d1SDavid du Colombier trp->tp++; 4833e12c5d1SDavid du Colombier /* need to find the real source */ 4843e12c5d1SDavid du Colombier s = cursource; 4853e12c5d1SDavid du Colombier while (s && s->fd==-1) 4863e12c5d1SDavid du Colombier s = s->next; 4873e12c5d1SDavid du Colombier if (s==NULL) 4883e12c5d1SDavid du Colombier s = cursource; 4893e12c5d1SDavid du Colombier /* most are strings */ 4903e12c5d1SDavid du Colombier tp->type = STRING; 4913e12c5d1SDavid du Colombier if (tp->wslen) { 4923e12c5d1SDavid du Colombier *outp++ = ' '; 4933e12c5d1SDavid du Colombier tp->wslen = 1; 4943e12c5d1SDavid du Colombier } 4953e12c5d1SDavid du Colombier op = outp; 4963e12c5d1SDavid du Colombier *op++ = '"'; 4973e12c5d1SDavid du Colombier switch (biname) { 4983e12c5d1SDavid du Colombier 4993e12c5d1SDavid du Colombier case KLINENO: 5003e12c5d1SDavid du Colombier tp->type = NUMBER; 5013e12c5d1SDavid du Colombier op = outnum(op-1, s->line); 5023e12c5d1SDavid du Colombier break; 5033e12c5d1SDavid du Colombier 5043e12c5d1SDavid du Colombier case KFILE: 5053e12c5d1SDavid du Colombier strcpy(op, s->filename); 5063e12c5d1SDavid du Colombier op += strlen(s->filename); 5073e12c5d1SDavid du Colombier break; 5083e12c5d1SDavid du Colombier 5093e12c5d1SDavid du Colombier case KDATE: 5103e12c5d1SDavid du Colombier strncpy(op, curtime+4, 7); 5113e12c5d1SDavid du Colombier strncpy(op+7, curtime+24, 4); /* Plan 9 asctime disobeys standard */ 5123e12c5d1SDavid du Colombier op += 11; 5133e12c5d1SDavid du Colombier break; 5143e12c5d1SDavid du Colombier 5153e12c5d1SDavid du Colombier case KTIME: 5163e12c5d1SDavid du Colombier strncpy(op, curtime+11, 8); 5173e12c5d1SDavid du Colombier op += 8; 5183e12c5d1SDavid du Colombier break; 5193e12c5d1SDavid du Colombier 5203e12c5d1SDavid du Colombier default: 5213e12c5d1SDavid du Colombier error(ERROR, "cpp botch: unknown internal macro"); 5223e12c5d1SDavid du Colombier return; 5233e12c5d1SDavid du Colombier } 5243e12c5d1SDavid du Colombier if (tp->type==STRING) 5253e12c5d1SDavid du Colombier *op++ = '"'; 5263e12c5d1SDavid du Colombier tp->t = (uchar*)outp; 5273e12c5d1SDavid du Colombier tp->len = op - outp; 5283e12c5d1SDavid du Colombier outp = op; 5293e12c5d1SDavid du Colombier } 530