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