diff --git a/App/lib/Phase/Phase1/Phase1Main.vp b/App/lib/Phase/Phase1/Phase1Main.vp index 1f4773c..163c4bf 100644 --- a/App/lib/Phase/Phase1/Phase1Main.vp +++ b/App/lib/Phase/Phase1/Phase1Main.vp @@ -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: diff --git a/App/lib/Phase/Phase2/__init__.vp b/App/lib/Phase/Phase2/__init__.vp index bd1de64..00a8918 100644 --- a/App/lib/Phase/Phase2/__init__.vp +++ b/App/lib/Phase/Phase2/__init__.vp @@ -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: diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 7a07469..1023e11 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -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: diff --git a/App/lib/core/Gen/Call/CallGenCBuiltin.vp b/App/lib/core/Gen/Call/CallGenCBuiltin.vp index 1c31350..0c746df 100644 --- a/App/lib/core/Gen/Call/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/Call/CallGenCBuiltin.vp @@ -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) diff --git a/App/lib/core/Gen/Call/CallGenDispatch.vp b/App/lib/core/Gen/Call/CallGenDispatch.vp index 18d5f97..8e194c5 100644 --- a/App/lib/core/Gen/Call/CallGenDispatch.vp +++ b/App/lib/core/Gen/Call/CallGenDispatch.vp @@ -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: diff --git a/App/lib/core/Gen/Type/TypeGenCType.vp b/App/lib/core/Gen/Type/TypeGenCType.vp index d015fd3..97055a9 100644 --- a/App/lib/core/Gen/Type/TypeGenCType.vp +++ b/App/lib/core/Gen/Type/TypeGenCType.vp @@ -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 diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index effb9b0..d52d92c 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -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 # 置该模块已扫描标记:同模块后续查询只查持久缓存表,不再重复读源