修正了一些错误

This commit is contained in:
2026-07-26 20:33:17 +08:00
parent 909792bc8f
commit 03d0bba534
40 changed files with 6939 additions and 827 deletions

View File

@@ -6,6 +6,8 @@ import llvmlite
import stdio
import ast
import hashtable
import viperlib
import lib.core.VLogger as VLogger
# ============================================================
@@ -19,7 +21,7 @@ import hashtable
# ============================================================
STRUCT_MAX: t.CDefine = 512
FIELD_MAX: t.CDefine = 32
FIELD_MAX: t.CDefine = 48
FIELD_NAME_MAX: t.CDefine = 64
@@ -196,7 +198,10 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr,
return existing
if _struct_count >= STRUCT_MAX:
stdio.printf("[STRUCT] table full, cannot register %s\n", name)
fb_st: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_st is not None:
viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name)
VLogger.error(fb_st, "STRUCT")
return None
entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count)
@@ -290,7 +295,10 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
return -1
if struct_entry.FieldCount >= FIELD_MAX:
stdio.printf("[STRUCT] field table full for %s\n", struct_entry.Name)
fb_sf: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_sf is not None:
viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name)
VLogger.error(fb_sf, "STRUCT")
return -1
idx: int = struct_entry.FieldCount
@@ -314,18 +322,41 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
return idx
# ============================================================
# get_struct_count — 获取已注册结构体数量(供 Phase2 多遍预注册判断收敛)
# ============================================================
def get_struct_count() -> int:
"""返回当前已注册的结构体数量"""
return _struct_count
# ============================================================
# find_struct — 按类名查找结构体
# ============================================================
def find_struct(name: str) -> StructEntry | t.CPtr:
"""按类名查找结构体,返回 StructEntry 或 None"""
"""按类名查找结构体,返回 StructEntry 或 None
支持模块限定名(如 "HT.Translator"
第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退
"""
if name is None or _struct_table is None:
return None
# 第一遍:精确匹配
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
# 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator"
dot_pos: str = string.strrchr(name, '.')
if dot_pos is not None:
class_name: str = dot_pos + 1
if class_name is not None and class_name[0] != '\0':
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, class_name) == 0:
return entry
return None
@@ -455,12 +486,27 @@ def lookup_field_by_class(class_name: str,
return None
# 优先用 SHA1 匹配(跨模块同名类区分)
# 支持模块限定名class_name 可能是 "HT.Translator"entry.Name 是 "Translator"
# 先精确匹配,失败后用 strrchr 提取类名部分回退匹配
if sha1 is not None:
sha1_matched: int = 0
# 计算类名回退部分("HT.Translator" → "Translator"
bare_name: str = class_name
dot_pos_lfbc: str = string.strrchr(class_name, '.')
if dot_pos_lfbc is not None:
bare_name = dot_pos_lfbc + 1
if bare_name is None or bare_name[0] == '\0':
bare_name = class_name
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
# 精确匹配或类名回退匹配
name_match: int = 0
if string.strcmp(entry.Name, class_name) == 0:
name_match = 1
elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0:
name_match = 1
if name_match != 0:
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
sha1_matched = 1
@@ -475,12 +521,65 @@ def lookup_field_by_class(class_name: str,
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
entry = find_struct(class_name)
if entry is None:
# 诊断:遍历打印所有已注册结构体名,确认目标类是否在注册表中
stdio.printf("[LFBC-DIAG] FAIL class=%s field=%s sha1=%s count=%d\n",
class_name, field_name,
sha1 if sha1 is not None else "(null)", _struct_count)
for diag_i in range(_struct_count):
diag_entry: StructEntry | t.CPtr = _get_struct_entry(diag_i)
if diag_entry is not None and diag_entry.Name is not None:
stdio.printf("[LFBC-DIAG] [%d] %s sha1=%s fc=%d\n",
diag_i, diag_entry.Name,
diag_entry.ModuleSha1 if diag_entry.ModuleSha1 is not None else "(null)",
diag_entry.FieldCount)
return None
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# 诊断:找到结构体但字段未找到
stdio.printf("[LFBC-DIAG] NOFIELD class=%s field=%s sname=%s fc=%d\n",
class_name, field_name, entry.Name, entry.FieldCount)
return None
# ============================================================
# find_subclass_with_field — 在基类的所有子类中搜索包含指定字段的结构体
#
# 用于处理 "注解类型是基类但实际值是派生类" 的场景:
# node: AST | t.CPtr = If(...)
# node.orelse = orelse ← orelse 在 If 上,不在 AST 上
#
# 遍历所有已注册结构体,通过 ParentName 链检查继承关系,
# 返回第一个包含 field_name 的子类 StructEntry。
# ============================================================
def find_subclass_with_field(base_class_name: str,
field_name: str) -> StructEntry | t.CPtr:
"""在 base_class_name 的所有子类中搜索包含 field_name 的结构体
返回第一个找到的 StructEntry包含正确的 TyNone=未找到
"""
if base_class_name is None or field_name is None:
return None
sc_i: int
for sc_i in range(_struct_count):
sc_entry: StructEntry | t.CPtr = _get_struct_entry(sc_i)
if sc_entry is None or sc_entry.Name is None:
continue
# 检查 sc_entry 是否是 base_class_name 的子类(传递性)
cur_parent: str = get_parent_name(sc_entry.Name)
while cur_parent is not None:
if string.strcmp(cur_parent, base_class_name) == 0:
# 是子类,检查是否有该字段
sc_fi: int
for sc_fi in range(sc_entry.FieldCount):
sc_fe: FieldEntry | t.CPtr = _get_field_entry(sc_entry, sc_fi)
if sc_fe is not None and sc_fe.Name is not None:
if string.strcmp(sc_fe.Name, field_name) == 0:
return sc_entry
break
cur_parent = get_parent_name(cur_parent)
return None
@@ -546,6 +645,28 @@ def _is_struct_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
return 0
def _is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
"""检查 ty 是否是 Ptr 类型(独立函数,规避嵌套 match 编译器 BUG"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Ptr(pointee):
return 1
case _:
return 0
def _get_ptr_pointee(ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""获取 Ptr 类型的 pointee独立函数规避嵌套 match 编译器 BUG"""
if ty is None:
return None
match ty:
case llvmlite.LLVMType.Ptr(pointee):
return pointee
case _:
return None
def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""从 Value 的类型推断结构体类型"""
if val is None or val.Ty is None:
@@ -935,6 +1056,119 @@ def get_field_count(name: str) -> int:
return entry.FieldCount
# ============================================================
# ensure_struct_def_in_module — 确保跨模块结构体的完整定义在当前模块中可用
#
# 当局部变量声明为值类型(如 f: Filealloca 需要完整类型定义。
# 如果结构体定义在另一个模块(名称含 SHA1 前缀,如 "0035c95a18d4f8e8.File"
# 将其完整定义复制到当前模块。module_add_named_type 会用完整定义替换
# 已存在的 opaque 声明,使 alloca 能正确分配空间。
#
# Args:
# pool: 内存池
# mod: 当前 LLVM 模块
# ty: 变量类型Struct/Ptr/其他)
# ============================================================
def ensure_struct_def_in_module(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr):
"""确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用)
处理两种情况:
1. Struct 值类型:需要完整定义(供 alloca 分配空间)
2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明
"""
if ty is None or mod is None or pool is None:
return
# 指针类型:确保 pointee 至少有 opaque 声明
# 用 _is_ptr_type 检查(独立函数,规避嵌套 match BUG
if _is_ptr_type(ty) != 0:
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
# 如果 pointee 是 Struct递归复制完整定义
# GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错)
pointee: llvmlite.LLVMType | t.CPtr = _get_ptr_pointee(ty)
if pointee is not None:
ensure_struct_def_in_module(pool, mod, pointee)
return
# 获取结构体名称(非 Struct 类型返回 None
sname: t.CChar | t.CPtr = llvmlite.get_struct_name(ty)
if sname is None:
return
# 检查是否为跨模块引用(名称包含 '.'
if string.strchr(sname, 46) is None:
return # 非跨模块引用,无需处理
# 提取类名(第一个 '.' 之后的部分)
# 必须用 strchr 而非 strrchr泛型特化名如 "list[ast.AST|t.CPtr]"
# 内部含 '.'ast.ASTstrrchr 会错误地把类名解析为 "AST|t.CPtr]"
dot_pos: str = string.strchr(sname, '.')
if dot_pos is None:
return
class_name: str = dot_pos + 1
if class_name is None or class_name[0] == '\0':
return
# 提取 SHA1sname 到 dot_pos 之间,用 strlen 避免指针减法)
total_len: t.CSizeT = string.strlen(sname)
class_name_len: t.CSizeT = string.strlen(class_name)
sha1_len: t.CSizeT = total_len - class_name_len - 1
sha1_buf: t.CChar | t.CPtr = pool.alloc(32)
if sha1_buf is None:
return
string.strncpy(sha1_buf, sname, sha1_len)
sha1_buf[sha1_len] = '\0'
# 按类名 + SHA1 查找结构体定义
entry: StructEntry | t.CPtr = find_struct_by_module(class_name, sha1_buf)
if entry is None:
# 回退到按类名查找(可能找到不同模块的同名类,但总比没有好)
entry = find_struct(class_name)
if entry is None:
return
if entry.Ty is None:
return
# 将完整定义添加到当前模块(会替换已存在的 opaque 声明)
llvmlite.module_add_named_type(mod, pool, entry.Ty)
# 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME
# 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。
_ensure_field_types_in_module(pool, mod, entry.Ty)
# ============================================================
# _ensure_field_types_in_module - 递归扫描结构体字段类型
#
# 遍历 Struct 的 Fields 链表,对每个值类型子结构体调用
# ensure_struct_def_in_module。指针/数组/基本类型递归到 pointee/element。
# ============================================================
def _ensure_field_types_in_module(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
ty: llvmlite.LLVMType | t.CPtr):
"""递归扫描类型树,确保值类型子结构体有完整定义"""
if ty is None or mod is None or pool is None:
return
# 用 match 遍历类型(独立函数,规避嵌套 match BUG
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, sname):
# 遍历字段链表
if fields is not None:
fld: llvmlite.ParamNode | t.CPtr = fields
while fld is not None:
if fld.Ty is not None:
# 值类型子结构体(如 FILETIME需要完整定义
if _is_struct_type(fld.Ty) != 0:
ensure_struct_def_in_module(pool, mod, fld.Ty)
_ensure_field_types_in_module(pool, mod, fld.Ty)
fld = fld.Next
case llvmlite.LLVMType.Ptr(pointee):
# 指针类型pointee 只需 opaque 声明,不需要完整定义
# 但如果 pointee 是 Struct确保 opaque 声明存在
if pointee is not None:
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
case llvmlite.LLVMType.Array(elem_ty, acount):
# 数组类型:元素如果是值类型结构体,需要完整定义
if elem_ty is not None:
_ensure_field_types_in_module(pool, mod, elem_ty)
case _:
pass
# ============================================================
# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器)
# ============================================================