feat(asm,err,typedef): 支持 __asm__/__llvmir__ 裸名与 typedef 语法糖;解析报错统一 Python 风格 traceback

CallGenCBuiltin/CallGenDispatch: __asm__/__llvmir__ 裸名调用,asminp/asmout/irinp/irout 与裸 ASM_DESCR。

AssignGenMixin: 支持 define NAME: T = V 形式的 CDefine 浮点值恢复;负浮点(-1e308)剥一层 UnaryOp(USub)。

Phase1Main/Phase2: AST 解析失败改调 GenApi.dump_parse_traceback(Traceback + File/行 + 源码行 + caret)。

TypeGenResolve/TypeGenCType: typedef 文本扫描统一支持 typedef 语法糖(builtins/库/单文件三处共用同一解析)。
This commit is contained in:
TermiNexus committed 2026-09-25 13:11:16 +08:00
1 parent a7af34bd7e
commit 676c19c362
7 files changed
+245 -171

No files matched your search

+6 -4
View File
@@ -779,10 +779,12 @@ def RunPhase1(mb: memhub.MemBuddy*, includes_dir: str, temp_dir: str,
if tree_pv is None:
stdlib.free(src_buf_pv)
p1bpre_failed += 1
VLogger.error(
f"[Phase 1b-pre] {file_path_pv} | AST 解析失败"
f"(第 {ast.get_parse_err_line()} 行第 {ast.get_parse_err_col()} 列: "
f"{ast.get_parse_err_msg()})", "Phase1")
# 解析失败:改由 Python 风格 traceback 统一上报(Traceback + File/行 +
# 源码行 + caret + SyntaxError: 消息;消息本身含 token 类型与前/后 token
# 附注,见 includes/ast/parser.vp 的 _record_parse_err_ctx),与单文件
# 管线 BuildPipeline 同一条上报路径。
VLogger.error(f"[Phase 1b-pre] {file_path_pv} | AST 解析失败", "Phase1")
GenApi.dump_parse_traceback(file_path_pv)
continue
pyi_buf_pv: bytes = stdlib.malloc(Phase1.PYI_BUF_SIZE)
if pyi_buf_pv is not None:
+6 -4
View File
@@ -805,10 +805,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy*,
if tree_vp2 is None:
stdlib.free(src_buf_vp2)
vpi_failed_p2 += 1
VLogger.error(
f"[Phase A-pre-vpi] {ent_vp2.Path} | AST 解析失败"
f"(第 {ast.get_parse_err_line()} 行第 {ast.get_parse_err_col()} 列: "
f"{ast.get_parse_err_msg()})", "PhaseA")
# 解析失败:改由 Python 风格 traceback 统一上报(Traceback + File/行 +
# 源码行 + caret + SyntaxError: 消息;消息本身含 token 类型与前/后 token
# 附注,见 includes/ast/parser.vp 的 _record_parse_err_ctx),与单文件
# 管线 BuildPipeline 同一条上报路径。
VLogger.error(f"[Phase A-pre-vpi] {ent_vp2.Path} | AST 解析失败", "PhaseA")
GenApi.dump_parse_traceback(ent_vp2.Path)
continue
pyi_buf_vp2: bytes = stdlib.malloc(PYI_BUF_SIZE_P2)
if pyi_buf_vp2 is not None:
+41 -7
View File
@@ -575,6 +575,21 @@ novirtual class AssignGenMixin:
first_arg_cd: ast.AST* = cl_args_cd.get(0)
if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant:
val_node = first_arg_cd
# 负浮点字面量(`define NAME: double = -1e308`):RHS 是
# UnaryOp(USub, Constant(CONST_FLOAT)),不是裸 Constant ⇒ 否则会落到下方的
# 整数提取,报"无法从表达式解析编译期常量"。此处只剥掉一层一元负号,把内层
# 浮点 Constant 交给浮点分支:浮点值一律由源文件文本恢复
# (_recover_cdefine_float 读原文,负号天然保留,不需在此取反)。
# 负整数不受影响(UnaryOp 继续落到 extract_cdefine_int_value,它本就认
# UnaryOp(USub, Constant)),故只拦 CONST_FLOAT 这一种内层形态。
if val_node is not None and val_node.kind() == ast.ASTKind.UnaryOp:
uu_cd: ast.UnaryOp* = ast.UnaryOp*(val_node)
if uu_cd is not None and uu_cd.op == OpKind.USub \
and uu_cd.operand is not None \
and uu_cd.operand.kind() == ast.ASTKind.Constant:
ic_cd: ast.Constant* = ast.Constant*(uu_cd.operand)
if ic_cd is not None and ic_cd.const_kind == ast.CONST_FLOAT:
val_node = uu_cd.operand
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
cn_fp: ast.Constant* = ast.Constant*(val_node)
if cn_fp.const_kind == ast.CONST_STR:
@@ -653,19 +668,36 @@ novirtual class AssignGenMixin:
if pos < total_len:
pos += 1
# 匹配行首的 "name",其后(跳过空格)必须是 ':' 或 '='
# (AnnAssign:`NAME: t.CDouble = 1.0`;无注解赋值:`NAME = 1.0`)
if line_len < name_len + 1:
# `define NAME: T = V`(宏常量关键字形式):名字前有 "define " 前缀,
# 且行内没有 t.CDefine 文本(CDefine 标记来自关键字本身,见
# parser.vp 的 _parse_define_const / _is_define_const)。故名字匹配
# 基准 ns 顺延到关键字之后的第一个非空白字符,并记下 is_define_line。
ns: sizet = line_start
is_define_line: int = 0
if line_len >= 8:
if buf[ns] == 'd' and buf[ns + 1] == 'e' and buf[ns + 2] == 'f' \
and buf[ns + 3] == 'i' and buf[ns + 4] == 'n' and buf[ns + 5] == 'e':
nb: sizet = ns + 6
while nb < line_start + line_len and (buf[nb] == ' ' or buf[nb] == '\t'):
nb += 1
# 后随空白才算关键字(避免匹配到 defineX 之类的标识符)
if nb > ns + 6:
is_define_line = 1
ns = nb
# 匹配行首(或 define 之后)的 "name",其后(跳过空格)必须是 ':' 或 '='
# (AnnAssign:`NAME: t.CDouble = 1.0`;无注解赋值:`NAME = 1.0`;
# 宏常量:`define NAME: double = 3.14`)
if ns + name_len + 1 > line_start + line_len:
continue
match_ok: int = 1
ki: sizet
for ki in range(name_len):
if buf[line_start + ki] != name[ki]:
if buf[ns + ki] != name[ki]:
match_ok = 0
break
if match_ok == 0:
continue
sep: sizet = line_start + name_len
sep: sizet = ns + name_len
while sep < line_start + line_len and buf[sep] == ' ':
sep += 1
if sep >= line_start + line_len:
@@ -673,8 +705,10 @@ novirtual class AssignGenMixin:
if buf[sep] != ':' and buf[sep] != '=':
continue
# CDefine 路径要求行内出现 "t.CDefine";普通浮点全局路径跳过该检查
if require_cdefine != 0:
# CDefine 路径要求行内出现 "t.CDefine",或本行是 `define` 关键字形式
# (宏常量 `define NAME: T = V` 行内无 t.CDefine 文本);普通浮点全局
# 路径(require_cdefine=0)跳过该检查
if require_cdefine != 0 and is_define_line == 0:
has_cd: int = 0
ci: sizet = line_start + name_len + 1
while ci + 8 <= line_start + line_len:
+22 -1
View File
@@ -823,6 +823,9 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
mod_nm2: ast.Name* = ast.Name*(at.value)
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0:
return self._resolve_register(at.attr)
# 裸名 ASM_DESCR.XXX:省去 t. 前缀的等价写法
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "ASM_DESCR") == 0:
return self._resolve_register(at.attr)
return ""
# Constant: 字符串常量
@@ -844,9 +847,27 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
def _asm_is_c_call(self, node: ast.Call*) -> str:
"""检查 Call 节点是否是 c.XXX 调用,返回属性名或 None"""
"""检查 Call 节点是否是操作数标记内建调用,返回规范名或 None
支持两种等价写法(裸名写法省去 c. 前缀),裸名统一返回规范名,
使调用点的 string.strcmp 判定无需分支:
- 内联汇编:c.AsmInp/c.AsmOut ↔ asminp/asmout("AsmInp"/"AsmOut")
- LLVM IR:c.LInp/c.LOut ↔ irinp/irout("LInp"/"LOut")
"""
if node is None or node.func is None:
return None
if node.func.kind() == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(node.func)
if nm.id is not None:
if string.strcmp(nm.id, "asminp") == 0:
return "AsmInp"
if string.strcmp(nm.id, "asmout") == 0:
return "AsmOut"
if string.strcmp(nm.id, "irinp") == 0:
return "LInp"
if string.strcmp(nm.id, "irout") == 0:
return "LOut"
return None
if node.func.kind() != ast.ASTKind.Attribute:
return None
at: ast.Attribute* = ast.Attribute*(node.func)
+20
View File
@@ -104,6 +104,26 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
translate_c_asm/translate_c_llvmir 成功处理 void 时返回 None,
若不加 hit_box 会被 translate_call 误判为"未命中"继续走外部函数路径。
"""
# __asm__(...) / __llvmir__(...) 语法糖:裸名调用等价 c.Asm(...) / c.LLVMIR(...)
# (无 c. 前缀,无需 import c)。必须在 c.* Attribute 分支之前拦截:
# 裸名 cl.func 是 Name 而非 Attribute。
if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
bare_nm: ast.Name* = ast.Name*(cl.func)
if bare_nm.id is not None and string.strcmp(bare_nm.id, "__asm__") == 0:
# 无输出(void)时 translate_c_asm 返回 None:置命中标记,
# 避免 translate_call 误判未命中继续走外部函数路径。
if hit_box is not None:
hit_box[0] = 1
return self.Gen.CallGenCBuiltin.translate_c_asm(pool, builder, mod, cl, trans)
if bare_nm.id is not None and string.strcmp(bare_nm.id, "__llvmir__") == 0:
# c.LLVMIR 总是无返回值(返回 None):置命中标记
if hit_box is not None:
hit_box[0] = 1
return self.Gen.CallGenCBuiltin.translate_c_llvmir(pool, builder, mod, cl, trans)
if bare_nm.id is not None and (string.strcmp(bare_nm.id, "irinp") == 0 or string.strcmp(bare_nm.id, "irout") == 0):
# irinp/irout 独立调用时返回 0(仅在 __llvmir__ 的 f-string 内有意义)
return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0")
# 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call)
# 及 coro.* 协程库拦截(coro.coro_run 内联翻译,TPV-M1)
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
+11 -46
View File
@@ -588,7 +588,7 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
return count
def register_ctypedef_from_source(self, pool: memhub.MemBuddy*,
src: str) -> int:
"""从源码文本逐行扫描注册 CTypedef(NAME: t.CTypedef = TYPE)
"""从源码文本逐行扫描注册 CTypedef(`typedef N = V` 或 `N: t.CTypedef = V`)
stdint.vp 崩溃根因修复:AST 字符串字段(attr/id)token 零拷贝指向
src_buf,跨阶段内容不稳定(悬空),ScanCTypedefDeclarations 读
@@ -608,54 +608,19 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
count: int = 0
line_start: sizet = 0
i: sizet = 0
# 行解析缓冲("NAME\0VALUE\0"),整文件复用(register_ctypedef 内部自会复制)
td_buf: str = pool.alloc(320)
while i <= src_len:
if i == src_len or src[i] == '\n':
line_len: sizet = i - line_start
if line_len > 0:
# 找行内第一个 ':'(跳过注释行)
j: sizet = 0
found_colon: int = 0
while j < line_len:
ch_c: char = src[line_start + j]
if ch_c == ':':
found_colon = 1
break
if ch_c == '#' or ch_c == '\r':
break
j += 1
if found_colon != 0:
# 左段 NAME(trim 尾随空格)
name_len: sizet = j
while name_len > 0 and src[line_start + name_len - 1] == ' ':
name_len -= 1
if name_len > 0 and name_len < 128:
# 右段必须含 "t.CTypedef"
rest: str = src + line_start + j + 1
if string.strstr(rest, "t.CTypedef") is not None:
# 提取 "=" 后的类型表达式(trim 空格)
eq_ptr: str = string.strstr(rest, "=")
if eq_ptr is not None:
# '=' 相对行首偏移;值段严格限定在行尾
# (line_len)内——防止跨行吞换行+后续行内容
eq_off: sizet = sizet(uint64(eq_ptr) - uint64(src)) - line_start
vs: sizet = eq_off + 1
while vs < line_len and src[line_start + vs] == ' ':
vs += 1
ve: sizet = line_len
while ve > vs and (src[line_start + ve - 1] == ' '
or src[line_start + ve - 1] == '\r'):
ve -= 1
if ve > vs:
vlen: sizet = ve - vs
name_buf: str = pool.alloc(name_len + 1)
ty_buf: str = pool.alloc(vlen + 1)
if name_buf is not None and ty_buf is not None:
string.strncpy(name_buf, src + line_start, name_len)
name_buf[name_len] = '\0'
string.strncpy(ty_buf, src + line_start + vs, vlen)
ty_buf[vlen] = '\0'
self.register_ctypedef(pool, name_buf, ty_buf)
count += 1
if line_len > 0 and td_buf is not None:
# 两种等价形态统一解析:语法糖 `typedef N = V`(builtins.vp 现用
# 形态)与注解 `N: t.CTypedef = V`(stdint.vp 等库模块)。
if self.Gen.TypeGenResolve._parse_typedef_line(td_buf, src, line_start, line_len) != 0:
name_buf: str = td_buf
ty_buf: str = td_buf + string.strlen(td_buf) + 1
self.register_ctypedef(pool, name_buf, ty_buf)
count += 1
line_start = i + 1
i += 1
return count
+139 -109
View File
@@ -882,6 +882,98 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if string.strncmp(buf + al_start, mod, mod_len) == 0:
return buf + tg_start
return None
def _parse_typedef_line(self, out_buf: str, buf: str,
line_start: sizet, line_len: sizet) -> int:
"""一行源码 → typedef 声明写入 out_buf("NAME\\0VALUE\\0"),返回 1/0
兼容两种等价形态(对齐 TPC TypeAnnotationResolver._parse_typedef_line):
- 语法糖 `typedef NAME = VALUE`(includes/builtins.vp 现用形态)
- 注解形态 `NAME: t.CTypedef = VALUE`(stdint.vp 等库模块)
只识别不注册;非法形态(缺 NAME / 缺 '=' / 缺 VALUE / 注释行)返回 0。
约束:NAME < 128、VALUE <= 190(out_buf 容量需 >= 320)。
"""
if buf is None or out_buf is None or line_len == 0:
return 0
lead: sizet = 0
while lead < line_len and (buf[line_start + lead] == ' ' or buf[line_start + lead] == '\t'):
lead += 1
if lead >= line_len or buf[line_start + lead] == '#':
return 0
name_s: sizet = 0
name_l: sizet = 0
vs: sizet = 0
is_sugar: int = 0
if lead + 8 <= line_len and buf[line_start + lead] == 't' \
and buf[line_start + lead + 1] == 'y' and buf[line_start + lead + 2] == 'p' \
and buf[line_start + lead + 3] == 'e' and buf[line_start + lead + 4] == 'd' \
and buf[line_start + lead + 5] == 'e' and buf[line_start + lead + 6] == 'f' \
and (buf[line_start + lead + 7] == ' ' or buf[line_start + lead + 7] == '\t'):
is_sugar = 1
if is_sugar != 0:
k: sizet = lead + 7
while k < line_len and (buf[line_start + k] == ' ' or buf[line_start + k] == '\t'):
k += 1
name_s = k
while k < line_len and buf[line_start + k] != ' ' and buf[line_start + k] != '\t' \
and buf[line_start + k] != '=' and buf[line_start + k] != '\r':
k += 1
name_l = k - name_s
while k < line_len and (buf[line_start + k] == ' ' or buf[line_start + k] == '\t'):
k += 1
if name_l == 0 or name_l >= 128:
return 0
if k >= line_len or buf[line_start + k] != '=':
return 0
if k + 1 < line_len and buf[line_start + k + 1] == '=':
return 0
vs = k + 1
else:
j: sizet = 0
fc: int = 0
while j < line_len:
ch: char = buf[line_start + j]
if ch == ':':
fc = 1
break
if ch == '#' or ch == '\r':
break
j += 1
if fc == 0:
return 0
name_l = j
while name_l > 0 and buf[line_start + name_l - 1] == ' ':
name_l -= 1
if name_l == 0 or name_l >= 128:
return 0
rest: str = buf + line_start + j + 1
if string.strstr(rest, "t.CTypedef") is None:
return 0
eq: str = string.strstr(rest, "=")
if eq is None:
return 0
vs = sizet(uint64(eq) - uint64(buf)) - line_start + 1
while vs < line_len and (buf[line_start + vs] == ' ' or buf[line_start + vs] == '\t'):
vs += 1
ve: sizet = line_len
while ve > vs and (buf[line_start + ve - 1] == ' ' or buf[line_start + ve - 1] == '\t' \
or buf[line_start + ve - 1] == '\r'):
ve -= 1
if ve <= vs:
return 0
vlen: sizet = ve - vs
if vlen > 190:
vlen = 190
ci: sizet = 0
while ci < name_l:
out_buf[ci] = buf[line_start + name_s + ci]
ci += 1
out_buf[name_l] = '\0'
ci = 0
while ci < vlen:
out_buf[name_l + 1 + ci] = buf[line_start + vs + ci]
ci += 1
out_buf[name_l + 1 + vlen] = '\0'
return 1
def _lookup_builtins_typedef(self, pool: memhub.MemBuddy*,
name: str) -> str:
"""builtins 最后匹配:查 includes/builtins.vp 的 CTypedef 声明
@@ -1005,73 +1097,42 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
b_i: sizet = 0
b_line_start: sizet = 0
b_res: str = None
# 行解析缓冲("NAME\0VALUE\0"),整文件复用;需要保留的值当场复制到独立分配
# (register_ctypedef 内部自会复制,b_res 是唯一需要拷出的引用)。
b_td_buf: str = pool.alloc(320)
while b_i <= b_total:
if b_i == b_total or b_buf[b_i] == '\n':
b_line_len: sizet = b_i - b_line_start
if b_line_len > 0:
# 找行内第一个 ':'(跳过注释行)
b_j: sizet = 0
b_found_colon: int = 0
while b_j < b_line_len:
b_ch: char = b_buf[b_line_start + b_j]
if b_ch == ':':
b_found_colon = 1
break
if b_ch == '#' or b_ch == '\r':
break
b_j += 1
if b_found_colon != 0:
# 左段 NAME(trim 尾随空格)
b_name_len: sizet = b_j
while b_name_len > 0 and b_buf[b_line_start + b_name_len - 1] == ' ':
b_name_len -= 1
if b_name_len > 0 and b_name_len < 128:
# 右段必须含 "t.CTypedef",提取 "=" 后的类型表达式
b_rest2: str = b_buf + b_line_start + b_j + 1
if string.strstr(b_rest2, "t.CTypedef") is not None:
b_eq2: str = string.strstr(b_rest2, "=")
if b_eq2 is not None:
# '=' 相对行首偏移;值段严格限定在行尾
# (b_line_len)内——此前 strlen 跨行吞掉
# 换行+下一行注释(size_t: t.CTypedef =
# stdint.size_t 后跟 "# size_t: t.CTypedef =
# sizet" → 值含 "\n# ..." → 展开取到注释
# 里的 '.' → 模块名垃圾,main2.vp size_t 根因)
b_eq_off: sizet = sizet(uint64(b_eq2) - uint64(b_buf)) - b_line_start
b_vs: sizet = b_eq_off + 1
while b_vs < b_line_len and b_buf[b_line_start + b_vs] == ' ':
b_vs += 1
b_ve: sizet = b_line_len
while b_ve > b_vs and (b_buf[b_line_start + b_ve - 1] == ' '
or b_buf[b_line_start + b_ve - 1] == '\r'):
b_ve -= 1
if b_ve > b_vs:
b_vlen: sizet = b_ve - b_vs
b_nb: str = pool.alloc(b_name_len + 1)
b_tb: str = pool.alloc(b_vlen + 1)
if b_nb is not None and b_tb is not None:
string.strncpy(b_nb, b_buf + b_line_start, b_name_len)
b_nb[b_name_len] = '\0'
string.strncpy(b_tb, b_buf + b_line_start + b_vs, b_vlen)
b_tb[b_vlen] = '\0'
# 表内已存在(模块自身/import 注入)不覆盖
b_exist: str = self.Gen.TypeGenCType.lookup_ctypedef(b_nb)
if b_exist is None or self.Gen.TypeGenCType.CTypedefFound == 0:
# 急切展开模块限定引用再注册(size_t:
# t.CTypedef = stdint.size_t → 注册 sizet),
# 使表内直接持有最终类型表达式,下游查表即中
b_tb_x: str = self._expand_typedef_ref(pool, b_tb)
if b_tb_x is not None:
self.Gen.TypeGenCType.register_ctypedef(pool, b_nb, b_tb_x)
if string.strcmp(b_nb, name) == 0:
b_res = b_tb
if b_line_len > 0 and b_td_buf is not None:
# 两种等价形态统一解析:语法糖 `typedef N = V` 与注解
# `N: t.CTypedef = V`。builtins.vp 已改用语法糖形态,
# 只认注解形态会让本兜底表恒空 → 裸名退化为 %"{mod}.名"* 假结构体。
if self._parse_typedef_line(b_td_buf, b_buf, b_line_start, b_line_len) != 0:
b_nb: str = b_td_buf
b_nl2: sizet = string.strlen(b_nb)
b_tb: str = b_td_buf + b_nl2 + 1
# 表内已存在(模块自身/import 注入)不覆盖
b_exist: str = self.Gen.TypeGenCType.lookup_ctypedef(b_nb)
if b_exist is None or self.Gen.TypeGenCType.CTypedefFound == 0:
# 急切展开模块限定引用再注册(size_t:
# t.CTypedef = stdint.size_t → 注册 sizet),
# 使表内直接持有最终类型表达式,下游查表即中
b_tb_x: str = self._expand_typedef_ref(pool, b_tb)
if b_tb_x is not None:
self.Gen.TypeGenCType.register_ctypedef(pool, b_nb, b_tb_x)
if string.strcmp(b_nb, name) == 0:
# 独立复制:b_td_buf 会被后续行覆盖
b_vl: sizet = string.strlen(b_tb)
b_res = pool.alloc(b_vl + 1)
if b_res is not None:
string.strcpy(b_res, b_tb)
b_line_start = b_i + 1
b_i += 1
# 置扫描完成标记:同文件内后续 miss 直接查表,不再重复读 builtins 源
self.Gen.TypeGenCType.BuiltinsTypedefScanned = 1
# b_res 是 b_buf 内的切片(非副本),必须在 free 之前完成展开与诊断复制:
# _expand_typedef_ref 可能原样返回指向 b_buf 的指针,free 之后再读即
# heap-use-after-free(诊断字段还会长期持有该悬垂指针)。
# b_res 已复制到 pool(非 b_buf 切片),展开与诊断复制仍须在 free(b_buf)
# 之前完成——_expand_typedef_ref 的中间结果可能引用 b_buf 之外的状态,
# 且诊断字段须长期持有自有副本。
b_final_r: str = None
if b_res is not None:
b_final_r = self._expand_typedef_ref(pool, b_res)
@@ -1209,64 +1270,33 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
return None
if m_read < LONG(BUF_L):
m_buf[sizet(m_read)] = 0
attr_len: sizet = string.strlen(attr)
m_total: sizet = string.strlen(m_buf)
m_i: sizet = 0
m_ls: sizet = 0
m_res: str = None
# 行解析缓冲("NAME\0VALUE\0"),整文件复用;命中值复制到独立分配再保留
# (m_td_buf 会被后续行覆盖,而 m_res 要活到 free(m_buf) 之后)。
m_td_buf: str = pool.alloc(320)
# 全文件扫描(不再在首次命中处提前退出):既为该模块建立完整持久缓存,
# 又用与原实现相同的比较取 attr 的首次命中值(保证首次调用返回值不变)。
while m_i <= m_total:
if m_i == m_total or m_buf[m_i] == '\n':
m_line_len: sizet = m_i - m_ls
if m_line_len > 0:
m_j: sizet = 0
m_fc: int = 0
while m_j < m_line_len:
m_ch: char = m_buf[m_ls + m_j]
if m_ch == ':':
m_fc = 1
break
if m_ch == '#' or m_ch == '\r':
break
m_j += 1
if m_fc != 0:
m_nl: sizet = m_j
while m_nl > 0 and m_buf[m_ls + m_nl - 1] == ' ':
m_nl -= 1
m_rest: str = m_buf + m_ls + m_j + 1
if string.strstr(m_rest, "t.CTypedef") is not None:
m_eq: str = string.strstr(m_rest, "=")
if m_eq is not None:
# '=' 相对行首偏移;值段严格限定在行尾
# (m_line_len)内,防止跨行吞换行+后续内容
m_eq_off: sizet = sizet(uint64(m_eq) - uint64(m_buf)) - m_ls
m_vs: sizet = m_eq_off + 1
while m_vs < m_line_len and m_buf[m_ls + m_vs] == ' ':
m_vs += 1
m_ve: sizet = m_line_len
while m_ve > m_vs and (m_buf[m_ls + m_ve - 1] == ' '
or m_buf[m_ls + m_ve - 1] == '\r'):
m_ve -= 1
if m_ve > m_vs:
m_vlen: sizet = m_ve - m_vs
m_tb: str = pool.alloc(m_vlen + 1)
if m_tb is not None:
string.strncpy(m_tb, m_buf + m_ls + m_vs, m_vlen)
m_tb[m_vlen] = '\0'
# 写入持久缓存(首次遇到的名字为准)
self._register_lib_typedef_cache(m_real, m_buf + m_ls, m_nl, m_tb)
# 原实现语义:attr 的首次匹配值
if m_res is None and m_nl == attr_len:
m_nm_ok: int = 1
m_ki: sizet = 0
while m_ki < attr_len:
if m_buf[m_ls + m_ki] != attr[m_ki]:
m_nm_ok = 0
break
m_ki += 1
if m_nm_ok == 1:
m_res = m_tb
if m_line_len > 0 and m_td_buf is not None:
# 两种等价形态统一解析:语法糖 `typedef N = V` 与注解
# `N: t.CTypedef = V`(库模块源两种形态都须识别)。
if self._parse_typedef_line(m_td_buf, m_buf, m_ls, m_line_len) != 0:
m_nb: str = m_td_buf
m_nl: sizet = string.strlen(m_nb)
m_tb: str = m_td_buf + m_nl + 1
# 写入持久缓存(首次遇到的名字为准)
self._register_lib_typedef_cache(m_real, m_nb, m_nl, m_tb)
# 原实现语义:attr 的首次匹配值
if m_res is None and string.strcmp(m_nb, attr) == 0:
m_vl: sizet = string.strlen(m_tb)
m_res = pool.alloc(m_vl + 1)
if m_res is not None:
string.strcpy(m_res, m_tb)
m_ls = m_i + 1
m_i += 1
# 置该模块已扫描标记:同模块后续查询只查持久缓存表,不再重复读源