diff --git a/tccpp.c b/tccpp.c index fa29ca9..59e3603 100644 --- a/tccpp.c +++ b/tccpp.c @@ -2994,8 +2994,30 @@ static int macro_subst_tok(TokenString *tok_str, else break; } - if (tok != ',') - expect(","); + /* + * #define f(a) f(a) + * #define h f(r + * h 5) + */ + if (tok != ',') { + /* Argh! Not a macro invocation after all, at this + * point, so put everything back onto mstr that's + * been skipped since we saw the '(' )*/ + tok_str_new(&str); + tok_str_add(&str, mtok); + tok_str_add(&str, '('); + for (sa = s->next; sa; sa = sa->next) { + int *p = sa->d; + while (p && *p) { + tok_str_add(&str, *p); + p++; + } + mstr = str.str; + /* leak memory */; + mstr_allocated = 0; + goto free_memory; + } + } next_nomacro(); } if (sa) { @@ -3005,6 +3027,7 @@ static int macro_subst_tok(TokenString *tok_str, /* now subst each arg */ mstr = macro_arg_subst(nested_list, mstr, args); + free_memory: /* free memory */ sa = args; while (sa) { @@ -3056,8 +3079,6 @@ static inline int *macro_twosharps(const int *macro_str) TOK_GET(&tok, &ptr, &tokc); if (tok == 0) break; - if (tok == TOK_TWOSHARPS) - continue; if (tok == TOK_NOSUBST && start_of_nosubsts < 0) start_of_nosubsts = macro_str1.len; while (*ptr == TOK_TWOSHARPS) { @@ -3077,13 +3098,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; @@ -3094,13 +3117,22 @@ static inline int *macro_twosharps(const int *macro_str) tcc_close(); cstr_free(&cstr); } + if (tok == TOK_TWOSHARPS) { + /* two sharps twosharped together tokenize to two + * sharp tokens, not a twosharp token. */ + /* That's fun to say, but is it actually true? GCC + * stringifies #define a # ## # ## # to "## #" (and a + * warning), while we produce "###" (no warning) */ + tok_str_add(¯o_str1, '#'); + tok = '#'; + } } if (tok != TOK_NOSUBST) { tok_str_add2(¯o_str1, tok, &tokc); tok = ' '; start_of_nosubsts = -1; - } - tok_str_add2(¯o_str1, tok, &tokc); + } else + tok_str_add2(¯o_str1, tok, &tokc); } tok_str_add(¯o_str1, 0); return macro_str1.str; @@ -3119,7 +3151,6 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, int t, spc; CValue cval; struct macro_level ml; - int force_blank; int gnucomma_index = -1; /* first scan for '##' operator handling */ @@ -3129,7 +3160,6 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, if (macro_str1) ptr = macro_str1; spc = 0; - force_blank = 0; while (1) { /* NOTE: ptr == NULL can only happen if tokens are read from @@ -3175,18 +3205,11 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, macro_ptr = ml.p; if (can_read_stream && *can_read_stream == &ml) *can_read_stream = ml.prev; - if (parse_flags & PARSE_FLAG_SPACES) - force_blank = 1; if (old_len == tok_str->len) tok_str_add(tok_str, TOK_PLCHLDR); } else { no_subst: - if (force_blank) { - tok_str_add(tok_str, ' '); - spc = 1; - force_blank = 0; - } - if (!check_space(t, &spc)) + if (!check_space(t, &spc)) tok_str_add2(tok_str, t, &cval); } if (gnucomma_index != -1) { diff --git a/tests/tests2/80_macros.c b/tests/tests2/80_macros.c new file mode 100644 index 0000000..4db2650 --- /dev/null +++ b/tests/tests2/80_macros.c @@ -0,0 +1,46 @@ +#include + +#define A(a,b...) g(a,##b,##b) +#define B(x...) x +#define C \ + +#define D(x,y) x ## y +#define E(x,y,z) x ## y ## z +#define F(x) x +#define G C +#define H() F + +#define STRINGIFY2(x) #x +#define STRINGIFY(x) STRINGIFY2(x) + +int main(void) +{ + printf("%s\n", STRINGIFY()); // should produce the empty string + printf("%s\n", STRINGIFY(C)); // should produce the empty string + printf("%s\n", STRINGIFY( + A(a,) + A(a,b) + A(a,b,c) + )); // should produce g(a ) g(a,b,b)g(a,b,c,b,c) + printf("%s\n", STRINGIFY(B())); // should produce the empty string + printf("%s\n", STRINGIFY(B(C))); // should produce the empty string + printf("%s\n", STRINGIFY(D(,))); // should produce the empty string + printf("%s\n", STRINGIFY(E(1,,))); // should produce 1 + printf("%s\n", STRINGIFY(E(,2,))); // should produce 2 + printf("%s\n", STRINGIFY(E(,,3))); // should produce 3 + printf("%s\n", STRINGIFY(E(1,2,3))); // should produce 123 + + // should produce g(a ) g(a )g(a )g(a )g(a ) + printf("%s\n", STRINGIFY(A(a,F()) A(a,C) A(a,G) A(a,) A(a))); + printf("%s\n", STRINGIFY(H()x)); + + // should produce F x, not Fx + printf("%s\n", STRINGIFY(H() +x)); + + printf("%s\n", STRINGIFY(I x)); + printf("%s\n", STRINGIFY(I +x)); + + return 0; +} diff --git a/tests/tests2/80_macros.expect b/tests/tests2/80_macros.expect new file mode 100644 index 0000000..0394cd3 --- /dev/null +++ b/tests/tests2/80_macros.expect @@ -0,0 +1,15 @@ + + +g(a) g(a,b,b) g(a,b,c,b,c) + + + +1 +2 +3 +123 +g(a) g(a) g(a) g(a) g(a) +Fx +F x +I x +I x diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index a441674..97c22dc 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -98,7 +98,8 @@ TESTS = \ 76_dollars_in_identifiers.test \ 77_push_pop_macro.test \ 78_vla_label.test \ - 79_vla_continue.test + 79_vla_continue.test \ + 80_macros.test # 34_array_assignment.test -- array assignment is not in C standard