fix: result of #if macro expr is wrong when has recursive trinary '?:'
authoryu.dongliang <18588496441@163.com>
Sun, 5 Jul 2026 04:40:59 +0000 (12:40 +0800)
committeryu.dongliang <18588496441@163.com>
Sun, 5 Jul 2026 04:40:59 +0000 (12:40 +0800)
lex/scf_macro_expr.c

index a1a3aa16d454e7b67efb2832323e029ed039e7d9..e5ae60d80fc07cfef66d57b7f01e13ddc8867fba 100644 (file)
@@ -6,6 +6,9 @@ typedef struct {
        scf_lex_word_t**  pp;
        scf_lex_word_t*   error;
 
+       int               n_q_masks;
+       int               n_colons;
+
        int               n_lps;
        int               n_rps;
 } scf_macro_ctx_t;
@@ -144,7 +147,7 @@ static int __macro_binary_##name(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_w
        } \
        \
        w0->data.i64 = w0->data.i64 op w1->data.i64; \
-       scf_logi("op: %s, result: %ld, line: %d, pos: %d\n", w_op->text->data, w0->data.i64, w_op->line, w_op->pos); \
+       scf_logi("op: %s, result: %ld, line: %d, pos: %d\n\n", w_op->text->data, w0->data.i64, w_op->line, w_op->pos); \
        \
        *operand = w0; \
        return 0; \
@@ -274,6 +277,8 @@ static int __macro_operator_cond(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_w
                return -EINVAL;
        }
 
+       ctx->n_q_masks++;
+
        scf_lex_word_t*  cond   = *operand;
        scf_lex_word_t*  _true  = NULL;
        scf_lex_word_t*  _false = NULL;
@@ -316,6 +321,7 @@ static int __macro_operator_cond(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_w
                        break;
 
                case SCF_LEX_WORD_COLON:
+                       ctx->n_colons++;
                        break;
                default:
                        scf_loge("'%s' is NOT ':' after '?', file: %s, line: %d, pos: %d\n",
@@ -324,17 +330,31 @@ static int __macro_operator_cond(scf_lex_t* lex, scf_macro_ctx_t* ctx, scf_lex_w
                        break;
        };
 
-       ret = __macro_unary_operand(lex, ctx, &_false);
-       if (ret < 0)
-               return ret;
+       while (1) {
+               _false = NULL;
+
+               ret = __macro_unary_operand(lex, ctx, &_false);
+               if (ret < 0)
+                       return ret;
+
+               if (SCF_LEX_WORD_COLON != _false->type)
+                       break;
+
+               if (++ctx->n_colons > ctx->n_q_masks) {
+
+                       scf_loge("too many '%s' after '?', file: %s, line: %d, pos: %d\n",
+                                       _false->text->data, _false->file->data, _false->line, _false->pos);
+                       return -EINVAL;
+               }
+       }
 
        if (cond->data.u64)
                *operand = _true;
        else
                *operand = _false;
 
-       scf_logi("op: %s, flag: %d, result: %ld, line: %d, pos: %d\n",
-                       w_op->text->data, !!cond->data.u64, (*operand)->data.i64, w_op->line, w_op->pos);
+       scf_logi("op: %s, flag: %d, result: %ld, true: %ld, false: %ld, line: %d, pos: %d\n\n",
+                       w_op->text->data, !!cond->data.u64, (*operand)->data.i64, _true->data.i64, _false->data.i64, w_op->line, w_op->pos);
        return 0;
 }
 
@@ -512,7 +532,7 @@ int __macro_if_expr(scf_lex_t* lex)
        scf_lex_word_t*  operand = NULL;
        scf_lex_word_t*  w   = NULL;
        scf_lex_word_t*  h   = NULL;
-       scf_macro_ctx_t  ctx = {&h, 0, 0};
+       scf_macro_ctx_t  ctx = {&h, 0, 0, 0, 0};
 
        int ret = 0;