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; 153e12c5d1SDavid du Colombier 163e12c5d1SDavid du Colombier tp = trp->tp+1; 173e12c5d1SDavid du Colombier if (tp>=trp->lp || tp->type!=NAME) { 183e12c5d1SDavid du Colombier error(ERROR, "#defined token is not a name"); 193e12c5d1SDavid du Colombier return; 203e12c5d1SDavid du Colombier } 213e12c5d1SDavid du Colombier np = lookup(tp, 1); 223e12c5d1SDavid du Colombier if (np->flag&ISUNCHANGE) { 233e12c5d1SDavid du Colombier error(ERROR, "#defined token %t can't be redefined", tp); 243e12c5d1SDavid du Colombier return; 253e12c5d1SDavid du Colombier } 263e12c5d1SDavid du Colombier /* collect arguments */ 273e12c5d1SDavid du Colombier tp += 1; 283e12c5d1SDavid du Colombier args = NULL; 293e12c5d1SDavid du Colombier if (tp<trp->lp && tp->type==LP && tp->wslen==0) { 303e12c5d1SDavid du Colombier /* macro with args */ 313e12c5d1SDavid du Colombier int narg = 0; 323e12c5d1SDavid du Colombier tp += 1; 333e12c5d1SDavid du Colombier args = new(Tokenrow); 343e12c5d1SDavid du Colombier maketokenrow(2, args); 353e12c5d1SDavid du Colombier if (tp->type!=RP) { 363e12c5d1SDavid du Colombier int err = 0; 373e12c5d1SDavid du Colombier for (;;) { 383e12c5d1SDavid du Colombier Token *atp; 393e12c5d1SDavid du Colombier if (tp->type!=NAME) { 403e12c5d1SDavid du Colombier err++; 413e12c5d1SDavid du Colombier break; 423e12c5d1SDavid du Colombier } 433e12c5d1SDavid du Colombier if (narg>=args->max) 443e12c5d1SDavid du Colombier growtokenrow(args); 453e12c5d1SDavid du Colombier for (atp=args->bp; atp<args->lp; atp++) 463e12c5d1SDavid du Colombier if (atp->len==tp->len 473e12c5d1SDavid du Colombier && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0) 483e12c5d1SDavid du Colombier error(ERROR, "Duplicate macro argument"); 493e12c5d1SDavid du Colombier *args->lp++ = *tp; 503e12c5d1SDavid du Colombier narg++; 513e12c5d1SDavid du Colombier tp += 1; 523e12c5d1SDavid du Colombier if (tp->type==RP) 533e12c5d1SDavid du Colombier break; 543e12c5d1SDavid du Colombier if (tp->type!=COMMA) { 553e12c5d1SDavid du Colombier err++; 563e12c5d1SDavid du Colombier break; 573e12c5d1SDavid du Colombier } 583e12c5d1SDavid du Colombier tp += 1; 593e12c5d1SDavid du Colombier } 603e12c5d1SDavid du Colombier if (err) { 613e12c5d1SDavid du Colombier error(ERROR, "Syntax error in macro parameters"); 623e12c5d1SDavid du Colombier return; 633e12c5d1SDavid du Colombier } 643e12c5d1SDavid du Colombier } 653e12c5d1SDavid du Colombier tp += 1; 663e12c5d1SDavid du Colombier } 673e12c5d1SDavid du Colombier trp->tp = tp; 683e12c5d1SDavid du Colombier if (((trp->lp)-1)->type==NL) 693e12c5d1SDavid du Colombier trp->lp -= 1; 703e12c5d1SDavid du Colombier def = normtokenrow(trp); 713e12c5d1SDavid du Colombier if (np->flag&ISDEFINED) { 723e12c5d1SDavid du Colombier if (comparetokens(def, np->vp) 733e12c5d1SDavid du Colombier || (np->ap==NULL) != (args==NULL) 743e12c5d1SDavid du Colombier || np->ap && comparetokens(args, np->ap)) 75219b2ee8SDavid du Colombier error(ERROR, "Macro redefinition of %t", trp->bp+2); 763e12c5d1SDavid du Colombier } 773e12c5d1SDavid du Colombier if (args) { 783e12c5d1SDavid du Colombier Tokenrow *tap; 793e12c5d1SDavid du Colombier tap = normtokenrow(args); 803e12c5d1SDavid du Colombier dofree(args->bp); 813e12c5d1SDavid du Colombier args = tap; 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier np->ap = args; 843e12c5d1SDavid du Colombier np->vp = def; 853e12c5d1SDavid du Colombier np->flag |= ISDEFINED; 863e12c5d1SDavid du Colombier } 873e12c5d1SDavid du Colombier 883e12c5d1SDavid du Colombier /* 893e12c5d1SDavid du Colombier * Definition received via -D or -U 903e12c5d1SDavid du Colombier */ 913e12c5d1SDavid du Colombier void 923e12c5d1SDavid du Colombier doadefine(Tokenrow *trp, int type) 933e12c5d1SDavid du Colombier { 943e12c5d1SDavid du Colombier Nlist *np; 95bd389b36SDavid du Colombier static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, (uchar*)"1" }}; 96bd389b36SDavid du Colombier static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 }; 973e12c5d1SDavid du Colombier 983e12c5d1SDavid du Colombier trp->tp = trp->bp; 993e12c5d1SDavid du Colombier if (type=='U') { 1003e12c5d1SDavid du Colombier if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME) 1013e12c5d1SDavid du Colombier goto syntax; 1023e12c5d1SDavid du Colombier if ((np = lookup(trp->tp, 0)) == NULL) 1033e12c5d1SDavid du Colombier return; 1043e12c5d1SDavid du Colombier np->flag &= ~ISDEFINED; 1053e12c5d1SDavid du Colombier return; 1063e12c5d1SDavid du Colombier } 1073e12c5d1SDavid du Colombier if (trp->tp >= trp->lp || trp->tp->type!=NAME) 1083e12c5d1SDavid du Colombier goto syntax; 1093e12c5d1SDavid du Colombier np = lookup(trp->tp, 1); 1103e12c5d1SDavid du Colombier np->flag |= ISDEFINED; 1113e12c5d1SDavid du Colombier trp->tp += 1; 1123e12c5d1SDavid du Colombier if (trp->tp >= trp->lp || trp->tp->type==END) { 1133e12c5d1SDavid du Colombier np->vp = &onetr; 1143e12c5d1SDavid du Colombier return; 1153e12c5d1SDavid du Colombier } 1163e12c5d1SDavid du Colombier if (trp->tp->type!=ASGN) 1173e12c5d1SDavid du Colombier goto syntax; 1183e12c5d1SDavid du Colombier trp->tp += 1; 1193e12c5d1SDavid du Colombier if ((trp->lp-1)->type == END) 1203e12c5d1SDavid du Colombier trp->lp -= 1; 1213e12c5d1SDavid du Colombier np->vp = normtokenrow(trp); 1223e12c5d1SDavid du Colombier return; 1233e12c5d1SDavid du Colombier syntax: 1243e12c5d1SDavid du Colombier error(FATAL, "Illegal -D or -U argument %r", trp); 1253e12c5d1SDavid du Colombier } 1263e12c5d1SDavid du Colombier 1273e12c5d1SDavid du Colombier /* 1283e12c5d1SDavid du Colombier * Do macro expansion in a row of tokens. 1293e12c5d1SDavid du Colombier * Flag is NULL if more input can be gathered. 1303e12c5d1SDavid du Colombier */ 1313e12c5d1SDavid du Colombier void 1323e12c5d1SDavid du Colombier expandrow(Tokenrow *trp, char *flag) 1333e12c5d1SDavid du Colombier { 1343e12c5d1SDavid du Colombier Token *tp; 1353e12c5d1SDavid du Colombier Nlist *np; 1363e12c5d1SDavid du Colombier 1373e12c5d1SDavid du Colombier if (flag) 1383e12c5d1SDavid du Colombier setsource(flag, -1, ""); 1393e12c5d1SDavid du Colombier for (tp = trp->tp; tp<trp->lp; ) { 1403e12c5d1SDavid du Colombier if (tp->type!=NAME 1413e12c5d1SDavid du Colombier || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0 1423e12c5d1SDavid du Colombier || (np = lookup(tp, 0))==NULL 1433e12c5d1SDavid du Colombier || (np->flag&(ISDEFINED|ISMAC))==0 1443e12c5d1SDavid du Colombier || tp->hideset && checkhideset(tp->hideset, np)) { 1453e12c5d1SDavid du Colombier tp++; 1463e12c5d1SDavid du Colombier continue; 1473e12c5d1SDavid du Colombier } 1483e12c5d1SDavid du Colombier trp->tp = tp; 149bd389b36SDavid du Colombier if (np->val==KDEFINED) { 150bd389b36SDavid du Colombier tp->type = DEFINED; 151bd389b36SDavid du Colombier if ((tp+1)<trp->lp && (tp+1)->type==NAME) 152bd389b36SDavid du Colombier (tp+1)->type = NAME1; 153bd389b36SDavid du Colombier else if ((tp+3)<trp->lp && (tp+1)->type==LP 154bd389b36SDavid du Colombier && (tp+2)->type==NAME && (tp+3)->type==RP) 155bd389b36SDavid du Colombier (tp+2)->type = NAME1; 156bd389b36SDavid du Colombier else 157bd389b36SDavid du Colombier error(ERROR, "Incorrect syntax for `defined'"); 158bd389b36SDavid du Colombier tp++; 159bd389b36SDavid du Colombier continue; 160bd389b36SDavid du Colombier } 1613e12c5d1SDavid du Colombier if (np->flag&ISMAC) 1623e12c5d1SDavid du Colombier builtin(trp, np->val); 1633e12c5d1SDavid du Colombier else { 1643e12c5d1SDavid du Colombier expand(trp, np); 1653e12c5d1SDavid du Colombier } 1663e12c5d1SDavid du Colombier tp = trp->tp; 1673e12c5d1SDavid du Colombier } 1683e12c5d1SDavid du Colombier if (flag) 1693e12c5d1SDavid du Colombier unsetsource(); 1703e12c5d1SDavid du Colombier } 1713e12c5d1SDavid du Colombier 1723e12c5d1SDavid du Colombier /* 1733e12c5d1SDavid du Colombier * Expand the macro whose name is np, at token trp->tp, in the tokenrow. 1743e12c5d1SDavid du Colombier * Return trp->tp at the first token next to be expanded 1753e12c5d1SDavid du Colombier * (ordinarily the beginning of the expansion) 1763e12c5d1SDavid du Colombier */ 1773e12c5d1SDavid du Colombier void 1783e12c5d1SDavid du Colombier expand(Tokenrow *trp, Nlist *np) 1793e12c5d1SDavid du Colombier { 1803e12c5d1SDavid du Colombier Tokenrow ntr; 1813e12c5d1SDavid du Colombier int ntokc, narg, i; 1823e12c5d1SDavid du Colombier Token *tp; 1833e12c5d1SDavid du Colombier Tokenrow *atr[NARG+1]; 1843e12c5d1SDavid du Colombier int hs; 185bd389b36SDavid du Colombier 1863e12c5d1SDavid du Colombier copytokenrow(&ntr, np->vp); /* copy macro value */ 1873e12c5d1SDavid du Colombier if (np->ap==NULL) /* parameterless */ 1883e12c5d1SDavid du Colombier ntokc = 1; 1893e12c5d1SDavid du Colombier else { 1903e12c5d1SDavid du Colombier ntokc = gatherargs(trp, atr, &narg); 1913e12c5d1SDavid du Colombier if (narg<0) { /* not actually a call (no '(') */ 192*7dd7cddfSDavid du Colombier trp->tp++; 1933e12c5d1SDavid du Colombier return; 1943e12c5d1SDavid du Colombier } 1953e12c5d1SDavid du Colombier if (narg != rowlen(np->ap)) { 1963e12c5d1SDavid du Colombier error(ERROR, "Disagreement in number of macro arguments"); 1973e12c5d1SDavid du Colombier trp->tp->hideset = newhideset(trp->tp->hideset, np); 1983e12c5d1SDavid du Colombier trp->tp += ntokc; 1993e12c5d1SDavid du Colombier return; 2003e12c5d1SDavid du Colombier } 2013e12c5d1SDavid du Colombier substargs(np, &ntr, atr); /* put args into replacement */ 2023e12c5d1SDavid du Colombier for (i=0; i<narg; i++) { 2033e12c5d1SDavid du Colombier dofree(atr[i]->bp); 2043e12c5d1SDavid du Colombier dofree(atr[i]); 2053e12c5d1SDavid du Colombier } 2063e12c5d1SDavid du Colombier } 2073e12c5d1SDavid du Colombier doconcat(&ntr); /* execute ## operators */ 2083e12c5d1SDavid du Colombier hs = newhideset(trp->tp->hideset, np); 2093e12c5d1SDavid du Colombier for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */ 2103e12c5d1SDavid du Colombier if (tp->type==NAME) { 2113e12c5d1SDavid du Colombier if (tp->hideset==0) 2123e12c5d1SDavid du Colombier tp->hideset = hs; 2133e12c5d1SDavid du Colombier else 2143e12c5d1SDavid du Colombier tp->hideset = unionhideset(tp->hideset, hs); 2153e12c5d1SDavid du Colombier } 2163e12c5d1SDavid du Colombier } 2173e12c5d1SDavid du Colombier ntr.tp = ntr.bp; 2183e12c5d1SDavid du Colombier insertrow(trp, ntokc, &ntr); 2193e12c5d1SDavid du Colombier trp->tp -= rowlen(&ntr); 2203e12c5d1SDavid du Colombier dofree(ntr.bp); 2213e12c5d1SDavid du Colombier return; 2223e12c5d1SDavid du Colombier } 2233e12c5d1SDavid du Colombier 2243e12c5d1SDavid du Colombier /* 2253e12c5d1SDavid du Colombier * Gather an arglist, starting in trp with tp pointing at the macro name. 2263e12c5d1SDavid du Colombier * Return total number of tokens passed, stash number of args found. 2273e12c5d1SDavid du Colombier * trp->tp is not changed relative to the tokenrow. 2283e12c5d1SDavid du Colombier */ 2293e12c5d1SDavid du Colombier int 2303e12c5d1SDavid du Colombier gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg) 2313e12c5d1SDavid du Colombier { 2323e12c5d1SDavid du Colombier int parens = 1; 2333e12c5d1SDavid du Colombier int ntok = 0; 2343e12c5d1SDavid du Colombier Token *bp, *lp; 2353e12c5d1SDavid du Colombier Tokenrow ttr; 2363e12c5d1SDavid du Colombier int ntokp; 237*7dd7cddfSDavid du Colombier int needspace; 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier *narg = -1; /* means that there is no macro call */ 2403e12c5d1SDavid du Colombier /* look for the ( */ 2413e12c5d1SDavid du Colombier for (;;) { 2423e12c5d1SDavid du Colombier trp->tp++; 2433e12c5d1SDavid du Colombier ntok++; 2443e12c5d1SDavid du Colombier if (trp->tp >= trp->lp) { 2453e12c5d1SDavid du Colombier gettokens(trp, 0); 2463e12c5d1SDavid du Colombier if ((trp->lp-1)->type==END) { 2473e12c5d1SDavid du Colombier trp->lp -= 1; 2483e12c5d1SDavid du Colombier trp->tp -= ntok; 2493e12c5d1SDavid du Colombier return ntok; 2503e12c5d1SDavid du Colombier } 2513e12c5d1SDavid du Colombier } 2523e12c5d1SDavid du Colombier if (trp->tp->type==LP) 2533e12c5d1SDavid du Colombier break; 2543e12c5d1SDavid du Colombier if (trp->tp->type!=NL) 2553e12c5d1SDavid du Colombier return ntok; 2563e12c5d1SDavid du Colombier } 2573e12c5d1SDavid du Colombier *narg = 0; 2583e12c5d1SDavid du Colombier ntok++; 2593e12c5d1SDavid du Colombier ntokp = ntok; 2603e12c5d1SDavid du Colombier trp->tp++; 2613e12c5d1SDavid du Colombier /* search for the terminating ), possibly extending the row */ 262*7dd7cddfSDavid du Colombier needspace = 0; 2633e12c5d1SDavid du Colombier while (parens>0) { 2643e12c5d1SDavid du Colombier if (trp->tp >= trp->lp) 2653e12c5d1SDavid du Colombier gettokens(trp, 0); 266*7dd7cddfSDavid du Colombier if (needspace) { 267*7dd7cddfSDavid du Colombier needspace = 0; 268*7dd7cddfSDavid du Colombier makespace(trp); 269*7dd7cddfSDavid du Colombier } 2703e12c5d1SDavid du Colombier if (trp->tp->type==END) { 2713e12c5d1SDavid du Colombier trp->lp -= 1; 2723e12c5d1SDavid du Colombier trp->tp -= ntok; 2733e12c5d1SDavid du Colombier error(ERROR, "EOF in macro arglist"); 2743e12c5d1SDavid du Colombier return ntok; 2753e12c5d1SDavid du Colombier } 2763e12c5d1SDavid du Colombier if (trp->tp->type==NL) { 2773e12c5d1SDavid du Colombier trp->tp += 1; 2783e12c5d1SDavid du Colombier adjustrow(trp, -1); 2793e12c5d1SDavid du Colombier trp->tp -= 1; 2803e12c5d1SDavid du Colombier makespace(trp); 281*7dd7cddfSDavid du Colombier needspace = 1; 2823e12c5d1SDavid du Colombier continue; 2833e12c5d1SDavid du Colombier } 2843e12c5d1SDavid du Colombier if (trp->tp->type==LP) 2853e12c5d1SDavid du Colombier parens++; 2863e12c5d1SDavid du Colombier else if (trp->tp->type==RP) 2873e12c5d1SDavid du Colombier parens--; 2883e12c5d1SDavid du Colombier trp->tp++; 2893e12c5d1SDavid du Colombier ntok++; 2903e12c5d1SDavid du Colombier } 2913e12c5d1SDavid du Colombier trp->tp -= ntok; 2923e12c5d1SDavid du Colombier /* Now trp->tp won't move underneath us */ 2933e12c5d1SDavid du Colombier lp = bp = trp->tp+ntokp; 2943e12c5d1SDavid du Colombier for (; parens>=0; lp++) { 2953e12c5d1SDavid du Colombier if (lp->type == LP) { 2963e12c5d1SDavid du Colombier parens++; 2973e12c5d1SDavid du Colombier continue; 2983e12c5d1SDavid du Colombier } 2993e12c5d1SDavid du Colombier if (lp->type==RP) 3003e12c5d1SDavid du Colombier parens--; 3013e12c5d1SDavid du Colombier if (lp->type==DSHARP) 3023e12c5d1SDavid du Colombier lp->type = DSHARP1; /* ## not special in arg */ 3033e12c5d1SDavid du Colombier if (lp->type==COMMA && parens==0 || parens<0 && (lp-1)->type!=LP) { 3043e12c5d1SDavid du Colombier if (*narg>=NARG-1) 3053e12c5d1SDavid du Colombier error(FATAL, "Sorry, too many macro arguments"); 3063e12c5d1SDavid du Colombier ttr.bp = ttr.tp = bp; 3073e12c5d1SDavid du Colombier ttr.lp = lp; 3083e12c5d1SDavid du Colombier atr[(*narg)++] = normtokenrow(&ttr); 3093e12c5d1SDavid du Colombier bp = lp+1; 3103e12c5d1SDavid du Colombier } 3113e12c5d1SDavid du Colombier } 3123e12c5d1SDavid du Colombier return ntok; 3133e12c5d1SDavid du Colombier } 3143e12c5d1SDavid du Colombier 3153e12c5d1SDavid du Colombier /* 3163e12c5d1SDavid du Colombier * substitute the argument list into the replacement string 3173e12c5d1SDavid du Colombier * This would be simple except for ## and # 3183e12c5d1SDavid du Colombier */ 3193e12c5d1SDavid du Colombier void 3203e12c5d1SDavid du Colombier substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr) 3213e12c5d1SDavid du Colombier { 3223e12c5d1SDavid du Colombier Tokenrow tatr; 3233e12c5d1SDavid du Colombier Token *tp; 3243e12c5d1SDavid du Colombier int ntok, argno; 3253e12c5d1SDavid du Colombier 3263e12c5d1SDavid du Colombier for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) { 3273e12c5d1SDavid du Colombier if (rtr->tp->type==SHARP) { /* string operator */ 3283e12c5d1SDavid du Colombier tp = rtr->tp; 3293e12c5d1SDavid du Colombier rtr->tp += 1; 3303e12c5d1SDavid du Colombier if ((argno = lookuparg(np, rtr->tp))<0) { 3313e12c5d1SDavid du Colombier error(ERROR, "# not followed by macro parameter"); 3323e12c5d1SDavid du Colombier continue; 3333e12c5d1SDavid du Colombier } 3343e12c5d1SDavid du Colombier ntok = 1 + (rtr->tp - tp); 3353e12c5d1SDavid du Colombier rtr->tp = tp; 3363e12c5d1SDavid du Colombier insertrow(rtr, ntok, stringify(atr[argno])); 3373e12c5d1SDavid du Colombier continue; 3383e12c5d1SDavid du Colombier } 3393e12c5d1SDavid du Colombier if (rtr->tp->type==NAME 3403e12c5d1SDavid du Colombier && (argno = lookuparg(np, rtr->tp)) >= 0) { 341*7dd7cddfSDavid du Colombier if (rtr->tp < rtr->bp) 342*7dd7cddfSDavid du Colombier error(ERROR, "access out of bounds"); 3433e12c5d1SDavid du Colombier if ((rtr->tp+1)->type==DSHARP 344bd389b36SDavid du Colombier || rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP) 3453e12c5d1SDavid du Colombier insertrow(rtr, 1, atr[argno]); 3463e12c5d1SDavid du Colombier else { 3473e12c5d1SDavid du Colombier copytokenrow(&tatr, atr[argno]); 3483e12c5d1SDavid du Colombier expandrow(&tatr, "<macro>"); 3493e12c5d1SDavid du Colombier insertrow(rtr, 1, &tatr); 3503e12c5d1SDavid du Colombier dofree(tatr.bp); 3513e12c5d1SDavid du Colombier } 3523e12c5d1SDavid du Colombier continue; 3533e12c5d1SDavid du Colombier } 3543e12c5d1SDavid du Colombier rtr->tp++; 3553e12c5d1SDavid du Colombier } 3563e12c5d1SDavid du Colombier } 3573e12c5d1SDavid du Colombier 3583e12c5d1SDavid du Colombier /* 3593e12c5d1SDavid du Colombier * Evaluate the ## operators in a tokenrow 3603e12c5d1SDavid du Colombier */ 3613e12c5d1SDavid du Colombier void 3623e12c5d1SDavid du Colombier doconcat(Tokenrow *trp) 3633e12c5d1SDavid du Colombier { 3643e12c5d1SDavid du Colombier Token *ltp, *ntp; 3653e12c5d1SDavid du Colombier Tokenrow ntr; 3663e12c5d1SDavid du Colombier int len; 3673e12c5d1SDavid du Colombier 3683e12c5d1SDavid du Colombier for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) { 3693e12c5d1SDavid du Colombier if (trp->tp->type==DSHARP1) 3703e12c5d1SDavid du Colombier trp->tp->type = DSHARP; 3713e12c5d1SDavid du Colombier else if (trp->tp->type==DSHARP) { 3723e12c5d1SDavid du Colombier char tt[128]; 3733e12c5d1SDavid du Colombier ltp = trp->tp-1; 3743e12c5d1SDavid du Colombier ntp = trp->tp+1; 3753e12c5d1SDavid du Colombier if (ltp<trp->bp || ntp>=trp->lp) { 3763e12c5d1SDavid du Colombier error(ERROR, "## occurs at border of replacement"); 3773e12c5d1SDavid du Colombier continue; 3783e12c5d1SDavid du Colombier } 3793e12c5d1SDavid du Colombier len = ltp->len + ntp->len; 3803e12c5d1SDavid du Colombier strncpy((char*)tt, (char*)ltp->t, ltp->len); 3813e12c5d1SDavid du Colombier strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len); 3823e12c5d1SDavid du Colombier tt[len] = '\0'; 3833e12c5d1SDavid du Colombier setsource("<##>", -1, tt); 3843e12c5d1SDavid du Colombier maketokenrow(3, &ntr); 3853e12c5d1SDavid du Colombier gettokens(&ntr, 1); 3863e12c5d1SDavid du Colombier unsetsource(); 3873e12c5d1SDavid du Colombier if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS) 3883e12c5d1SDavid du Colombier error(WARNING, "Bad token %r produced by ##", &ntr); 3893e12c5d1SDavid du Colombier ntr.lp = ntr.bp+1; 3903e12c5d1SDavid du Colombier trp->tp = ltp; 3913e12c5d1SDavid du Colombier makespace(&ntr); 3923e12c5d1SDavid du Colombier insertrow(trp, (ntp-ltp)+1, &ntr); 3933e12c5d1SDavid du Colombier dofree(ntr.bp); 3943e12c5d1SDavid du Colombier trp->tp--; 3953e12c5d1SDavid du Colombier } 3963e12c5d1SDavid du Colombier } 3973e12c5d1SDavid du Colombier } 3983e12c5d1SDavid du Colombier 3993e12c5d1SDavid du Colombier /* 4003e12c5d1SDavid du Colombier * tp is a potential parameter name of macro mac; 4013e12c5d1SDavid du Colombier * look it up in mac's arglist, and if found, return the 4023e12c5d1SDavid du Colombier * corresponding index in the argname array. Return -1 if not found. 4033e12c5d1SDavid du Colombier */ 4043e12c5d1SDavid du Colombier int 4053e12c5d1SDavid du Colombier lookuparg(Nlist *mac, Token *tp) 4063e12c5d1SDavid du Colombier { 4073e12c5d1SDavid du Colombier Token *ap; 4083e12c5d1SDavid du Colombier 4093e12c5d1SDavid du Colombier if (tp->type!=NAME || mac->ap==NULL) 4103e12c5d1SDavid du Colombier return -1; 4113e12c5d1SDavid du Colombier for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) { 4123e12c5d1SDavid du Colombier if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0) 4133e12c5d1SDavid du Colombier return ap - mac->ap->bp; 4143e12c5d1SDavid du Colombier } 4153e12c5d1SDavid du Colombier return -1; 4163e12c5d1SDavid du Colombier } 4173e12c5d1SDavid du Colombier 4183e12c5d1SDavid du Colombier /* 4193e12c5d1SDavid du Colombier * Return a quoted version of the tokenrow (from # arg) 4203e12c5d1SDavid du Colombier */ 4213e12c5d1SDavid du Colombier #define STRLEN 512 4223e12c5d1SDavid du Colombier Tokenrow * 4233e12c5d1SDavid du Colombier stringify(Tokenrow *vp) 4243e12c5d1SDavid du Colombier { 4253e12c5d1SDavid du Colombier static Token t = { STRING }; 4263e12c5d1SDavid du Colombier static Tokenrow tr = { &t, &t, &t+1, 1 }; 4273e12c5d1SDavid du Colombier Token *tp; 4283e12c5d1SDavid du Colombier uchar s[STRLEN]; 4293e12c5d1SDavid du Colombier uchar *sp = s, *cp; 4303e12c5d1SDavid du Colombier int i, instring; 4313e12c5d1SDavid du Colombier 4323e12c5d1SDavid du Colombier *sp++ = '"'; 4333e12c5d1SDavid du Colombier for (tp = vp->bp; tp < vp->lp; tp++) { 4343e12c5d1SDavid du Colombier instring = tp->type==STRING || tp->type==CCON; 4353e12c5d1SDavid du Colombier if (sp+2*tp->len >= &s[STRLEN-10]) { 4363e12c5d1SDavid du Colombier error(ERROR, "Stringified macro arg is too long"); 4373e12c5d1SDavid du Colombier break; 4383e12c5d1SDavid du Colombier } 4393e12c5d1SDavid du Colombier if (tp->wslen && (tp->flag&XPWS)==0) 4403e12c5d1SDavid du Colombier *sp++ = ' '; 4413e12c5d1SDavid du Colombier for (i=0, cp=tp->t; i<tp->len; i++) { 4423e12c5d1SDavid du Colombier if (instring && (*cp=='"' || *cp=='\\')) 4433e12c5d1SDavid du Colombier *sp++ = '\\'; 4443e12c5d1SDavid du Colombier *sp++ = *cp++; 4453e12c5d1SDavid du Colombier } 4463e12c5d1SDavid du Colombier } 4473e12c5d1SDavid du Colombier *sp++ = '"'; 4483e12c5d1SDavid du Colombier *sp = '\0'; 4493e12c5d1SDavid du Colombier sp = s; 4503e12c5d1SDavid du Colombier t.len = strlen((char*)sp); 4513e12c5d1SDavid du Colombier t.t = newstring(sp, t.len, 0); 4523e12c5d1SDavid du Colombier return &tr; 4533e12c5d1SDavid du Colombier } 4543e12c5d1SDavid du Colombier 4553e12c5d1SDavid du Colombier /* 4563e12c5d1SDavid du Colombier * expand a builtin name 4573e12c5d1SDavid du Colombier */ 4583e12c5d1SDavid du Colombier void 4593e12c5d1SDavid du Colombier builtin(Tokenrow *trp, int biname) 4603e12c5d1SDavid du Colombier { 4613e12c5d1SDavid du Colombier char *op; 4623e12c5d1SDavid du Colombier Token *tp; 4633e12c5d1SDavid du Colombier Source *s; 4643e12c5d1SDavid du Colombier 4653e12c5d1SDavid du Colombier tp = trp->tp; 4663e12c5d1SDavid du Colombier trp->tp++; 4673e12c5d1SDavid du Colombier /* need to find the real source */ 4683e12c5d1SDavid du Colombier s = cursource; 4693e12c5d1SDavid du Colombier while (s && s->fd==-1) 4703e12c5d1SDavid du Colombier s = s->next; 4713e12c5d1SDavid du Colombier if (s==NULL) 4723e12c5d1SDavid du Colombier s = cursource; 4733e12c5d1SDavid du Colombier /* most are strings */ 4743e12c5d1SDavid du Colombier tp->type = STRING; 4753e12c5d1SDavid du Colombier if (tp->wslen) { 4763e12c5d1SDavid du Colombier *outp++ = ' '; 4773e12c5d1SDavid du Colombier tp->wslen = 1; 4783e12c5d1SDavid du Colombier } 4793e12c5d1SDavid du Colombier op = outp; 4803e12c5d1SDavid du Colombier *op++ = '"'; 4813e12c5d1SDavid du Colombier switch (biname) { 4823e12c5d1SDavid du Colombier 4833e12c5d1SDavid du Colombier case KLINENO: 4843e12c5d1SDavid du Colombier tp->type = NUMBER; 4853e12c5d1SDavid du Colombier op = outnum(op-1, s->line); 4863e12c5d1SDavid du Colombier break; 4873e12c5d1SDavid du Colombier 4883e12c5d1SDavid du Colombier case KFILE: 4893e12c5d1SDavid du Colombier strcpy(op, s->filename); 4903e12c5d1SDavid du Colombier op += strlen(s->filename); 4913e12c5d1SDavid du Colombier break; 4923e12c5d1SDavid du Colombier 4933e12c5d1SDavid du Colombier case KDATE: 4943e12c5d1SDavid du Colombier strncpy(op, curtime+4, 7); 4953e12c5d1SDavid du Colombier strncpy(op+7, curtime+24, 4); /* Plan 9 asctime disobeys standard */ 4963e12c5d1SDavid du Colombier op += 11; 4973e12c5d1SDavid du Colombier break; 4983e12c5d1SDavid du Colombier 4993e12c5d1SDavid du Colombier case KTIME: 5003e12c5d1SDavid du Colombier strncpy(op, curtime+11, 8); 5013e12c5d1SDavid du Colombier op += 8; 5023e12c5d1SDavid du Colombier break; 5033e12c5d1SDavid du Colombier 5043e12c5d1SDavid du Colombier default: 5053e12c5d1SDavid du Colombier error(ERROR, "cpp botch: unknown internal macro"); 5063e12c5d1SDavid du Colombier return; 5073e12c5d1SDavid du Colombier } 5083e12c5d1SDavid du Colombier if (tp->type==STRING) 5093e12c5d1SDavid du Colombier *op++ = '"'; 5103e12c5d1SDavid du Colombier tp->t = (uchar*)outp; 5113e12c5d1SDavid du Colombier tp->len = op - outp; 5123e12c5d1SDavid du Colombier outp = op; 5133e12c5d1SDavid du Colombier } 514