Improve the posix preprocessor.

This fixes token pasting, making it expand when
it should expand, and paste before expansion when
it should paste before expanding.

	#define CAT(a, b) a ## b
	#define BAR	3
	#define FOO	CAT(BAR, 3)
	FOO

now produces 33, while

	#define CAT(a, b) a ## b
	#define EOF	(-1)
	#define NOP(x)	x
	NOP(CAT(foo, EOF))
	CAT(,EOF)
	CAT(,)

produces

	fooEOF
	(-1)
	<empty>

respectively.
This commit is contained in:
Ori Bernstein 2020-03-17 22:03:25 -07:00
parent 52dc943702
commit 37b86df09f
7 changed files with 283 additions and 136 deletions

View file

@ -68,7 +68,7 @@ process(Tokenrow *trp)
trp->tp += 1; trp->tp += 1;
control(trp); control(trp);
} else if (!skipping && anymacros) } else if (!skipping && anymacros)
expandrow(trp, NULL, Notinmacro); expandrow(trp, NULL);
if (skipping) if (skipping)
setempty(trp); setempty(trp);
puttokens(trp); puttokens(trp);
@ -217,7 +217,7 @@ control(Tokenrow *trp)
case KLINE: case KLINE:
trp->tp = tp+1; trp->tp = tp+1;
expandrow(trp, "<line>", Notinmacro); expandrow(trp, "<line>");
tp = trp->bp+2; tp = trp->bp+2;
kline: kline:
if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp

View file

@ -14,7 +14,7 @@ enum toktype { END, UNCLASS, NAME, NUMBER, STRING, CCON, NL, WS, DSHARP,
EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS, EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS,
ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS, ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS,
TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST, TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST,
COLON, ASGN, COMMA, SHARP, SEMIC, CBRA, CKET, COLON, ASGN, COMMA, XCOMMA, SHARP, SEMIC, CBRA, CKET,
ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH, ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH,
ASRSH, ASOR, ASAND, ELLIPS, ASRSH, ASOR, ASAND, ELLIPS,
DSHARP1, NAME1, DEFINED, UMINUS }; DSHARP1, NAME1, DEFINED, UMINUS };
@ -107,11 +107,11 @@ void dodefine(Tokenrow *);
void doadefine(Tokenrow *, int); void doadefine(Tokenrow *, int);
void doinclude(Tokenrow *); void doinclude(Tokenrow *);
void doif(Tokenrow *, enum kwtype); void doif(Tokenrow *, enum kwtype);
void expand(Tokenrow *, Nlist *, int); void expand(Tokenrow *, Nlist *);
void builtin(Tokenrow *, int); void builtin(Tokenrow *, int);
int gatherargs(Tokenrow *, Tokenrow **, int, int *); int gatherargs(Tokenrow *, Tokenrow **, int, int *);
void substargs(Nlist *, Tokenrow *, Tokenrow **); void substargs(Nlist *, Tokenrow *, Tokenrow **);
void expandrow(Tokenrow *, char *, int); void expandrow(Tokenrow *, char *);
void maketokenrow(int, Tokenrow *); void maketokenrow(int, Tokenrow *);
Tokenrow *copytokenrow(Tokenrow *, Tokenrow *); Tokenrow *copytokenrow(Tokenrow *, Tokenrow *);
Token *growtokenrow(Tokenrow *); Token *growtokenrow(Tokenrow *);
@ -120,7 +120,7 @@ void adjustrow(Tokenrow *, int);
void movetokenrow(Tokenrow *, Tokenrow *); void movetokenrow(Tokenrow *, Tokenrow *);
void insertrow(Tokenrow *, int, Tokenrow *); void insertrow(Tokenrow *, int, Tokenrow *);
void peektokens(Tokenrow *, char *); void peektokens(Tokenrow *, char *);
void doconcat(Tokenrow *); void glue(Tokenrow *, Token *, Token *);
Tokenrow *stringify(Tokenrow *); Tokenrow *stringify(Tokenrow *);
int lookuparg(Nlist *, Token *); int lookuparg(Nlist *, Token *);
long eval(Tokenrow *, int); long eval(Tokenrow *, int);

