diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index fd03ace..819af60 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -54,7 +54,9 @@ novirtual class AssignGenMixin: 位宽规则(供 define 物化用): - 显式强转(Call 的 callee 是整型/typedef,如 WORD / int / t.CUInt16T)→ 该位宽; - Name 引用其它 define → 沿用其位宽; - - BinOp:两侧位宽**相等** → 保持该位宽(**不提升**);不等 → 取较宽;任一未知 → 未知; + - BinOp:操作数的**声明宽度**保持最小(不提升),基准取较宽者;`+ - * <<` 的结果若装不进 + 基准宽度,就**按结果值加宽**(向上取到 8/16/32/64)—— 静态计算不允许回绕; + 基准未知(如纯字面量算式)→ 保持未知,仍由物化端按值推断; - 字面量/一元 → 未知(物化时按值推断)。 pool 为 None 时无法解析 typedef(仅旧调用方走此路),强转按"取实参值、位宽未知"处理。 """ @@ -79,31 +81,56 @@ novirtual class AssignGenMixin: rb: int = 0 left_val: int64 = self.extract_cdefine_int_value_bits(bop.left, pool, &lb) right_val: int64 = self.extract_cdefine_int_value_bits(bop.right, pool, &rb) - if bits_out is not None: - if lb != 0 and rb != 0: bits_out[0] = lb if lb > rb else rb - elif lb != 0: bits_out[0] = lb - elif rb != 0: bits_out[0] = rb - if bop.op == ast.OpKind.BitOr: return left_val | right_val - if bop.op == ast.OpKind.BitAnd: return left_val & right_val - if bop.op == ast.OpKind.BitXor: return left_val ^ right_val + # 操作数位宽(各自的**声明宽度**,保持最小、不提升):两侧不等取较宽,一侧未知则沿用另一侧 + wbase: int = 0 + if lb != 0 and rb != 0: wbase = lb if lb > rb else rb + elif lb != 0: wbase = lb + elif rb != 0: wbase = rb + res: int64 = 0 + if bop.op == ast.OpKind.BitOr: res = left_val | right_val + elif bop.op == ast.OpKind.BitAnd: res = left_val & right_val + elif bop.op == ast.OpKind.BitXor: res = left_val ^ right_val # 移位:求值器内部按 64 位算,计数为负或 >= 64 时结果无意义(宿主侧是 poison/未定义), # 与 require_shift_count_in_range 同一口径直接 fail-fast,不产出垃圾常量。 - if bop.op == ast.OpKind.LShift or bop.op == ast.OpKind.RShift: + elif bop.op == ast.OpKind.LShift or bop.op == ast.OpKind.RShift: if right_val < 0 or right_val >= 64: self.Gen.TypeGenErr.fatal_error(val_node, f"constant expression shift count out of range: the shift count evaluates to {right_val} at compile time, " "but the evaluator works on 64-bit integers (valid range 0..63); the result would be undefined. " "Fix: use a count in 0..63, or restructure the expression.", "ValueError") - if bop.op == ast.OpKind.LShift: return left_val << right_val - return left_val >> right_val - if bop.op == ast.OpKind.Add: return left_val + right_val - if bop.op == ast.OpKind.Sub: return left_val - right_val - if bop.op == ast.OpKind.Mult: return left_val * right_val + if bop.op == ast.OpKind.LShift: res = left_val << right_val + else: res = left_val >> right_val + elif bop.op == ast.OpKind.Add: res = left_val + right_val + elif bop.op == ast.OpKind.Sub: res = left_val - right_val + elif bop.op == ast.OpKind.Mult: res = left_val * right_val # 编译期除零:绝不把除法交给宿主(会直接把编译器打挂),fail-fast 给出可读诊断。 - if bop.op == ast.OpKind.Div or bop.op == ast.OpKind.FloorDiv or bop.op == ast.OpKind.Mod: + elif bop.op == ast.OpKind.Div or bop.op == ast.OpKind.FloorDiv or bop.op == ast.OpKind.Mod: if right_val == 0: self.Gen.TypeGenErr.fatal_error(val_node, "constant expression division by zero: the right operand of '/', '//' or '%' evaluates to 0 at compile time.", "ValueError") - if bop.op == ast.OpKind.Mod: return left_val % right_val - return left_val // right_val - # Unknown BinOp operator: fail fast - self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError") + if bop.op == ast.OpKind.Mod: res = left_val % right_val + else: res = left_val // right_val + else: + # Unknown BinOp operator: fail fast(不能静默返回 0) + self.Gen.TypeGenErr.fatal_error(val_node, "CDefine value extraction failed: cannot parse a compile-time constant from the expression", "TypeError") + if bits_out is not None: + # 静态计算**自行拓宽**:字面量/define 的声明宽度仍保持最小(不提升),但 `+ - * <<` + # 的精确结果可能比操作数宽 —— 若照操作数宽度物化就会静默回绕 + # (现场:define A=8192(最小 16 位)的 `A*24+512` 被按 16 位物化成 512)。 + # 规则:以操作数的“较宽”为基准,再用**结果值**算精确可容纳位宽,只有装不下才加宽 + # (不无故提升,避免把 `CDefine + 1` 这类算式整体抬成 i64 引出新的“隐式窄化”报错); + # 基准未知(wbase==0,如纯字面量算式)时保持“未知”,仍由物化端按值推断。 + w: int = wbase + if w > 0 and res != 0: + t: int64 = res + if res < 0: t = res ^ int64(-1) + vw: int = 1 # 符号位 + while t != 0: + vw += 1 + t = t >> 1 + if vw > w: w = vw + if w > 0: + if w <= 8: bits_out[0] = 8 + elif w <= 16: bits_out[0] = 16 + elif w <= 32: bits_out[0] = 32 + else: bits_out[0] = 64 + return res # Case 3: Name - a registered CDefine constant or True/False literal if k == ast.ASTKind.Name: