diff --git a/tcc.h b/tcc.h index 384e8de..aeb44fc 100644 --- a/tcc.h +++ b/tcc.h @@ -880,6 +880,7 @@ struct TCCState { #define TOK_DOTS 0xcc /* three dots */ #define TOK_SHR 0xcd /* unsigned shift right */ #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_SAR 0x02 /* signed shift right */ diff --git a/tccpp.c b/tccpp.c index 0a99832..f884b37 100644 --- a/tccpp.c +++ b/tccpp.c @@ -2771,14 +2771,11 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) if (gnu_ext && s->type.t && last_tok == TOK_TWOSHARPS && str.len >= 2 && str.str[str.len - 2] == ',') { - if (*st == TOK_PLCHLDR) { - /* suppress ',' '##' */ - str.len -= 2; - } else { - /* suppress '##' and add variable */ - str.len--; - goto add_var; - } + str.len -= 2; + tok_str_add(&str, TOK_GNUCOMMA); + str.str[str.len] = 0; + + goto add_var; } else { int t1; add_var: @@ -2789,7 +2786,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) tok_str_add2(&str, t1, &cval); } } - } else if (*st != TOK_PLCHLDR) { + } else { /* NOTE: the stream cannot be read when macro substituing an argument */ macro_subst(&str, nested_list, st, NULL); @@ -2802,6 +2799,8 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) } last_tok = t; } + if (str.len == 0) + tok_str_add(&str, TOK_PLCHLDR); tok_str_add(&str, 0); return str.str; } @@ -2942,9 +2941,9 @@ static int macro_subst_tok(TokenString *tok_str, tok_str_add2(&str, tok, &tokc); next_nomacro_spc(); } - if (!str.len) - tok_str_add(&str, TOK_PLCHLDR); str.len -= spc; + if (str.len == 0) + tok_str_add(&str, TOK_PLCHLDR); tok_str_add(&str, 0); sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); sa1->d = str.str; @@ -3039,13 +3038,15 @@ static inline int *macro_twosharps(const int *macro_str) if (tok != TOK_PLCHLDR) cstr_cat(&cstr, get_tok_str(tok, &tokc)); n = cstr.size; - if (t != TOK_PLCHLDR || tok == TOK_PLCHLDR) + if (t != TOK_PLCHLDR) cstr_cat(&cstr, get_tok_str(t, &cval)); cstr_ccat(&cstr, '\0'); tcc_open_bf(tcc_state, ":paste:", cstr.size); memcpy(file->buffer, cstr.data, cstr.size); for (;;) { + if (0 == *file->buf_ptr) + break; next_nomacro1(); if (0 == *file->buf_ptr) break; @@ -3082,6 +3083,7 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, CValue cval; struct macro_level ml; int force_blank; + int gnucomma_index = -1; /* first scan for '##' operator handling */ ptr = macro_str; @@ -3106,8 +3108,16 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, TOK_GET(&t, &ptr, &cval); 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); if (s != NULL) { + int old_length = tok_str->len; /* if nested substitution, do nothing */ if (sym_find2(*nested_list, t)) { /* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */ @@ -3120,6 +3130,8 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, macro_ptr = (int *)ptr; tok = t; ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); + if (old_length == tok_str->len) + tok_str_add(tok_str, TOK_PLCHLDR); ptr = (int *)macro_ptr; macro_ptr = ml.p; if (can_read_stream && *can_read_stream == &ml) @@ -3138,6 +3150,12 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, if (!check_space(t, &spc)) tok_str_add2(tok_str, t, &cval); } + if (gnucomma_index != -1 && + tok_str->len >= gnucomma_index+2 && + tok_str->str[gnucomma_index+1] == TOK_PLCHLDR) + tok_str->str[gnucomma_index] = ' '; + if (tok_str->len && tok_str->str[tok_str->len-1] == TOK_PLCHLDR) + tok_str->len--; } if (macro_str1) tok_str_free(macro_str1);