feat(handles): 实现 c.CIf/c.CIfdef/c.CIfndef 编译期宏(对齐 TPC HandlesIf)
- 常量表达式求值: CDefine/跨模块 CDefine/平台宏 + 算术/比较/逻辑/位运算 - 编译期剪枝: 命中分支只编译, elif 递归, 未定义名特判(CIfdef 走 else/CIfndef 走 then, 不报错) - 求值失败(运行时变量)回退运行时翻译(HandlesExprCall: CIf 真值比较/CIfdef 恒真)
This commit is contained in:
1 parent
57d6ffefad
commit
e79b676e51
1 file changed
+392
@@ -10,6 +10,365 @@ import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesBody as HandlesBody
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
|
||||
#
|
||||
# 对齐 TPC HandlesIf.py:编译期求值命中分支并剪枝(不发射运行时 IR)。
|
||||
# c.CIf(expr) → 常量表达式求值(CDefine/平台宏/算术/比较/逻辑)
|
||||
# c.CIfdef(NAME) → NAME 已定义?(本地 CDefine / 跨模块 CDefine / 平台宏)
|
||||
# c.CIfndef(NAME) → NAME 未定义? ← 未定义名特判:返回"未定义"而非报错
|
||||
#
|
||||
# 求值失败(如运行时变量 val == 1)→ 回退运行时翻译
|
||||
# (c.CIf 由 HandlesExprCall.translate_call 特判翻译成运行时真值,
|
||||
# c.CIfdef/c.CIfndef 运行时恒真,对齐 TPC HandlesExprCall.py L2434-2446)。
|
||||
# ============================================================
|
||||
|
||||
_g_cif_eval_ok: int = 0
|
||||
|
||||
|
||||
def _is_cif_attr(attr: str) -> int:
|
||||
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)"""
|
||||
if attr is None:
|
||||
return 0
|
||||
if string.strcmp(attr, "CIf") == 0: return 1
|
||||
if string.strcmp(attr, "CIfdef") == 0: return 1
|
||||
if string.strcmp(attr, "CIfndef") == 0: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _is_cif_call(node: ast.AST | t.CPtr) -> int:
|
||||
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
|
||||
if node is None or node.kind() != ast.ASTKind.Call:
|
||||
return 0
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl.func is None:
|
||||
return 0
|
||||
fk: int = cl.func.kind()
|
||||
if fk == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if at.attr is None:
|
||||
return 0
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if vn.id is not None and string.strcmp(vn.id, "c") == 0:
|
||||
return _is_cif_attr(at.attr)
|
||||
return 0
|
||||
if fk == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
|
||||
if nm.id is not None and _is_cif_attr(nm.id) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _get_platform_macro_value(name: str) -> int:
|
||||
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
|
||||
|
||||
命中置 _g_cif_eval_ok=1;未命中置 0 返回 0。
|
||||
"""
|
||||
global _g_cif_eval_ok
|
||||
_g_cif_eval_ok = 0
|
||||
if name is None:
|
||||
return 0
|
||||
triple: str = Config.TargetTriple
|
||||
if triple is None:
|
||||
triple = "x86_64-pc-windows-gnu"
|
||||
is_win: int = 0
|
||||
is_linux: int = 0
|
||||
is_x64: int = 0
|
||||
if string.strstr(triple, "windows") is not None \
|
||||
or string.strstr(triple, "win32") is not None \
|
||||
or string.strstr(triple, "mingw") is not None \
|
||||
or string.strstr(triple, "msvc") is not None:
|
||||
is_win = 1
|
||||
if string.strstr(triple, "linux") is not None:
|
||||
is_linux = 1
|
||||
if string.strstr(triple, "x86_64") is not None:
|
||||
is_x64 = 1
|
||||
# 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致)
|
||||
if string.strcmp(name, "_WIN32") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
|
||||
if string.strcmp(name, "WIN32") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
|
||||
if string.strcmp(name, "_WIN64") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
|
||||
if string.strcmp(name, "WIN64") == 0: _g_cif_eval_ok = is_win; return 1 if is_win else 0
|
||||
if string.strcmp(name, "__linux__") == 0: _g_cif_eval_ok = is_linux; return 1 if is_linux else 0
|
||||
if string.strcmp(name, "__x86_64__") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
|
||||
if string.strcmp(name, "__x86_64") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
|
||||
if string.strcmp(name, "_M_X64") == 0: _g_cif_eval_ok = is_x64; return 1 if is_x64 else 0
|
||||
if string.strcmp(name, "SIZEOF_VOID_P") == 0: _g_cif_eval_ok = 1; return 8 if is_x64 else 4
|
||||
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: _g_cif_eval_ok = 1; return 8 if is_x64 else 4
|
||||
if string.strcmp(name, "NDEBUG") == 0: _g_cif_eval_ok = 1; return 0
|
||||
return 0
|
||||
|
||||
|
||||
def _cif_name_value(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
name: str) -> int:
|
||||
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
|
||||
|
||||
命中置 _g_cif_eval_ok=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
|
||||
"""
|
||||
global _g_cif_eval_ok
|
||||
_g_cif_eval_ok = 0
|
||||
if name is None or trans is None:
|
||||
return 0
|
||||
v: int = HandlesType.lookup_cdefine_constant(name)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
_g_cif_eval_ok = 1
|
||||
return v
|
||||
v2: int = HandlesExpr._lookup_cross_module_cdefine(
|
||||
pool, name, trans._from_imports, trans._imported_modules)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
_g_cif_eval_ok = 1
|
||||
return v2
|
||||
pv: int = _get_platform_macro_value(name)
|
||||
if _g_cif_eval_ok != 0:
|
||||
return pv
|
||||
return 0
|
||||
|
||||
|
||||
def _cif_attr_value(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
at: ast.Attribute | t.CPtr) -> int:
|
||||
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
|
||||
|
||||
命中置 _g_cif_eval_ok=1;未命中置 0。
|
||||
"""
|
||||
global _g_cif_eval_ok
|
||||
_g_cif_eval_ok = 0
|
||||
if at is None or at.attr is None or at.value is None or trans is None:
|
||||
return 0
|
||||
if at.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
vn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if vn.id is None:
|
||||
return 0
|
||||
v: int = HandlesType.lookup_cdefine_constant(at.attr)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
_g_cif_eval_ok = 1
|
||||
return v
|
||||
# 跨模块: 确定真实模块名(解析 from_imports 别名)
|
||||
real_mod: str = vn.id
|
||||
if trans._from_imports is not None:
|
||||
resolved: str = HandlesImports.lookup_from_import(
|
||||
trans._from_imports, vn.id, 0)
|
||||
if resolved is not None:
|
||||
rm_len: t.CSizeT = 0
|
||||
while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':':
|
||||
rm_len += 1
|
||||
rm_buf: str = pool.alloc(rm_len + 1)
|
||||
if rm_buf is not None:
|
||||
for rm_i in range(rm_len):
|
||||
rm_buf[rm_i] = resolved[rm_i]
|
||||
rm_buf[rm_len] = '\0'
|
||||
real_mod = rm_buf
|
||||
fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod) + 2
|
||||
fi: str = pool.alloc(fi_len)
|
||||
if fi is None:
|
||||
return 0
|
||||
viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod)
|
||||
v2: int = HandlesExpr._lookup_cross_module_cdefine(pool, at.attr, fi)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
_g_cif_eval_ok = 1
|
||||
return v2
|
||||
return 0
|
||||
|
||||
|
||||
def _cif_eval_node(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""递归常量求值 CIf 表达式。
|
||||
|
||||
支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine)
|
||||
/ BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=)
|
||||
/ BoolOp(and/or) / UnaryOp(not - + ~)。
|
||||
成功置 _g_cif_eval_ok=1;失败(含运行时变量)置 0 返回 0。
|
||||
"""
|
||||
global _g_cif_eval_ok
|
||||
if node is None:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
_g_cif_eval_ok = 1
|
||||
return cn.int_val
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is None:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
return _cif_name_value(pool, trans, nm.id)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
return _cif_attr_value(pool, trans, at)
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||||
if uop.operand is None:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
ov: int = _cif_eval_node(pool, trans, uop.operand)
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0
|
||||
if uop.op == ast.OpKind.USub: return -ov
|
||||
if uop.op == ast.OpKind.UAdd: return ov
|
||||
if uop.op == ast.OpKind.Invert: return ~ov
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
if k == ast.ASTKind.BoolOp:
|
||||
bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||||
vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values
|
||||
if vals is None:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
bn: t.CSizeT = vals.__len__()
|
||||
if bo.op == ast.OpKind.And:
|
||||
for bi in range(bn):
|
||||
rv: int = _cif_eval_node(pool, trans, vals.get(bi))
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
if rv == 0:
|
||||
return 0
|
||||
return 1
|
||||
if bo.op == ast.OpKind.Or:
|
||||
for bi in range(bn):
|
||||
rv: int = _cif_eval_node(pool, trans, vals.get(bi))
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
if rv != 0:
|
||||
return 1
|
||||
return 0
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
if k == ast.ASTKind.Compare:
|
||||
cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||||
lv: int = _cif_eval_node(pool, trans, cmp.left)
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
|
||||
comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
|
||||
if ops_list is None or comps is None:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
cc: t.CSizeT = comps.__len__()
|
||||
ci: t.CSizeT
|
||||
for ci in range(cc):
|
||||
rv: int = _cif_eval_node(pool, trans, comps.get(ci))
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
op_id: int = ops_list.get(ci)
|
||||
ok_cmp: int = 0
|
||||
if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0
|
||||
elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0
|
||||
elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0
|
||||
elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0
|
||||
elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0
|
||||
elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0
|
||||
else:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
if ok_cmp == 0:
|
||||
return 0
|
||||
lv = rv
|
||||
return 1
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
lv: int = _cif_eval_node(pool, trans, bop.left)
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
rv: int = _cif_eval_node(pool, trans, bop.right)
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
if bop.op == ast.OpKind.Add: return lv + rv
|
||||
if bop.op == ast.OpKind.Sub: return lv - rv
|
||||
if bop.op == ast.OpKind.Mult: return lv * rv
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
if rv == 0:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.Mod:
|
||||
if rv == 0:
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
return lv % rv
|
||||
if bop.op == ast.OpKind.BitAnd: return lv & rv
|
||||
if bop.op == ast.OpKind.BitOr: return lv | rv
|
||||
if bop.op == ast.OpKind.BitXor: return lv ^ rv
|
||||
if bop.op == ast.OpKind.LShift: return lv << rv
|
||||
if bop.op == ast.OpKind.RShift: return lv >> rv
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
_g_cif_eval_ok = 0
|
||||
return 0
|
||||
|
||||
|
||||
def _evaluate_cif_test(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
test: ast.AST | t.CPtr) -> int:
|
||||
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
|
||||
|
||||
成功: 置 _g_cif_eval_ok=1,返回条件值(0/1)
|
||||
失败(运行时变量/未知结构): 置 _g_cif_eval_ok=0,返回 0
|
||||
"""
|
||||
global _g_cif_eval_ok
|
||||
_g_cif_eval_ok = 0
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(test)
|
||||
if cl is None or cl.func is None:
|
||||
return 0
|
||||
kind: str = None
|
||||
fk: int = cl.func.kind()
|
||||
if fk == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
kind = at.attr
|
||||
elif fk == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
|
||||
kind = nm.id
|
||||
if kind is None:
|
||||
return 0
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if cargs is None or cargs.__len__() < 1:
|
||||
return 0
|
||||
arg0: ast.AST | t.CPtr = cargs.get(0)
|
||||
if string.strcmp(kind, "CIf") == 0:
|
||||
v: int = _cif_eval_node(pool, trans, arg0)
|
||||
if _g_cif_eval_ok == 0:
|
||||
return 0
|
||||
return 1 if v != 0 else 0
|
||||
# CIfdef / CIfndef: 判定宏名是否已定义
|
||||
defined: int = 0
|
||||
if arg0 is not None and arg0.kind() == ast.ASTKind.Name:
|
||||
nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
|
||||
if nm0.id is None:
|
||||
return 0
|
||||
_cif_name_value(pool, trans, nm0.id)
|
||||
defined = _g_cif_eval_ok
|
||||
elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant:
|
||||
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
|
||||
if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None:
|
||||
_cif_name_value(pool, trans, cn0.str_val)
|
||||
defined = _g_cif_eval_ok
|
||||
else:
|
||||
return 0
|
||||
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
|
||||
at0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
|
||||
_cif_attr_value(pool, trans, at0)
|
||||
defined = _g_cif_eval_ok
|
||||
else:
|
||||
return 0
|
||||
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
|
||||
_g_cif_eval_ok = 1
|
||||
if string.strcmp(kind, "CIfdef") == 0:
|
||||
return 1 if defined != 0 else 0
|
||||
# CIfndef
|
||||
return 0 if defined != 0 else 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -52,6 +411,39 @@ class IfHandle(HandlesBase.Mixin):
|
||||
|
||||
if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
|
||||
|
||||
# 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
|
||||
# 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归
|
||||
# 求值失败(运行时变量等)→ 回退运行时翻译
|
||||
if _is_cif_call(if_node.test) == 1:
|
||||
cif_val: int = _evaluate_cif_test(pool, trans, if_node.test)
|
||||
if _g_cif_eval_ok != 0:
|
||||
if cif_val != 0:
|
||||
body_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.children
|
||||
if body_cif is not None:
|
||||
bc_cif: t.CSizeT = body_cif.__len__()
|
||||
bi_cif: t.CSizeT
|
||||
for bi_cif in range(bc_cif):
|
||||
stmt_cif: ast.AST | t.CPtr = body_cif.get(bi_cif)
|
||||
if stmt_cif is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt_cif)
|
||||
else:
|
||||
orelse_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse
|
||||
if orelse_cif is not None and orelse_cif.__len__() == 1:
|
||||
sub_cif: ast.AST | t.CPtr = orelse_cif.get(0)
|
||||
if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If:
|
||||
# elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译)
|
||||
self.Handle(sub_cif)
|
||||
elif sub_cif is not None:
|
||||
HandlesBody.translate_stmt(trans, sub_cif)
|
||||
elif orelse_cif is not None:
|
||||
oc_cif: t.CSizeT = orelse_cif.__len__()
|
||||
oi_cif: t.CSizeT
|
||||
for oi_cif in range(oc_cif):
|
||||
stmt_cif2: ast.AST | t.CPtr = orelse_cif.get(oi_cif)
|
||||
if stmt_cif2 is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt_cif2)
|
||||
return 0
|
||||
|
||||
# 1. 求值条件表达式
|
||||
cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, if_node.test,
|
||||
|
||||
Reference in new issue
Block a user