View file

@ -28,66 +28,67 @@ const struct pri {
char arity; char arity;
char ctype; char ctype;
} priority[] = { } priority[] = {
{ 0, 0, 0 }, /* END */ [END] { 0, 0, 0 },
{ 0, 0, 0 }, /* UNCLASS */ [UNCLASS] { 0, 0, 0 },
{ 0, 0, 0 }, /* NAME */ [NAME] { 0, 0, 0 },
{ 0, 0, 0 }, /* NUMBER */ [NUMBER] { 0, 0, 0 },
{ 0, 0, 0 }, /* STRING */ [STRING] { 0, 0, 0 },
{ 0, 0, 0 }, /* CCON */ [CCON] { 0, 0, 0 },
{ 0, 0, 0 }, /* NL */ [NL] { 0, 0, 0 },
{ 0, 0, 0 }, /* WS */ [WS] { 0, 0, 0 },
{ 0, 0, 0 }, /* DSHARP */ [DSHARP] { 0, 0, 0 },
{ 11, 2, RELAT }, /* EQ */ [EQ] { 11, 2, RELAT },
{ 11, 2, RELAT }, /* NEQ */ [NEQ] { 11, 2, RELAT },
{ 12, 2, RELAT }, /* LEQ */ [LEQ] { 12, 2, RELAT },
{ 12, 2, RELAT }, /* GEQ */ [GEQ] { 12, 2, RELAT },
{ 13, 2, SHIFT }, /* LSH */ [LSH] { 13, 2, SHIFT },
{ 13, 2, SHIFT }, /* RSH */ [RSH] { 13, 2, SHIFT },
{ 7, 2, LOGIC }, /* LAND */ [LAND] { 7, 2, LOGIC },
{ 6, 2, LOGIC }, /* LOR */ [LOR] { 6, 2, LOGIC },
{ 0, 0, 0 }, /* PPLUS */ [PPLUS] { 0, 0, 0 },
{ 0, 0, 0 }, /* MMINUS */ [MMINUS] { 0, 0, 0 },
{ 0, 0, 0 }, /* ARROW */ [ARROW] { 0, 0, 0 },
{ 0, 0, 0 }, /* SBRA */ [SBRA] { 0, 0, 0 },
{ 0, 0, 0 }, /* SKET */ [SKET] { 0, 0, 0 },
{ 3, 0, 0 }, /* LP */ [LP] { 3, 0, 0 },
{ 3, 0, 0 }, /* RP */ [RP] { 3, 0, 0 },
{ 0, 0, 0 }, /* DOT */ [DOT] { 0, 0, 0 },
{ 10, 2, ARITH }, /* AND */ [AND] { 10, 2, ARITH },
{ 15, 2, ARITH }, /* STAR */ [STAR] { 15, 2, ARITH },
{ 14, 2, ARITH }, /* PLUS */ [PLUS] { 14, 2, ARITH },
{ 14, 2, ARITH }, /* MINUS */ [MINUS] { 14, 2, ARITH },
{ 16, 1, UNARY }, /* TILDE */ [TILDE] { 16, 1, UNARY },
{ 16, 1, UNARY }, /* NOT */ [NOT] { 16, 1, UNARY },
{ 15, 2, ARITH }, /* SLASH */ [SLASH] { 15, 2, ARITH },
{ 15, 2, ARITH }, /* PCT */ [PCT] { 15, 2, ARITH },
{ 12, 2, RELAT }, /* LT */ [LT] { 12, 2, RELAT },
{ 12, 2, RELAT }, /* GT */ [GT] { 12, 2, RELAT },
{ 9, 2, ARITH }, /* CIRC */ [CIRC] { 9, 2, ARITH },
{ 8, 2, ARITH }, /* OR */ [OR] { 8, 2, ARITH },
{ 5, 2, SPCL }, /* QUEST */ [QUEST] { 5, 2, SPCL },
{ 5, 2, SPCL }, /* COLON */ [COLON] { 5, 2, SPCL },
{ 0, 0, 0 }, /* ASGN */ [ASGN] { 0, 0, 0 },
{ 4, 2, 0 }, /* COMMA */ [COMMA] { 4, 2, 0 },
{ 0, 0, 0 }, /* SHARP */ [XCOMMA] { 4, 2, 0 },
{ 0, 0, 0 }, /* SEMIC */ [SHARP] { 0, 0, 0 },
{ 0, 0, 0 }, /* CBRA */ [SEMIC] { 0, 0, 0 },
{ 0, 0, 0 }, /* CKET */ [CBRA] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASPLUS */ [CKET] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASMINUS */ [ASPLUS] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASSTAR */ [ASMINUS] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASSLASH */ [ASSTAR] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASPCT */ [ASSLASH] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASCIRC */ [ASPCT] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASLSH */ [ASCIRC] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASRSH */ [ASLSH] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASOR */ [ASRSH] { 0, 0, 0 },
{ 0, 0, 0 }, /* ASAND */ [ASOR] { 0, 0, 0 },
{ 0, 0, 0 }, /* ELLIPS */ [ASAND] { 0, 0, 0 },
{ 0, 0, 0 }, /* DSHARP1 */ [ELLIPS] { 0, 0, 0 },
{ 0, 0, 0 }, /* NAME1 */ [DSHARP1] { 0, 0, 0 },
{ 16, 1, UNARY }, /* DEFINED */ [NAME1] { 0, 0, 0 },
{ 16, 0, UNARY }, /* UMINUS */ [DEFINED] { 16, 1, UNARY },
[UMINUS] { 16, 0, UNARY },
}; };
int evalop(struct pri); int evalop(struct pri);
@ -116,7 +117,7 @@ eval(Tokenrow *trp, int kw)
} }
ntok = trp->tp - trp->bp; ntok = trp->tp - trp->bp;
kwdefined->val = KDEFINED; /* activate special meaning of defined */ kwdefined->val = KDEFINED; /* activate special meaning of defined */
expandrow(trp, "<if>", Notinmacro); expandrow(trp, "<if>");
kwdefined->val = NAME; kwdefined->val = NAME;
vp = vals; vp = vals;
op = ops; op = ops;
@ -165,7 +166,7 @@ eval(Tokenrow *trp, int kw)
case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH: case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
case LAND: case LOR: case SLASH: case PCT: case LAND: case LOR: case SLASH: case PCT:
case LT: case GT: case CIRC: case OR: case QUEST: case LT: case GT: case CIRC: case OR: case QUEST:
case COLON: case COMMA: case COLON: case COMMA: case XCOMMA:
if (rand==0) if (rand==0)
goto syntax; goto syntax;
if (evalop(priority[tp->type])!=0) if (evalop(priority[tp->type])!=0)

