diff --git a/tcc.h b/tcc.h index 9955839..dda2fc1 100644 --- a/tcc.h +++ b/tcc.h @@ -836,6 +836,7 @@ struct TCCState { /* <-- */ #define TOK_TWOSHARPS 0xc0 /* ## preprocessing token */ +#define TOK_PLCHLDR 0xc1 /* placeholder token as defined in C99 */ #define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ #define TOK_ADDC1 0xc3 /* add with carry generation */ #define TOK_ADDC2 0xc4 /* add with carry use */ diff --git a/tccpp.c b/tccpp.c index c8beec5..dfdee50 100644 --- a/tccpp.c +++ b/tccpp.c @@ -2565,7 +2565,8 @@ ST_FUNC void next_nomacro(void) } while (is_space(tok)); } -/* substitute args in macro_str and return allocated string */ +/* substitute arguments in replacement lists in macro_str by the values in + args (field d) and return allocated string */ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) { int last_tok, t, spc; @@ -2622,7 +2623,7 @@ 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 == 0) { + if (*st == TOK_PLCHLDR) { /* suppress ',' '##' */ str.len -= 2; } else { @@ -2793,6 +2794,8 @@ 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; tok_str_add(&str, 0); sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); @@ -2885,9 +2888,11 @@ static inline int *macro_twosharps(const int *macro_str) TOK_GET(&t, &ptr, &cval); /* We concatenate the two tokens */ cstr_new(&cstr); - cstr_cat(&cstr, get_tok_str(tok, &tokc)); + if (tok != TOK_PLCHLDR) + cstr_cat(&cstr, get_tok_str(tok, &tokc)); n = cstr.size; - cstr_cat(&cstr, get_tok_str(t, &cval)); + if (t != TOK_PLCHLDR || tok == TOK_PLCHLDR) + cstr_cat(&cstr, get_tok_str(t, &cval)); cstr_ccat(&cstr, '\0'); tcc_open_bf(tcc_state, ":paste:", cstr.size); @@ -2904,8 +2909,35 @@ static inline int *macro_twosharps(const int *macro_str) cstr_free(&cstr); } } - if (tok != TOK_NOSUBST) + if (tok != TOK_NOSUBST) { + const int *oldptr; + CValue cval; + + /* Check if a space need to be added after ## concatenation in + order to avoid misinterpreting the newly formed token + followed by the next token as being a single token (see + macro_concat test) */ + cstr_new(&cstr); + cstr_cat(&cstr, get_tok_str(tok, &tokc)); + oldptr = ptr; + TOK_GET(&t, &ptr, &cval); + ptr = oldptr; + cstr_cat(&cstr, get_tok_str(t, &cval)); + cstr_ccat(&cstr, '\0'); + t = tok; + cval = tokc; + tcc_open_bf(tcc_state, ":paste:", cstr.size); + memcpy(file->buffer, cstr.data, cstr.size); + next_nomacro1(); + if (!*file->buf_ptr) { + tok_str_add2(¯o_str1, t, &cval); + tok = ' '; + } + tcc_close(); + cstr_free(&cstr); + start_of_nosubsts = -1; + } tok_str_add2(¯o_str1, tok, &tokc); } tok_str_add(¯o_str1, 0); diff --git a/tests/tests2/67_macro_concat.c b/tests/tests2/67_macro_concat.c new file mode 100644 index 0000000..c580d3a --- /dev/null +++ b/tests/tests2/67_macro_concat.c @@ -0,0 +1,14 @@ +#include + +#define P(A,B) A ## B ; bob +#define Q(A,B) A ## B+ + +int main(void) +{ + int bob, jim = 21; + bob = P(jim,) *= 2; + printf("jim: %d, bob: %d\n", jim, bob); + jim = 60 Q(+,)3; + printf("jim: %d\n", jim); + return 0; +} diff --git a/tests/tests2/67_macro_concat.expect b/tests/tests2/67_macro_concat.expect new file mode 100644 index 0000000..8386c2d --- /dev/null +++ b/tests/tests2/67_macro_concat.expect @@ -0,0 +1,2 @@ +jim: 21, bob: 42 +jim: 63 diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index 41adb2d..a7c8a2f 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -81,7 +81,8 @@ TESTS = \ 63_local_enumerator_redefinition.test \ 64_macro_nesting.test \ 65_macro_concat_start.test \ - 66_macro_concat_end.test + 66_macro_concat_end.test \ + 67_macro_concat.test # 30_hanoi.test -- seg fault in the code, gcc as well # 34_array_assignment.test -- array assignment is not in C standard