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.)
Unified · Split
| @@ -880,6 +880,7 @@ struct TCCState { · 879 unmodified lines | ||
| 880 | 880 | #define TOK_DOTS 0xcc /* three dots */ |
| 881 | 881 | #define TOK_SHR 0xcd /* unsigned shift right */ |
| 882 | 882 | #define TOK_NOSUBST 0xcf /* means following token has already been pp'd */ |
| 883 | +#define TOK_GNUCOMMA 0xd0 /* ,## preprocessing token */ | |
| 883 | 884 | |
| 884 | 885 | #define TOK_SHL 0x01 /* shift left */ |
| 885 | 886 | #define TOK_SAR 0x02 /* signed shift right */ |
| @@ -2786,25 +2786,18 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) · 2785 unmodified lines | ||
| 2786 | 2786 | if (gnu_ext && s->type.t && |
| 2787 | 2787 | last_tok == TOK_TWOSHARPS && |
| 2788 | 2788 | str.len >= 2 && str.str[str.len - 2] == ',') { |
| 2789 | − if (*st == TOK_PLCHLDR) { | |
| 2790 | − /* suppress ',' '##' */ | |
| 2791 | − str.len -= 2; | |
| 2792 | − } else { | |
| 2793 | − /* suppress '##' and add variable */ | |
| 2794 | − str.len--; | |
| 2795 | − goto add_var; | |
| 2796 | − } | |
| 2797 | − } else { | |
| 2789 | + str.len -= 2; | |
| 2790 | + tok_str_add(&str, TOK_GNUCOMMA); | |
| 2791 | + } | |
| 2792 | + | |
| 2793 | + for(;;) { | |
| 2798 | 2794 | int t1; |
| 2799 | − add_var: | |
| 2800 | − for(;;) { | |
| 2801 | − TOK_GET(&t1, &st, &cval); | |
| 2802 | − if (!t1) | |
| 2803 | − break; | |
| 2804 | − tok_str_add2(&str, t1, &cval); | |
| 2805 | − } | |
| 2795 | + TOK_GET(&t1, &st, &cval); | |
| 2796 | + if (!t1) | |
| 2797 | + break; | |
| 2798 | + tok_str_add2(&str, t1, &cval); | |
| 2806 | 2799 | } |
| 2807 | − } else if (*st != TOK_PLCHLDR) { | |
| 2800 | + } else { | |
| 2808 | 2801 | /* NOTE: the stream cannot be read when macro |
| 2809 | 2802 | substituing an argument */ |
| 2810 | 2803 | 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) · 6 unmodified lines | ||
| 2817 | 2810 | } |
| 2818 | 2811 | last_tok = t; |
| 2819 | 2812 | } |
| 2813 | + if (str.len == 0) | |
| 2814 | + tok_str_add(&str, TOK_PLCHLDR); | |
| 2820 | 2815 | tok_str_add(&str, 0); |
| 2821 | 2816 | return str.str; |
| 2822 | 2817 | } |
| @@ -2982,9 +2977,9 @@ static int macro_subst_tok(TokenString *tok_str, · 159 unmodified lines | ||
| 2982 | 2977 | tok_str_add2(&str, tok, &tokc); |
| 2983 | 2978 | next_nomacro_spc(); |
| 2984 | 2979 | } |
| 2985 | − if (!str.len) | |
| 2986 | − tok_str_add(&str, TOK_PLCHLDR); | |
| 2987 | 2980 | str.len -= spc; |
| 2981 | + if (str.len == 0) | |
| 2982 | + tok_str_add(&str, TOK_PLCHLDR); | |
| 2988 | 2983 | tok_str_add(&str, 0); |
| 2989 | 2984 | sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0); |
| 2990 | 2985 | sa1->d = str.str; |
| @@ -3123,6 +3118,7 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, · 132 unmodified lines | ||
| 3123 | 3118 | CValue cval; |
| 3124 | 3119 | struct macro_level ml; |
| 3125 | 3120 | int force_blank; |
| 3121 | + int gnucomma_index = -1; | |
| 3126 | 3122 | |
| 3127 | 3123 | /* first scan for '##' operator handling */ |
| 3128 | 3124 | ptr = macro_str; |
| @@ -3150,8 +3146,16 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, · 21 unmodified lines | ||
| 3150 | 3146 | TOK_GET(&t, &ptr, &cval); |
| 3151 | 3147 | goto no_subst; |
| 3152 | 3148 | } |
| 3149 | + if (t == TOK_GNUCOMMA) { | |
| 3150 | + if (gnucomma_index != -1) | |
| 3151 | + tcc_error("two GNU commas in the same macro"); | |
| 3152 | + gnucomma_index = tok_str->len; | |
| 3153 | + tok_str_add(tok_str, ','); | |
| 3154 | + TOK_GET(&t, &ptr, &cval); | |
| 3155 | + } | |
| 3153 | 3156 | s = define_find(t); |
| 3154 | 3157 | if (s != NULL) { |
| 3158 | + int old_len = tok_str->len; | |
| 3155 | 3159 | /* if nested substitution, do nothing */ |
| 3156 | 3160 | if (sym_find2(*nested_list, t)) { |
| 3157 | 3161 | /* 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, · 13 unmodified lines | ||
| 3171 | 3175 | *can_read_stream = ml.prev; |
| 3172 | 3176 | if (parse_flags & PARSE_FLAG_SPACES) |
| 3173 | 3177 | force_blank = 1; |
| 3178 | + if (old_len == tok_str->len) | |
| 3179 | + tok_str_add(tok_str, TOK_PLCHLDR); | |
| 3174 | 3180 | } else { |
| 3175 | 3181 | no_subst: |
| 3176 | 3182 | if (force_blank) { |
| @@ -3181,6 +3187,15 @@ static void macro_subst(TokenString *tok_str, Sym **nested_list, · 4 unmodified lines | ||
| 3181 | 3187 | if (!check_space(t, &spc)) |
| 3182 | 3188 | tok_str_add2(tok_str, t, &cval); |
| 3183 | 3189 | } |
| 3190 | + if (gnucomma_index != -1) { | |
| 3191 | + if (tok_str->len >= gnucomma_index+2) { | |
| 3192 | + if (tok_str->str[gnucomma_index+1] == TOK_PLCHLDR) | |
| 3193 | + tok_str->len -= 2; | |
| 3194 | + gnucomma_index = -1; | |
| 3195 | + } | |
| 3196 | + } | |
| 3197 | + if (tok_str->len && tok_str->str[tok_str->len-1] == TOK_PLCHLDR) | |
| 3198 | + tok_str->len--; | |
| 3184 | 3199 | } |
| 3185 | 3200 | if (macro_str1) |
| 3186 | 3201 | tok_str_free(macro_str1); |