View file

@ -18,7 +18,7 @@ doinclude(Tokenrow *trp)
goto syntax; goto syntax;
if (trp->tp->type!=STRING && trp->tp->type!=LT) { if (trp->tp->type!=STRING && trp->tp->type!=LT) {
len = trp->tp - trp->bp; len = trp->tp - trp->bp;
expandrow(trp, "<include>", Notinmacro); expandrow(trp, "<include>");
trp->tp = trp->bp+len; trp->tp = trp->bp+len;
} }
if (trp->tp->type==STRING) { if (trp->tp->type==STRING) {

View file

@ -138,7 +138,7 @@ syntax:
* Flag is NULL if more input can be gathered. * Flag is NULL if more input can be gathered.
*/ */
void void
expandrow(Tokenrow *trp, char *flag, int inmacro) expandrow(Tokenrow *trp, char *flag)
{ {
Token *tp; Token *tp;
Nlist *np; Nlist *np;
@ -170,7 +170,7 @@ expandrow(Tokenrow *trp, char *flag, int inmacro)
if (np->flag&ISMAC) if (np->flag&ISMAC)
builtin(trp, np->val); builtin(trp, np->val);
else { else {
expand(trp, np, inmacro); expand(trp, np);
} }
tp = trp->tp; tp = trp->tp;
} }
@ -184,7 +184,7 @@ expandrow(Tokenrow *trp, char *flag, int inmacro)
* (ordinarily the beginning of the expansion) * (ordinarily the beginning of the expansion)
*/ */
void void
expand(Tokenrow *trp, Nlist *np, int inmacro) expand(Tokenrow *trp, Nlist *np)
{ {
Tokenrow ntr; Tokenrow ntr;
int ntokc, narg, i; int ntokc, narg, i;
@ -193,12 +193,14 @@ expand(Tokenrow *trp, Nlist *np, int inmacro)
int hs; int hs;
copytokenrow(&ntr, np->vp); /* copy macro value */ copytokenrow(&ntr, np->vp); /* copy macro value */
if (np->ap==NULL) /* parameterless */ if (np->ap==NULL) { /* parameterless */
ntokc = 1; ntokc = 1;
else { /* substargs for handling # and ## */
atr[0] = nil;
substargs(np, &ntr, atr);
} else {
ntokc = gatherargs(trp, atr, (np->flag&ISVARMAC) ? rowlen(np->ap) : 0, &narg); ntokc = gatherargs(trp, atr, (np->flag&ISVARMAC) ? rowlen(np->ap) : 0, &narg);
if (narg<0) { /* not actually a call (no '(') */ if (narg<0) { /* not actually a call (no '(') */
/* error(WARNING, "%d %r\n", narg, trp); */
/* gatherargs has already pushed trp->tr to the next token */ /* gatherargs has already pushed trp->tr to the next token */
return; return;
} }
@ -214,8 +216,6 @@ expand(Tokenrow *trp, Nlist *np, int inmacro)
dofree(atr[i]); dofree(atr[i]);
} }
} }
if(!inmacro)
doconcat(&ntr); /* execute ## operators */
hs = newhideset(trp->tp->hideset, np); hs = newhideset(trp->tp->hideset, np);
for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */ for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */
if (tp->type==NAME) { if (tp->type==NAME) {
@ -228,8 +228,7 @@ expand(Tokenrow *trp, Nlist *np, int inmacro)
ntr.tp = ntr.bp; ntr.tp = ntr.bp;
insertrow(trp, ntokc, &ntr); insertrow(trp, ntokc, &ntr);
trp->tp -= rowlen(&ntr); trp->tp -= rowlen(&ntr);
dofree(ntr.bp); free(ntr.bp);
return;
} }
/* /*
@ -255,7 +254,6 @@ gatherargs(Tokenrow *trp, Tokenrow **atr, int dots, int *narg)
if (trp->tp >= trp->lp) { if (trp->tp >= trp->lp) {
gettokens(trp, 0); gettokens(trp, 0);
if ((trp->lp-1)->type==END) { if ((trp->lp-1)->type==END) {
/* error(WARNING, "reach END\n"); */
trp->lp -= 1; trp->lp -= 1;
if (*narg>=0) if (*narg>=0)
trp->tp -= ntok; trp->tp -= ntok;
@ -326,7 +324,25 @@ gatherargs(Tokenrow *trp, Tokenrow **atr, int dots, int *narg)
} }
return ntok; return ntok;
} }
int
ispaste(Tokenrow *rtr, Token **ap, Token **an, int *ntok)
{
*ap = nil;
*an = nil;
/* EMPTY ## tok */
if (rtr->tp->type == DSHARP && rtr->tp != rtr->bp)
rtr->tp--;
/* tok ## tok */
if(rtr->tp + 1 != rtr->lp && rtr->tp[1].type == DSHARP) {
*ap = rtr->tp;
if(rtr->tp + 2 != rtr->lp)
*an = rtr->tp + 2;
*ntok = 1 + (*ap != nil) + (*an != nil);
return 1;
}
return 0;
}
/* /*
* substitute the argument list into the replacement string * substitute the argument list into the replacement string
* This would be simple except for ## and # * This would be simple except for ## and #
@ -334,12 +350,14 @@ gatherargs(Tokenrow *trp, Tokenrow **atr, int dots, int *narg)
void void
substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr) substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr)
{ {
Tokenrow tatr; Tokenrow ttr;
Token *tp; Token *tp, *ap, *an, *pp, *pn;
int ntok, argno; int ntok, argno, hs;
for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) { for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) {
if (rtr->tp->type==SHARP) { /* string operator */ if(rtr->tp->hideset && checkhideset(rtr->tp->hideset, np)) {
rtr->tp++;
} else if (rtr->tp->type==SHARP) { /* string operator */
tp = rtr->tp; tp = rtr->tp;
rtr->tp += 1; rtr->tp += 1;
if ((argno = lookuparg(np, rtr->tp))<0) { if ((argno = lookuparg(np, rtr->tp))<0) {
@ -349,24 +367,52 @@ substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr)
ntok = 1 + (rtr->tp - tp); ntok = 1 + (rtr->tp - tp);
rtr->tp = tp; rtr->tp = tp;
insertrow(rtr, ntok, stringify(atr[argno])); insertrow(rtr, ntok, stringify(atr[argno]));
continue; } else if (ispaste(rtr, &ap, &an, &ntok)) { /* first token, just do the next one */
} pp = ap;
if (rtr->tp->type==NAME pn = an;
&& (argno = lookuparg(np, rtr->tp)) >= 0) { if (ap && (argno = lookuparg(np, ap)) >= 0){
if (rtr->tp < rtr->bp) pp = nil;
error(ERROR, "access out of bounds"); if(atr[argno]->tp != atr[argno]->lp)
if ((rtr->tp+1)->type==DSHARP pp = atr[argno]->lp - 1;
|| rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP)
insertrow(rtr, 1, atr[argno]);
else {
copytokenrow(&tatr, atr[argno]);
expandrow(&tatr, "<macro>", Inmacro);
insertrow(rtr, 1, &tatr);
dofree(tatr.bp);
} }
continue; if (an && (argno = lookuparg(np, an)) >= 0) {
pn = nil;
if(atr[argno]->tp != atr[argno]->lp)
pn = atr[argno]->lp - 1;
}
glue(&ttr, pp, pn);
insertrow(rtr, ntok, &ttr);
free(ttr.bp);
} else if (rtr->tp->type==NAME) {
if((argno = lookuparg(np, rtr->tp)) >= 0) {
if (rtr->tp < rtr->bp) {
error(ERROR, "access out of bounds");
continue;
}
copytokenrow(&ttr, atr[argno]);
expandrow(&ttr, "<macro>");
insertrow(rtr, 1, &ttr);
free(ttr.bp);
} else {
maketokenrow(1, &ttr);
ttr.lp = ttr.tp + 1;
*ttr.tp = *rtr->tp;
hs = newhideset(rtr->tp->hideset, np);
if(ttr.tp->hideset == 0)
ttr.tp->hideset = hs;
else
ttr.tp->hideset = unionhideset(ttr.tp->hideset, hs);
expandrow(&ttr, (char*)np->name);
for(tp = ttr.bp; tp != ttr.lp; tp++)
if(tp->type == COMMA)
tp->type = XCOMMA;
insertrow(rtr, 1, &ttr);
dofree(ttr.bp);
}
} else {
rtr->tp++;
} }
rtr->tp++;
} }
} }
@ -374,41 +420,35 @@ substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr)
* Evaluate the ## operators in a tokenrow * Evaluate the ## operators in a tokenrow
*/ */
void void
doconcat(Tokenrow *trp) glue(Tokenrow *ntr, Token *tp, Token *tn)
{ {
Token *ltp, *ntp; int np, nn;
Tokenrow ntr; char *tt, *p, *n;
int len;
for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) { np = tp ? tp->len : 0;
if (trp->tp->type==DSHARP1) nn = tn ? tn->len : 0;
trp->tp->type = DSHARP; tt = domalloc(np + nn + 1);
else if (trp->tp->type==DSHARP) { if(tp)
char tt[128]; memcpy(tt, tp->t, tp->len);
ltp = trp->tp-1; if(tn)
ntp = trp->tp+1; memcpy(tt+np, tn->t, tn->len);
if (ltp<trp->bp || ntp>=trp->lp) { tt[np+nn] = '\0';
error(ERROR, "## occurs at border of replacement"); setsource("<##>", -1, tt);
continue; maketokenrow(3, ntr);
} gettokens(ntr, 1);
len = ltp->len + ntp->len; unsetsource();
strncpy((char*)tt, (char*)ltp->t, ltp->len); dofree(tt);
strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len); if (np + nn == 0) {
tt[len] = '\0'; ntr->lp = ntr->bp;
setsource("<##>", -1, tt); } else {
maketokenrow(3, &ntr); if (ntr->lp - ntr->bp!=2 || ntr->bp->type==UNCLASS) {
gettokens(&ntr, 1); p = tp ? (char*)tp->t : "<empty>";
unsetsource(); n = tn ? (char*)tn->t : "<empty>";
if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS) error(WARNING, "Bad token %r produced by %s ## %s", &ntr, p, n);
error(WARNING, "Bad token %r produced by ##", &ntr);
ntr.lp = ntr.bp+1;
trp->tp = ltp;
makespace(&ntr);
insertrow(trp, (ntp-ltp)+1, &ntr);
dofree(ntr.bp);
trp->tp--;
} }
ntr->lp = ntr->bp+1;
} }
makespace(ntr);
} }
/* /*

View file

@ -1,4 +1,61 @@
#define M1() #define NOP(x) x
#define M2(A1) A1() #define CAT(a, b) a ## b
M2(M1) #define EOF (-1)
M2(P1) x NOP(CAT(foo, EOF)) y
x NOP(CAT(EOF, foo)) y
x CAT(, EOF) y
y CAT(foo,) x
x CAT(,foo) y
X NOP(CAT(,)) y
#define NCAT(a) foo ## a
NCAT(bar)
#define XCAT(a) ## a
foo XCAT(bar)
#define CAT3(foo) a##foo##b
CAT3(blah)
#define BAR 3
#define FOO CAT(BAR, 3)
FOO
/*
* CURRENTLY BROKEN:
* __VA_ARGS__ requires at least one item.
* It should accept an empty list.
#define xprint(a, ...) print(a, __VA_ARGS__)
xprint("hi", "there")
xprint("hi")
*/
#define C a,b
#define X(a) a
#define Y X(C)
Y
#define x 3
#define f(a) f(x * (a))
#undef x
#define x 2
#define g f
#define z z[0]
#define h g(~
#define m(a) a(w)
#define w 0,1
#define t(a) a
#define p() int
#define q(x) x
#define r(x,y) x ## y
#define str(x) # x
f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
g(x+(3,4)-w) | h 5) & m
(f)^m(m);
/*
* CURRENTLY BROKEN:
* mac() needs at least one argument.
* It should treat no args as a single empty arg list.
p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
char c[2][6] = { str(hello), str() };
*/

View file

@ -0,0 +1,49 @@
#line 1 "/usr/ori/src/cpp/test.c"
x fooEOF y
x EOFfoo y
x(-1) y
y foo x
x foo y
X y
foobar
foo ## bar
ablahb
33
#line 32 "/usr/ori/src/cpp/test.c"
a,b
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2+(3,4)- 0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^ m(0,1);
#line 55 "/usr/ori/src/cpp/test.c"