tccpp.c: fix GNU comma handling

This requires moving TOK_PLCHLDR handling, but the new logic should make
things easier even if (when?) GNU comma handling is removed.

(Somewhat confusingly, GCC no longer supports GNU commas. See
http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html for a description
of past and current GCC behaviour.)
master
Philip 2015-05-02 14:27:49 +00:00
parent 2f50cefbd4
commit 2f90db434e
2 changed files with 36 additions and 20 deletions

1
tcc.h
View File

@ -880,6 +880,7 @@ struct TCCState {
#define TOK_DOTS 0xcc /* three dots */ #define TOK_DOTS 0xcc /* three dots */
#define TOK_SHR 0xcd /* unsigned shift right */ #define TOK_SHR 0xcd /* unsigned shift right */
#define TOK_NOSUBST 0xcf /* means following token has already been pp'd */ #define TOK_NOSUBST 0xcf /* means following token has already been pp'd */
#define TOK_GNUCOMMA 0xd0 /* ,## preprocessing token */
#define TOK_SHL 0x01 /* shift left */ #define TOK_SHL 0x01 /* shift left */
#define TOK_SAR 0x02 /* signed shift right */ #define TOK_SAR 0x02 /* signed shift right */

55
tccpp.c
View File

@ -2786,25 +2786,18 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
if (gnu_ext && s->type.t && if (gnu_ext && s->type.t &&
last_tok == TOK_TWOSHARPS && last_tok == TOK_TWOSHARPS &&
str.len >= 2 && str.str[str.len - 2] == ',') { str.len >= 2 && str.str[str.len - 2] == ',') {
if (*st == TOK_PLCHLDR) { str.len -= 2;
/* suppress ',' '##' */ tok_str_add(&str, TOK_GNUCOMMA);
str.len -= 2;
} else {
/* suppress '##' and add variable */
str.len--;
goto add_var;
}
} else {
int t1;
add_var:
for(;;) {
TOK_GET(&t1, &st, &cval);
if (!t1)
break;
tok_str_add2(&str, t1, &cval);
}
} }
} else if (*st != TOK_PLCHLDR) {
for(;;) {
int t1;
TOK_GET(&t1, &st, &cval);
if (!t1)
break;
tok_str_add2(&str, t1, &cval);
}
} else {
/* NOTE: the stream cannot be read when macro /* NOTE: the stream cannot be read when macro
substituing an argument */ substituing an argument */
macro_subst(&str, nested_list, st, NULL); macro_subst(&str, nested_list, st, NULL);
@ -2817,6 +2810,8 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
} }
last_tok = t; last_tok = t;
} }
if (str.len == 0)
tok_str_add(&str, TOK_PLCHLDR);
tok_str_add(&str, 0); tok_str_add(&str, 0);
return str.str; return str.str;
} }
@ -2982,9 +2977,9 @@ static int macro_subst_tok(TokenString *tok_str,
tok_str_add2(&str, tok, &tokc); tok_str_add2(&str, tok, &tokc);
next_nomacro_spc(); next_nomacro_spc();
} }
if (!str.len)
tok_str_add(&str, TOK_PLCHLDR);
str.len -= spc; str.len -= spc;
if (str.len == 0)
tok_str_add(&str, TOK_PLCHLDR);
tok_str_add(&str, 0); tok_str_add(&str, 0);
sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
sa1->d = str.str; sa1->d = str.str;
@ -3123,6 +3118,7 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list,
CValue cval; CValue cval;
struct macro_level ml; struct macro_level ml;
int force_blank; int force_blank;
int gnucomma_index = -1;
/* first scan for '##' operator handling */ /* first scan for '##' operator handling */
ptr = macro_str; ptr = macro_str;
@ -3150,8 +3146,16 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list,
TOK_GET(&t, &ptr, &cval); TOK_GET(&t, &ptr, &cval);
goto no_subst; goto no_subst;
} }
if (t == TOK_GNUCOMMA) {
if (gnucomma_index != -1)
tcc_error("two GNU commas in the same macro");
gnucomma_index = tok_str->len;
tok_str_add(tok_str, ',');
TOK_GET(&t, &ptr, &cval);
}
s = define_find(t); s = define_find(t);
if (s != NULL) { if (s != NULL) {
int old_len = tok_str->len;
/* if nested substitution, do nothing */ /* if nested substitution, do nothing */
if (sym_find2(*nested_list, t)) { if (sym_find2(*nested_list, t)) {
/* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */
@ -3171,6 +3175,8 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list,
*can_read_stream = ml.prev; *can_read_stream = ml.prev;
if (parse_flags & PARSE_FLAG_SPACES) if (parse_flags & PARSE_FLAG_SPACES)
force_blank = 1; force_blank = 1;
if (old_len == tok_str->len)
tok_str_add(tok_str, TOK_PLCHLDR);
} else { } else {
no_subst: no_subst:
if (force_blank) { if (force_blank) {
@ -3181,6 +3187,15 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list,
if (!check_space(t, &spc)) if (!check_space(t, &spc))
tok_str_add2(tok_str, t, &cval); tok_str_add2(tok_str, t, &cval);
} }
if (gnucomma_index != -1) {
if (tok_str->len >= gnucomma_index+2) {
if (tok_str->str[gnucomma_index+1] == TOK_PLCHLDR)
tok_str->len -= 2;
gnucomma_index = -1;
}
}
if (tok_str->len && tok_str->str[tok_str->len-1] == TOK_PLCHLDR)
tok_str->len--;
} }
if (macro_str1) if (macro_str1)
tok_str_free(macro_str1); tok_str_free(macro_str1);