The following code : #define hash_hash # ## # #define mkstr(a) # a #define in_between(a) mkstr(a) #define join(c, d) in_between(c hash_hash d) char p[] = join(x, y); should produce : char p[] = "x ## y"; instead of : char p[] = "xy"; I think stringify() is called too many. That's why I propose this fix. However, even though it fixes this problem, I cannot tell you of any collateral damages ;) Phil; Reference: /n/sources/patch/applied/cpp-bad-stringify Date: Fri Nov 30 10:45:46 CET 2007 Signed-off-by: xigh@free.fr --- /sys/src/cmd/cpp/cpp.c Fri Nov 30 10:40:28 2007 +++ /sys/src/cmd/cpp/cpp.c Fri Nov 30 10:40:25 2007 @@ -69,7 +69,7 @@ trp->tp += 1; control(trp); } else if (!skipping && anymacros) - expandrow(trp, NULL); + expandrow(trp, NULL, 0); if (skipping) setempty(trp); puttokens(trp); @@ -213,7 +213,7 @@ case KLINE: trp->tp = tp+1; - expandrow(trp, ""); + expandrow(trp, "", 0); tp = trp->bp+2; kline: if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3lp --- /sys/src/cmd/cpp/cpp.h Fri Nov 30 10:40:34 2007 +++ /sys/src/cmd/cpp/cpp.h Fri Nov 30 10:40:31 2007 @@ -109,11 +109,11 @@ void doadefine(Tokenrow *, int); void doinclude(Tokenrow *); void doif(Tokenrow *, enum kwtype); -void expand(Tokenrow *, Nlist *); +void expand(Tokenrow *, Nlist *, int); void builtin(Tokenrow *, int); int gatherargs(Tokenrow *, Tokenrow **, int, int *); void substargs(Nlist *, Tokenrow *, Tokenrow **); -void expandrow(Tokenrow *, char *); +void expandrow(Tokenrow *, char *, int); void maketokenrow(int, Tokenrow *); Tokenrow *copytokenrow(Tokenrow *, Tokenrow *); Token *growtokenrow(Tokenrow *); --- /sys/src/cmd/cpp/eval.c Fri Nov 30 10:40:41 2007 +++ /sys/src/cmd/cpp/eval.c Fri Nov 30 10:40:37 2007 @@ -116,7 +116,7 @@ } ntok = trp->tp - trp->bp; kwdefined->val = KDEFINED; /* activate special meaning of defined */ - expandrow(trp, ""); + expandrow(trp, "", 0); kwdefined->val = NAME; vp = vals; op = ops; --- /sys/src/cmd/cpp/include.c Fri Nov 30 10:40:47 2007 +++ /sys/src/cmd/cpp/include.c Fri Nov 30 10:40:43 2007 @@ -18,7 +18,7 @@ goto syntax; if (trp->tp->type!=STRING && trp->tp->type!=LT) { len = trp->tp - trp->bp; - expandrow(trp, ""); + expandrow(trp, "", 0); trp->tp = trp->bp+len; } if (trp->tp->type==STRING) { --- /sys/src/cmd/cpp/macro.c Fri Nov 30 10:40:54 2007 +++ /sys/src/cmd/cpp/macro.c Fri Nov 30 10:40:50 2007 @@ -138,7 +138,7 @@ * Flag is NULL if more input can be gathered. */ void -expandrow(Tokenrow *trp, char *flag) +expandrow(Tokenrow *trp, char *flag, int inmacro) { Token *tp; Nlist *np; @@ -170,7 +170,7 @@ if (np->flag&ISMAC) builtin(trp, np->val); else { - expand(trp, np); + expand(trp, np, inmacro); } tp = trp->tp; } @@ -184,7 +184,7 @@ * (ordinarily the beginning of the expansion) */ void -expand(Tokenrow *trp, Nlist *np) +expand(Tokenrow *trp, Nlist *np, int inmacro) { Tokenrow ntr; int ntokc, narg, i; @@ -214,7 +214,8 @@ dofree(atr[i]); } } - doconcat(&ntr); /* execute ## operators */ + if(!inmacro) + doconcat(&ntr); /* execute ## operators */ hs = newhideset(trp->tp->hideset, np); for (tp=ntr.bp; tptype==NAME) { @@ -359,7 +360,7 @@ insertrow(rtr, 1, atr[argno]); else { copytokenrow(&tatr, atr[argno]); - expandrow(&tatr, ""); + expandrow(&tatr, "", 1); insertrow(rtr, 1, &tatr); dofree(tatr.bp); } @@ -452,7 +453,7 @@ error(ERROR, "Stringified macro arg is too long"); break; } - if (tp->wslen && (tp->flag&XPWS)==0) + if (tp->wslen) // && (tp->flag&XPWS)==0) *sp++ = ' '; for (i=0, cp=tp->t; ilen; i++) { if (instring && (*cp=='"' || *cp=='\\'))