feat(tpv): S2 落无符号判定双写闸门,并修 i8 拓宽丢符号与 WCHARPTR 旧判
- TypeSpec: 新增 SpecFromLLVMType(LLVM 类型 -> TypeSpec 结构转换器,当前无调用点);SpecSignFromTypeName 拆出零分配切片版 Span
- TypeGenCType: 新增 lookup_ctypedef_span 与独立符号性真源 spec_sign_of_annot(精确名白名单 + CTypedef 链逐层展开)
- ExprGenOps: 旧判定改名 *_legacy,外层加双写闸门 _spec_sign_check(新真源明确表态且不一致即 fatal;S2 不切读)
- ExprGenOps: 修旧符号性两个洞 -- 子串表补 WORD、裸别名沿 CTypedef 链展开(闸门实测暴露 WCHARPTR 旧判 signed、新真源 unsigned)
- ExprGenOps: should_zext_widen 的 i8 分支补「源注解明确有符号则 sext」例外,修 b8470c1 引入的 TypeCastTest 回归(t.CInt32T(v) 丢符号);新增 _node_type_signed
- TypeGenBase: 补 import lib.core.Gen.Type.TypeSpec(此前遗漏)并接入驻留表 ensure_spec_arena(PermPool 惰性创建)
- 修两条链接错误: TypeSpec.vp 残留 stdlib.atoi 改 string.atoi;模块别名与模块内类名同名会被误解析为该类静态方法(隐式补 self 实参),四处导入别名统一改 TSpec
This commit is contained in:
1 parent
b1090abe70
commit
b7100e9dc1
5 files changed
+598
-17
No files matched your search
@@ -7,6 +7,7 @@ import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
@@ -178,7 +179,9 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
|
||||
对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则:
|
||||
1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...)
|
||||
2. i8 → zext(系统编程中 i8 几乎总是无符号字节)
|
||||
2. i8 → zext(系统编程中 i8 几乎总是无符号字节);
|
||||
例外:源注解**明确有符号**(t.CInt8T/int8/i8/char…)→ sext 保号
|
||||
(判据 _node_type_signed,见下)
|
||||
3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext
|
||||
(常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与
|
||||
uint32 值比较,sext 会把 0xAABBCCDD 变成
|
||||
@@ -190,6 +193,12 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if narrow_bits == 1:
|
||||
return 1
|
||||
if narrow_bits == 8:
|
||||
# i8 默认按「无符号字节」处理(系统编程惯例,保持既有行为);
|
||||
# 但**源注解明确为有符号类型**时必须 sext 保号:
|
||||
# TypeCastTest 回归 —— `t.CInt32T(v)`(v: t.CInt8T = -50)期望 -50,
|
||||
# 此前 b8470c1 把强转路径统一到本函数后撞上无条件 zext 而变成 206。
|
||||
if self._node_type_signed(pool, narrow_node, trans) != 0:
|
||||
return 0
|
||||
return 1
|
||||
# 宽侧常量启发式
|
||||
if wide_val is not None and wide_val.IsConst == 1:
|
||||
@@ -325,8 +334,65 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
fi_u += 1
|
||||
return 0
|
||||
return 0
|
||||
def _type_name_unsigned(self, type_name: str) -> int:
|
||||
"""类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)"""
|
||||
def _node_type_signed(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""源节点是否**明确有符号**整数(独立真源的 SIGNED 分支;未知返回 0)
|
||||
|
||||
只服务 should_zext_widen 的 i8 分支:i8 默认按「无符号字节」zext,
|
||||
但源注解明确有符号(t.CInt8T / int8 / i8 / char …)时须 sext 保号。
|
||||
判据走独立符号性真源(精确名 + CTypedef 链),与 _node_type_unsigned 的
|
||||
遍历形态对应,但只覆盖**注解直接可见**的节点形态(Call(t.X) / Name /
|
||||
Subscript);其余返回 0,即保持 i8 的既有默认行为(不扩大改动面)。
|
||||
"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 \
|
||||
and at.attr is not None:
|
||||
if self._spec_sign_from_annot(at.attr) == TSpec.TS_SIGN_SIGNED:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is not None:
|
||||
if self._spec_sign_from_annot(nm.id) == TSpec.TS_SIGN_SIGNED:
|
||||
return 1
|
||||
if trans is not None:
|
||||
ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm.id)
|
||||
if ve is not None and ve.AnnotClassName is not None:
|
||||
if self._spec_sign_from_annot(ve.AnnotClassName) == TSpec.TS_SIGN_SIGNED:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None and sub_s.value.kind() == ast.ASTKind.Name:
|
||||
snm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_s.value)
|
||||
if snm.id is not None and trans is not None:
|
||||
ve_s: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, snm.id)
|
||||
if ve_s is not None and ve_s.AnnotClassName is not None:
|
||||
if self._spec_sign_from_annot(ve_s.AnnotClassName) == TSpec.TS_SIGN_SIGNED:
|
||||
return 1
|
||||
return 0
|
||||
return 0
|
||||
def _last_dot_tail(self, name: str) -> str:
|
||||
"""取最后一个 '.' 之后的部分(无 '.' 返回 None);用于模块限定名退查"""
|
||||
if name is None:
|
||||
return None
|
||||
dot: str = string.strrchr(name, 46)
|
||||
if dot is None:
|
||||
return None
|
||||
return dot + 1
|
||||
def _type_name_unsigned_legacy(self, type_name: str) -> int:
|
||||
"""[旧路径] 类型名是否为无符号整数类型(精确匹配 + CTypedef 展开一层)"""
|
||||
if type_name is None:
|
||||
return 0
|
||||
# t.CUIntXXT 形式
|
||||
@@ -338,8 +404,12 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
# CSizeT 此前缺失 → viperio.Buf.write 的 capacity/length 比较生成
|
||||
# icmp sgt/sle/slt(应 ult/ule/ult),A5 同族残留根因。
|
||||
if string.strcmp(type_name, "CSizeT") == 0: return 1
|
||||
if string.strcmp(type_name, "SSizeT") == 0: return 1
|
||||
if string.strcmp(type_name, "CUIntPtrT") == 0: return 1
|
||||
# bool / t.CBool:i1 属无符号语义(should_zext_widen 对 narrow_bits==1
|
||||
# 已强制 zext,此处登记仅为与独立真源口径一致)。
|
||||
# 原表把 SSizeT 列为无符号(A3 缺陷)——已删:SSizeT 实为有符号。
|
||||
if string.strcmp(type_name, "CBool") == 0: return 1
|
||||
if string.strcmp(type_name, "bool") == 0: return 1
|
||||
# stdint 裸别名(from stdint import *)
|
||||
if string.strcmp(type_name, "UInt8T") == 0: return 1
|
||||
if string.strcmp(type_name, "UInt16T") == 0: return 1
|
||||
@@ -358,17 +428,32 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if string.strcmp(type_name, "UINT") == 0: return 1
|
||||
if string.strcmp(type_name, "ULONG") == 0: return 1
|
||||
# [阶段3] CTypedef 动态表兜底:stdint 别名(DWORD/uint32_t 等)走库定义
|
||||
# 展开,按 _annot_str_unsigned 子串规则判断符号性(单一真源)。
|
||||
ts_u: str = self.Gen.TypeGenCType.lookup_ctypedef(type_name)
|
||||
if ts_u is not None and self.Gen.TypeGenCType.CTypedefFound != 0:
|
||||
if self._annot_str_unsigned(ts_u) != 0:
|
||||
# 展开,按 _annot_str_unsigned_legacy 子串规则判断符号性。
|
||||
# S2 修正:原实现**只展开一层** ⇒ 多层别名漏判(如 WCHAR→WORD→
|
||||
# t.CUInt16T、FSIZE_t→DWORD→t.CUInt32T);改为沿链展开至不动点。
|
||||
cur_u: str = type_name
|
||||
depth_u: int = 0
|
||||
while depth_u < 16:
|
||||
ts_u: str = self.Gen.TypeGenCType.lookup_ctypedef(cur_u)
|
||||
if ts_u is None or self.Gen.TypeGenCType.CTypedefFound == 0:
|
||||
# 模块限定名(如 stdint.u32 / builtins.DWORD)退到最后一段重查
|
||||
tail_u: str = self._last_dot_tail(cur_u)
|
||||
if tail_u is not None:
|
||||
ts_u = self.Gen.TypeGenCType.lookup_ctypedef(tail_u)
|
||||
if ts_u is None or self.Gen.TypeGenCType.CTypedefFound == 0:
|
||||
break
|
||||
if self._annot_str_unsigned_legacy(ts_u) != 0:
|
||||
return 1
|
||||
if string.strcmp(ts_u, cur_u) == 0:
|
||||
break
|
||||
cur_u = ts_u
|
||||
depth_u += 1
|
||||
return 0
|
||||
def _annot_str_unsigned(self, annot: str) -> int:
|
||||
"""检查类型注解字符串是否引用无符号整型(子串扫描)
|
||||
def _annot_str_unsigned_scan(self, annot: str) -> int:
|
||||
"""[旧路径·子串表] 纯子串扫描(不做别名链展开)
|
||||
|
||||
用于复合注解(t.CArray[uint8, 16] / uint8 | t.CPtr),
|
||||
_type_name_unsigned 的精确匹配对这类串不适用。
|
||||
_type_name_unsigned_legacy 的精确匹配对这类串不适用。
|
||||
"""
|
||||
if annot is None:
|
||||
return 0
|
||||
@@ -388,12 +473,109 @@ class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if string.strstr(annot, "uint32") is not None: return 1
|
||||
if string.strstr(annot, "uint64") is not None: return 1
|
||||
if string.strstr(annot, "CUnsigned") is not None: return 1
|
||||
# bool / CBool:i1 属无符号语义(与 _type_name_unsigned_legacy 同口径)
|
||||
if string.strstr(annot, "CBool") is not None: return 1
|
||||
if string.strstr(annot, "bool") is not None: return 1
|
||||
if string.strstr(annot, "BYTE") is not None: return 1
|
||||
if string.strstr(annot, "UCHAR") is not None: return 1
|
||||
if string.strstr(annot, "USHORT") is not None: return 1
|
||||
if string.strstr(annot, "UINT") is not None: return 1
|
||||
if string.strstr(annot, "ULONG") is not None: return 1
|
||||
# WORD 系:WORD/DWORD/QWORD/WCHAR/FSIZE_t/LBA_t 均为无符号(WORD=t.CUInt16T)。
|
||||
# 原表漏 WORD ⇒ 复合别名 `WCHARPTR = WORD | t.CPtr` 被旧判为 signed
|
||||
# (S2 闸门实测暴露:旧判 signed / 新真源 unsigned,旧错)。
|
||||
if string.strstr(annot, "WORD") is not None: return 1
|
||||
return 0
|
||||
def _is_simple_ident(self, s: str) -> int:
|
||||
"""是否简单标识符(仅标识符字符与 '.',不含空白/运算符/括号/逗号)"""
|
||||
if s is None:
|
||||
return 0
|
||||
n: sizet = string.strlen(s)
|
||||
if n == 0:
|
||||
return 0
|
||||
i: sizet = 0
|
||||
while i < n:
|
||||
if s[i] == ' ' or s[i] == '\t' or s[i] == '\n' or s[i] == '\r':
|
||||
return 0
|
||||
if s[i] == '|' or s[i] == '[' or s[i] == ']' or s[i] == '(' or s[i] == ')':
|
||||
return 0
|
||||
if s[i] == '*' or s[i] == ',' or s[i] == '+':
|
||||
return 0
|
||||
i += 1
|
||||
return 1
|
||||
def _annot_str_unsigned_legacy(self, annot: str) -> int:
|
||||
"""[旧路径] 注解串无符号判定 = 子串扫描 + 裸别名沿 CTypedef 链展开后再扫
|
||||
|
||||
为何需要链展开:`_node_type_unsigned` 的 Subscript/Attribute 分支会把
|
||||
**裸别名**(`sizet` / `u64` / `WORD` …)当作注解串传进来,而子串表只认
|
||||
`CSizeT` / `uint64` 等长名 ⇒ 这些别名此前被漏判(A5 同族)。链展开后
|
||||
其目标(`t.CSizeT` / `t.CUInt64T`)能被子串表命中。
|
||||
复合串(含 '|' / '[' 等)不做链展开,交给子串表。
|
||||
"""
|
||||
if self._annot_str_unsigned_scan(annot) != 0:
|
||||
return 1
|
||||
if annot is None or self._is_simple_ident(annot) == 0:
|
||||
return 0
|
||||
cur: str = annot
|
||||
d: int = 0
|
||||
while d < 16:
|
||||
ts: str = self.Gen.TypeGenCType.lookup_ctypedef(cur)
|
||||
if ts is None or self.Gen.TypeGenCType.CTypedefFound == 0:
|
||||
tail: str = self._last_dot_tail(cur)
|
||||
if tail is not None:
|
||||
ts = self.Gen.TypeGenCType.lookup_ctypedef(tail)
|
||||
if ts is None or self.Gen.TypeGenCType.CTypedefFound == 0:
|
||||
break
|
||||
if self._annot_str_unsigned_scan(ts) != 0:
|
||||
return 1
|
||||
if string.strcmp(ts, cur) == 0:
|
||||
break
|
||||
cur = ts
|
||||
d += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# S2 双写(无符号判定块)——独立真源与旧判定比对,不一致即 fatal
|
||||
#
|
||||
# 新真源:TypeGenCType.spec_sign_of_annot(精确名白名单 + CTypedef 链逐层展开),
|
||||
# 与旧路径(strstr 子串扫描 + 只展开一层)**完全独立**,故能暴露 A2~A5 类错判。
|
||||
# 读仍走旧路径(S3 才切读);此处只做一致性闸门(D6-3 决策:直接 fatal)。
|
||||
#
|
||||
# 只在**新真源明确表态**时比对:别名/复合注解若新真源返回 UNKNOWN
|
||||
# (尚未覆盖),则不参与比对,避免用"未知"误杀旧路径的正确判定。
|
||||
# ============================================================
|
||||
def _spec_sign_from_annot(self, annot: str) -> int:
|
||||
"""新真源入口:注解 → TS_SIGN_*(UNKNOWN 表示不表态)"""
|
||||
return self.Gen.TypeGenCType.spec_sign_of_annot(annot, 0)
|
||||
def _spec_sign_check(self, text: str, old_unsigned: int) -> None:
|
||||
"""S2 一致性闸门:新真源明确表态且与旧判定不一致 → fatal"""
|
||||
if text is None:
|
||||
return
|
||||
new_sign: int = self._spec_sign_from_annot(text)
|
||||
if new_sign == TSpec.TS_SIGN_UNKNOWN:
|
||||
return
|
||||
new_unsigned: int = 0
|
||||
if new_sign == TSpec.TS_SIGN_UNSIGNED:
|
||||
new_unsigned = 1
|
||||
if new_unsigned == old_unsigned:
|
||||
return
|
||||
old_txt: str = "signed"
|
||||
if old_unsigned != 0:
|
||||
old_txt = "unsigned"
|
||||
new_txt: str = "signed"
|
||||
if new_unsigned != 0:
|
||||
new_txt = "unsigned"
|
||||
msg: str = f"[S2 符号性双写] 注解 '{text}':旧判定={old_txt},新真源={new_txt}"
|
||||
self.Gen.TypeGenErr.fatal_error(None, msg, "TypeError")
|
||||
def _type_name_unsigned(self, type_name: str) -> int:
|
||||
"""[S2 双写] 类型名无符号判定 + 独立真源比对"""
|
||||
old: int = self._type_name_unsigned_legacy(type_name)
|
||||
self._spec_sign_check(type_name, old)
|
||||
return old
|
||||
def _annot_str_unsigned(self, annot: str) -> int:
|
||||
"""[S2 双写] 注解串无符号判定 + 独立真源比对"""
|
||||
old: int = self._annot_str_unsigned_legacy(annot)
|
||||
self._spec_sign_check(annot, old)
|
||||
return old
|
||||
def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
|
||||
@@ -6,7 +6,8 @@ import memhub
|
||||
# TypeSpec:统一类型描述符(Debugger/_Type.md 第 6 节设计)。
|
||||
# S1 阶段仅 import 使该模块参与编译(尚未在任何条目上使用其字段);
|
||||
# S2 起在 VarEntry/FieldEntry/FuncEntry 上加 Spec 字段并双写。
|
||||
import lib.core.Gen.Type.TypeSpec as TypeSpec
|
||||
# 别名用 TSpec:模块内类名同为 TypeSpec,别名同名会被解析器误判为类静态方法。
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -12,7 +12,11 @@ import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
# TypeSpec 模块导入别名用 TSpec(模块内类名也叫 TypeSpec,别名同名会被解析器
|
||||
# 当成"类 TypeSpec 的静态方法",导致跨模块调用被 mangled 成 <sha1>.TypeSpec.<fn>
|
||||
# 并隐式补 self 实参 → undefined symbol)。
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
|
||||
|
||||
@@ -94,8 +98,13 @@ class TypeGenBase:
|
||||
# --- 常量整数表达式计算成功标志(原 _g_const_eval_ok) ---
|
||||
ConstEvalOk: int
|
||||
|
||||
# --- 全局当前文件名(原 _g_current_file) ---
|
||||
CurrentFile: str
|
||||
# --- 全局当前文件名(原 _g_current_filename) ---
|
||||
CurrentFile: str
|
||||
|
||||
# --- TypeSpec 驻留表(统一类型描述符,Debugger/_Type.md 第 6 节) ---
|
||||
# 惰性创建(ensure_spec_arena);由类型子系统自身持有,避免模块级全局表。
|
||||
# 实例与内部数组均 PermPool 分配 ⇒ 跨文件/跨 mark 存活。
|
||||
Specs: TSpec.TypeSpecArena | t.CPtr
|
||||
def InitTypeGen(self) -> int:
|
||||
"""初始化类型 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
|
||||
if self is None:
|
||||
@@ -131,7 +140,29 @@ class TypeGenBase:
|
||||
self.ImportAliasBuf = None
|
||||
self.ConstEvalOk = 0
|
||||
self.CurrentFile = None
|
||||
self.Specs = None
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# ensure_spec_arena - 惰性创建 TypeSpec 驻留表(幂等)
|
||||
#
|
||||
# 用 PermPool 分配 arena 本体;表内部缓冲由 TSpec.SpecArenaInit 分配
|
||||
# (同样 PermPool)。失败返回 None(调用方按 fail-fast 处理,不静默退化)。
|
||||
# ============================================================
|
||||
def ensure_spec_arena(self) -> TSpec.TypeSpecArena | t.CPtr:
|
||||
"""确保 TypeSpec 驻留表已创建,返回 arena;失败返回 None"""
|
||||
if self.Specs is not None:
|
||||
return self.Specs
|
||||
size: sizet = TSpec.TypeSpecArena.__sizeof__()
|
||||
arena: TSpec.TypeSpecArena | t.CPtr = (TSpec.TypeSpecArena | t.CPtr)(
|
||||
t.CVoid(CompilerFactory.factory.PermPool.alloc(size), t.CPtr))
|
||||
if arena is None:
|
||||
return None
|
||||
string.memset(arena, 0, size)
|
||||
if TSpec.SpecArenaInit(arena, 0) != 0:
|
||||
return None
|
||||
self.Specs = arena
|
||||
return arena
|
||||
# ============================================================
|
||||
# P2 迁移方法(函数体来自 HandlesType.vp,全局变量改 self.字段,
|
||||
# 同模块函数调用改 self.方法;签名与 HandlesType 原函数一致)
|
||||
|
||||
@@ -13,7 +13,8 @@ import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
# builtins 诊断串自有缓冲长度(仅服务"变量类型注解解析失败"报错文本)
|
||||
TYPEDEF_DIAG_BUF: t.CDefine = 256
|
||||
@@ -122,6 +123,153 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
def is_ctypedef_found(self) -> int:
|
||||
"""检查上次 lookup_ctypedef 是否找到值"""
|
||||
return self.CTypedefFound
|
||||
def lookup_ctypedef_span(self, text: str, start: sizet, end: sizet) -> str:
|
||||
"""按名字切片查 CTypedef(零分配,不复制子串)
|
||||
|
||||
与 lookup_ctypedef 同表;命中置 CTypedefFound=1 并返回类型表达式串,
|
||||
未命中返回 None(CTypedefFound=0)。用于符号性独立真源的别名链展开。
|
||||
"""
|
||||
self.CTypedefFound = 0
|
||||
if text is None or end <= start:
|
||||
return None
|
||||
if self.CTypedefNames is None:
|
||||
return None
|
||||
want: sizet = end - start
|
||||
n: sizet = len(self.CTypedefNames)
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
nm: str = self.CTypedefNames.get(i)
|
||||
if nm is None:
|
||||
continue
|
||||
if string.strlen(nm) != want:
|
||||
continue
|
||||
hit: int = 1
|
||||
k: sizet = 0
|
||||
while k < want:
|
||||
if nm[k] != text[start + k]:
|
||||
hit = 0
|
||||
break
|
||||
k += 1
|
||||
if hit != 0:
|
||||
ts: str = self.CTypedefTypeStrs.get(i)
|
||||
self.CTypedefFound = 1
|
||||
return ts
|
||||
return None
|
||||
# ============================================================
|
||||
# 独立符号性真源(S2 双写比对用;与旧 _annot_str_unsigned 完全独立)
|
||||
#
|
||||
# 旧实现:strstr 子串扫描 + CTypedef 只展开一层 ⇒ 两类错判:
|
||||
# A4 `BYTEPTR` 含 `BYTE` 被判无符号;A5 sha1 前缀名含 `uint32` 命中;
|
||||
# 多层别名(WCHAR→WORD→t.CUInt16T)因只展开一层而漏判。
|
||||
# 本实现:精确名白名单(TSpec.SpecSignFromTypeNameSpan)+ 别名链逐层展开。
|
||||
# ============================================================
|
||||
def spec_sign_of_annot(self, text: str, depth: int = 0) -> int:
|
||||
"""按注解文本判定其整数值符号性(独立真源),未覆盖返回 TS_SIGN_UNKNOWN"""
|
||||
if text is None or depth > 16:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
return self._spec_sign_of_span(text, 0, string.strlen(text), depth)
|
||||
def _spec_sign_of_span(self, text: str, start: sizet, end: sizet,
|
||||
depth: int) -> int:
|
||||
"""顶层 '|' 分段,返回首个能确定的符号性(`X | t.CPtr` 取 X)"""
|
||||
seg_start: sizet = start
|
||||
bracket_depth: int = 0
|
||||
i: sizet = start
|
||||
while i <= end:
|
||||
is_split: int = 0
|
||||
if i == end:
|
||||
is_split = 1
|
||||
elif text[i] == '|' and bracket_depth == 0:
|
||||
is_split = 1
|
||||
if is_split != 0:
|
||||
r: int = self._spec_sign_of_segment(text, seg_start, i, depth)
|
||||
if r != TSpec.TS_SIGN_UNKNOWN:
|
||||
return r
|
||||
seg_start = i + 1
|
||||
elif text[i] == '[' or text[i] == '(':
|
||||
bracket_depth += 1
|
||||
elif text[i] == ']' or text[i] == ')':
|
||||
if bracket_depth > 0:
|
||||
bracket_depth -= 1
|
||||
i += 1
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
def _spec_sign_of_segment(self, text: str, start: sizet, end: sizet,
|
||||
depth: int) -> int:
|
||||
"""单个片段:去空白/括号 → 指针后缀 → 下标取元素 → 末段名 → 别名链展开"""
|
||||
s: sizet = start
|
||||
e: sizet = end
|
||||
while s < e:
|
||||
if text[s] != ' ' and text[s] != '\t' and text[s] != '\n':
|
||||
break
|
||||
s += 1
|
||||
while e > s:
|
||||
if text[e - 1] != ' ' and text[e - 1] != '\t' and text[e - 1] != '\n':
|
||||
break
|
||||
e -= 1
|
||||
# 去外层成对括号(如 "(t.CUInt32T)")
|
||||
while e > s + 1:
|
||||
if text[s] != '(' or text[e - 1] != ')':
|
||||
break
|
||||
s += 1
|
||||
e -= 1
|
||||
while s < e:
|
||||
if text[s] != ' ' and text[s] != '\t':
|
||||
break
|
||||
s += 1
|
||||
while e > s:
|
||||
if text[e - 1] != ' ' and text[e - 1] != '\t':
|
||||
break
|
||||
e -= 1
|
||||
if e <= s:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
# C 指针后缀 '*' → 指针,不表态(指针语义由 PtrLevel 表达)
|
||||
if text[e - 1] == '*':
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
# 泛型/数组/rowptr 下标:IDENT[INNER, ...] → 取 INNER(元素决定值符号性)
|
||||
bracket: sizet = 0
|
||||
has_bracket: int = 0
|
||||
k: sizet = s
|
||||
while k < e:
|
||||
if text[k] == '[':
|
||||
bracket = k
|
||||
has_bracket = 1
|
||||
break
|
||||
k += 1
|
||||
if has_bracket != 0:
|
||||
inner_s: sizet = bracket + 1
|
||||
inner_e: sizet = inner_s
|
||||
d: int = 0
|
||||
while inner_e < e:
|
||||
if text[inner_e] == '[' or text[inner_e] == '(':
|
||||
d += 1
|
||||
elif text[inner_e] == ']':
|
||||
if d == 0:
|
||||
break
|
||||
d -= 1
|
||||
elif text[inner_e] == ')':
|
||||
if d > 0:
|
||||
d -= 1
|
||||
elif text[inner_e] == ',':
|
||||
if d == 0:
|
||||
break
|
||||
inner_e += 1
|
||||
return self._spec_sign_of_span(text, inner_s, inner_e, depth)
|
||||
# 去模块限定前缀:取最后一个 '.' 之后的名字
|
||||
name_s: sizet = s
|
||||
w: sizet = s
|
||||
while w < e:
|
||||
if text[w] == '.':
|
||||
name_s = w + 1
|
||||
w += 1
|
||||
exact: int = TSpec.SpecSignFromTypeNameSpan(text, name_s, e)
|
||||
if exact != TSpec.TS_SIGN_UNKNOWN:
|
||||
return exact
|
||||
# 精确名未覆盖 → 沿 CTypedef 链展开(depth 限制防环)
|
||||
if depth >= 16:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
ts: str = self.lookup_ctypedef_span(text, name_s, e)
|
||||
if ts is None or self.CTypedefFound == 0:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
return self._spec_sign_of_span(ts, 0, string.strlen(ts), depth + 1)
|
||||
def clear_ctypedefs(self) -> None:
|
||||
"""清空 CTypedef 表(模块切换时调用)"""
|
||||
self.CTypedefNames = None
|
||||
|
||||
@@ -59,6 +59,122 @@ SPEC_INTERN_MAX: t.CDefine = 8192
|
||||
SPEC_TEXT_MAX: t.CDefine = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 符号性精确名表 - 按「名字切片」判定(**不做子串扫描**)
|
||||
#
|
||||
# 为什么必须精确匹配:旧实现 `_annot_str_unsigned` 用 strstr 子串扫描,
|
||||
# 已确认两类误判(Debugger/_Type.md A4/A5):
|
||||
# - `BYTEPTR`(本质 i8* 指针)含子串 `BYTE` → 被判为无符号整数;
|
||||
# - 任何含 `uint32` 子串的名字(含 sha1 前缀名)都会命中。
|
||||
#
|
||||
# 覆盖范围界定:本模块**只认 t/c 核心原语名与少数内建名**;stdint 的别名
|
||||
# (DWORD/WORD/QWORD/size_t/uint32_t/u32/…)由调用方沿 CTypedef 链**逐层展开**
|
||||
# 后再落到本函数(链展开需要 CTypedef 表,不在本模块做,避免反向依赖)。
|
||||
#
|
||||
# 规范性修正(相对旧表):
|
||||
# - `SSizeT` 是**有符号**(旧 `_type_name_unsigned` 把它列为无符号,为 A3 缺陷);
|
||||
# - `BOOL` 按 stdint.vp 定义是 `t.CInt`(**有符号**),并非布尔无符号;
|
||||
# - 指针名(`BYTEPTR/UINTPTR/INTPTR/CHARPTR/…`)在此返回 UNKNOWN ——
|
||||
# 指针的"无符号"语义由 PtrLevel 表达,与整数符号性无关。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _spec_name_eq - 比较 text[start:end] 与字面量 lit 是否逐字符相等(零分配)
|
||||
# ============================================================
|
||||
def _spec_name_eq(text: str, start: sizet, end: sizet, lit: str) -> int:
|
||||
"""切片名比较:长度相同且逐字符相等返回 1,否则 0"""
|
||||
if text is None or lit is None:
|
||||
return 0
|
||||
if end <= start:
|
||||
return 0
|
||||
ln: sizet = string.strlen(lit)
|
||||
if end - start != ln:
|
||||
return 0
|
||||
k: sizet = 0
|
||||
while k < ln:
|
||||
if text[start + k] != lit[k]:
|
||||
return 0
|
||||
k += 1
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SpecSignFromTypeNameSpan - 按名字切片精确判定符号性(零分配)
|
||||
# 返回 TS_SIGN_UNSIGNED / TS_SIGN_SIGNED / TS_SIGN_UNKNOWN(不表态)
|
||||
# ============================================================
|
||||
def SpecSignFromTypeNameSpan(text: str, start: sizet, end: sizet) -> int:
|
||||
"""按 text[start:end] 精确判定符号性,未覆盖返回 TS_SIGN_UNKNOWN"""
|
||||
if text is None:
|
||||
return TS_SIGN_UNKNOWN
|
||||
# --- t/c 核心无符号原语 ---
|
||||
if _spec_name_eq(text, start, end, "CUInt8T") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUInt16T") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUInt32T") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUInt64T") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUnsignedChar") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUnsignedShort") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUnsignedInt") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUnsignedLong") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUnsignedLongLong") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CSizeT") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CUIntPtrT") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
if _spec_name_eq(text, start, end, "CBool") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
# --- 内建小写标量 ---
|
||||
if _spec_name_eq(text, start, end, "bool") != 0:
|
||||
return TS_SIGN_UNSIGNED
|
||||
# --- t/c 核心有符号原语 ---
|
||||
if _spec_name_eq(text, start, end, "CInt8T") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CInt16T") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CInt32T") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CInt64T") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CSignedChar") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CShort") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CInt") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CLong") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CLongLong") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CPtrDiffT") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "CChar") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "int") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
if _spec_name_eq(text, start, end, "char") != 0:
|
||||
return TS_SIGN_SIGNED
|
||||
return TS_SIGN_UNKNOWN
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SpecSignFromTypeName - 类型名(NUL 终止串)精确判定符号性
|
||||
# ============================================================
|
||||
def SpecSignFromTypeName(name: str) -> int:
|
||||
"""按类型名精确判定符号性,未覆盖返回 TS_SIGN_UNKNOWN"""
|
||||
if name is None:
|
||||
return TS_SIGN_UNKNOWN
|
||||
return SpecSignFromTypeNameSpan(name, 0, string.strlen(name))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeSpec - 类型描述符
|
||||
#
|
||||
@@ -497,7 +613,7 @@ def _text_to_spec(text: str, depth: int) -> TypeSpec | t.CPtr:
|
||||
return _spec_make(TS_VOID, 0, TS_SIGN_UNKNOWN)
|
||||
# i32 / u64 / f64
|
||||
if text[0] == 'u' or text[0] == 'i' or text[0] == 'f':
|
||||
bits: int = stdlib.atoi(text + 1)
|
||||
bits: int = string.atoi(text + 1)
|
||||
if bits <= 0:
|
||||
return None
|
||||
if text[0] == 'u':
|
||||
@@ -671,6 +787,109 @@ def SpecBitWidth(sp: TypeSpec | t.CPtr) -> int:
|
||||
return sp.Bits
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SpecFromLLVMType - 已解析 LLVM 类型 → TypeSpec(结构翻译)
|
||||
#
|
||||
# 只做**结构层**翻译:Int / Float / Void / Ptr / Array / Func / Struct。
|
||||
# - 指针层级:由 Ptr 递归得到(NewTypePtr 内 PtrLevel = Elem.PtrLevel + 1)
|
||||
# - 数组维度:取 Array.Count(元素语义三元组由 NewTypeArray 填)
|
||||
# - 函数签名:Ret + 形参数组(沿 ParamNode 链表遍历;llvmlite **无按下标取参**)
|
||||
# - 结构体:取结构体名;匿名结构体退化为无名 TS_STRUCT
|
||||
#
|
||||
# ⚠️ 两个**已知局限**(有意为之,避免臆造):
|
||||
# 1. 符号性:LLVM 类型层**无法区分 iN 与 uN**(都是 i32)⇒ 本转换器一律给
|
||||
# `TS_INT + TS_SIGN_SIGNED`(与 SpecBaseText 的 "iN" 编码口径一致,保证驻留键
|
||||
# 不产生"同键不同义")。**无符号性必须由注解侧(符号性真源)覆盖**;
|
||||
# 消费方在 S3 切读前**不要直接信任**本 spec 的 IsSigned。
|
||||
# 2. 变参:`...` 不在 `LLVMType.Func` 上(只存在于 `llvmlite.Function.IsVarArg`)
|
||||
# ⇒ 本转换器恒置 IsVarArg=0;带变参的签名需由函数对象侧补写。
|
||||
#
|
||||
# 本函数当前**无调用点**(S2 只入库;接线在后续步骤)。
|
||||
# ============================================================
|
||||
def SpecFromLLVMType(arena: TypeSpecArena | t.CPtr,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> TypeSpec | t.CPtr:
|
||||
"""把已解析的 LLVM 类型翻译成 TypeSpec;不支持或为 None 时返回 None"""
|
||||
if arena is None or ty is None:
|
||||
return None
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Int(bits):
|
||||
if bits == 1:
|
||||
return NewTypeSpec(arena, TS_BOOL, 1, TS_SIGN_UNSIGNED)
|
||||
return NewTypeSpec(arena, TS_INT, bits, TS_SIGN_SIGNED)
|
||||
case llvmlite.LLVMType.Float(bits):
|
||||
return NewTypeSpec(arena, TS_FLOAT, bits, TS_SIGN_SIGNED)
|
||||
case llvmlite.LLVMType.Void():
|
||||
return NewTypeSpec(arena, TS_VOID, 0, TS_SIGN_UNKNOWN)
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
return _spec_from_ptr(arena, pointee)
|
||||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||||
return _spec_from_array(arena, elem_ty, count)
|
||||
case llvmlite.LLVMType.Func(ret, params, pcount):
|
||||
return _spec_from_func(arena, ret, params, pcount)
|
||||
case llvmlite.LLVMType.Struct(_, _, sname):
|
||||
return _spec_from_struct(arena, sname)
|
||||
case _:
|
||||
return None
|
||||
|
||||
|
||||
def _spec_from_ptr(arena: TypeSpecArena | t.CPtr,
|
||||
pointee: llvmlite.LLVMType | t.CPtr) -> TypeSpec | t.CPtr:
|
||||
"""Ptr(pointee) → TypeSpec(PtrLevel/ElemBits/IsElemPtr 由 NewTypePtr 填)"""
|
||||
inner: TypeSpec | t.CPtr = SpecFromLLVMType(arena, pointee)
|
||||
if inner is None:
|
||||
return None
|
||||
return NewTypePtr(arena, inner)
|
||||
|
||||
|
||||
def _spec_from_array(arena: TypeSpecArena | t.CPtr,
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr,
|
||||
count: int) -> TypeSpec | t.CPtr:
|
||||
"""[count x elem] → TypeSpec(ArrayCount/ElemBits/IsElemPtr 由 NewTypeArray 填)"""
|
||||
inner: TypeSpec | t.CPtr = SpecFromLLVMType(arena, elem_ty)
|
||||
if inner is None:
|
||||
return None
|
||||
return NewTypeArray(arena, inner, count)
|
||||
|
||||
|
||||
def _spec_from_func(arena: TypeSpecArena | t.CPtr,
|
||||
ret: llvmlite.LLVMType | t.CPtr,
|
||||
params: llvmlite.ParamNode | t.CPtr,
|
||||
pcount: int) -> TypeSpec | t.CPtr:
|
||||
"""函数类型 → TypeSpec(形参沿 ParamNode 链表遍历;IsVarArg 恒 0,见上)"""
|
||||
ret_s: TypeSpec | t.CPtr = SpecFromLLVMType(arena, ret)
|
||||
if ret_s is None:
|
||||
return None
|
||||
if pcount <= 0:
|
||||
no_params: sizet | t.CPtr = None
|
||||
return NewTypeFunc(arena, ret_s, no_params, 0, 0)
|
||||
params_arr: sizet | t.CPtr = CompilerFactory.factory.PermPool.alloc(8 * pcount)
|
||||
if params_arr is None:
|
||||
return None
|
||||
node: llvmlite.ParamNode | t.CPtr = params
|
||||
i: int = 0
|
||||
while node is not None and i < pcount:
|
||||
pty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(node)
|
||||
ps: TypeSpec | t.CPtr = SpecFromLLVMType(arena, pty)
|
||||
if ps is None:
|
||||
return None
|
||||
slot: sizet | t.CPtr = (sizet | t.CPtr)(
|
||||
t.CVoid(uint64(params_arr) + uint64(i * 8), t.CPtr))
|
||||
if slot is None:
|
||||
return None
|
||||
slot[0] = sizet(ps)
|
||||
node = llvmlite.paramnode_get_next(node)
|
||||
i += 1
|
||||
return NewTypeFunc(arena, ret_s, params_arr, pcount, 0)
|
||||
|
||||
|
||||
def _spec_from_struct(arena: TypeSpecArena | t.CPtr,
|
||||
sname: str) -> TypeSpec | t.CPtr:
|
||||
"""有名结构体 → TS_STRUCT + BaseName;匿名结构体 → 无名 TS_STRUCT"""
|
||||
if sname is not None:
|
||||
return NewTypeStruct(arena, TS_STRUCT, sname)
|
||||
return NewTypeSpec(arena, TS_STRUCT, 0, TS_SIGN_UNKNOWN)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SpecSelfCheck - S1 自检(不参与编译流程,供手动调用/后续单测)
|
||||
#
|
||||
|
||||
Reference in new issue
Block a user