407 lines
15 KiB
Python
407 lines
15 KiB
Python
import t, c
|
||
from stdint import *
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
|
||
|
||
# ============================================================
|
||
# HandlesVar - 嵌套作用域符号表 + 变量管理
|
||
#
|
||
# 使用 Scope 链(Parent 指针)管理嵌套作用域,
|
||
# 每个作用域包含一个 VarEntry 数组(扁平化,已验证可工作)。
|
||
#
|
||
# 作用域类型:
|
||
# SCOPE_MODULE — 模块级(根作用域)
|
||
# SCOPE_FUNCTION — 函数级
|
||
# SCOPE_BLOCK — 块级(if/for/while,当前未使用块作用域)
|
||
# ============================================================
|
||
|
||
# 作用域类型常量
|
||
SCOPE_MODULE: t.CDefine = 0
|
||
SCOPE_FUNCTION: t.CDefine = 1
|
||
SCOPE_BLOCK: t.CDefine = 2
|
||
|
||
# 每个作用域最大变量数
|
||
MAX_VARS: t.CDefine = 256
|
||
|
||
|
||
# ============================================================
|
||
# VarEntry - 变量表条目
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class VarEntry:
|
||
"""变量表条目"""
|
||
Name: t.CChar | t.CPtr
|
||
Alloca: llvmlite.Value | t.CPtr
|
||
Used: t.CInt
|
||
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
|
||
IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长
|
||
|
||
|
||
# ============================================================
|
||
# Scope - 作用域节点
|
||
#
|
||
# Parent 指向父作用域(None 表示根),
|
||
# Vars 是 VarEntry 数组,VarCount 是当前变量数。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class Scope:
|
||
"""作用域节点"""
|
||
Parent: Scope | t.CPtr
|
||
Vars: VarEntry | t.CPtr
|
||
VarCount: t.CInt
|
||
Kind: t.CInt
|
||
|
||
|
||
# ============================================================
|
||
# SymbolTable - 嵌套作用域符号表
|
||
#
|
||
# Root 是模块级根作用域,Current 是当前作用域。
|
||
# enter_scope/exit_scope 管理作用域栈。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class SymbolTable:
|
||
"""嵌套作用域符号表"""
|
||
Pool: memhub.MemBuddy | t.CPtr
|
||
Root: Scope | t.CPtr
|
||
Current: Scope | t.CPtr
|
||
|
||
|
||
# ============================================================
|
||
# init_vars — 分配并清零 VarEntry 数组
|
||
# ============================================================
|
||
def init_vars(pool: memhub.MemBuddy | t.CPtr) -> VarEntry | t.CPtr:
|
||
"""分配并清零变量表数组"""
|
||
size: t.CSizeT = MAX_VARS * VarEntry.__sizeof__()
|
||
vars_ptr: VarEntry | t.CPtr = pool.alloc(size)
|
||
if vars_ptr is not None:
|
||
string.memset(vars_ptr, 0, size)
|
||
return vars_ptr
|
||
|
||
|
||
# ============================================================
|
||
# find_var — 在变量表中按名称查找
|
||
# ============================================================
|
||
def find_var(vars_ptr: VarEntry | t.CPtr,
|
||
var_count: int,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""在变量表中按名称查找"""
|
||
if name is None or vars_ptr is None:
|
||
return None
|
||
entry_size: t.CSizeT = VarEntry.__sizeof__()
|
||
for i in range(var_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
|
||
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None and entry.Used != 0:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry.Alloca
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy)
|
||
# ============================================================
|
||
def find_var_entry(vars_ptr: VarEntry | t.CPtr,
|
||
var_count: int,
|
||
name: str) -> VarEntry | t.CPtr:
|
||
"""在变量表中按名称查找,返回 VarEntry 或 None"""
|
||
if name is None or vars_ptr is None:
|
||
return None
|
||
entry_size: t.CSizeT = VarEntry.__sizeof__()
|
||
for i in range(var_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
|
||
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None and entry.Used != 0:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry
|
||
# ============================================================
|
||
def lookup_var_entry(symtab: SymbolTable | t.CPtr,
|
||
name: str) -> VarEntry | t.CPtr:
|
||
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: Scope | t.CPtr = symtab.Current
|
||
while scope is not None:
|
||
result: VarEntry | t.CPtr = find_var_entry(scope.Vars, scope.VarCount, name)
|
||
if result is not None:
|
||
return result
|
||
scope = scope.Parent
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# set_var_annot_class_name — 设置变量的原始类型注解类名
|
||
#
|
||
# 在函数参数定义后调用,存储原始类型注解的类名。
|
||
# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化),
|
||
# 通过 AnnotClassName 查找实际结构体类型。
|
||
# ============================================================
|
||
def set_var_annot_class_name(symtab: SymbolTable | t.CPtr,
|
||
name: str,
|
||
class_name: str) -> int:
|
||
"""设置变量的原始类型注解类名,返回 0=成功 / 1=失败"""
|
||
if symtab is None or name is None:
|
||
return 1
|
||
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
|
||
if entry is None:
|
||
return 1
|
||
entry.AnnotClassName = class_name
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型
|
||
#
|
||
# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*,
|
||
# 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。
|
||
# 此标志在 HandlesAnnAssign 中根据注解形式设置。
|
||
# ============================================================
|
||
def set_var_ptr_element(symtab: SymbolTable | t.CPtr,
|
||
name: str) -> int:
|
||
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败"""
|
||
if symtab is None or name is None:
|
||
return 1
|
||
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
|
||
if entry is None:
|
||
return 1
|
||
entry.IsPtrElement = 1
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# add_var — 添加变量到变量表
|
||
# ============================================================
|
||
def add_var(vars_ptr: VarEntry | t.CPtr,
|
||
var_count: int,
|
||
name: str,
|
||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""添加变量到变量表"""
|
||
if name is None or alloca is None or vars_ptr is None:
|
||
return 1
|
||
if var_count >= MAX_VARS:
|
||
return 1
|
||
entry_size: t.CSizeT = VarEntry.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size
|
||
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
entry.Name = name
|
||
entry.Alloca = alloca
|
||
entry.Used = 1
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性)
|
||
#
|
||
# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成,
|
||
# 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。
|
||
# 标准做法:所有 alloca 在函数入口块生成。
|
||
#
|
||
# 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。
|
||
# ============================================================
|
||
def _alloca_at_entry(builder: llvmlite.IRBuilder | t.CPtr,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""在函数入口块生成 alloca,返回 alloca 值
|
||
|
||
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca,
|
||
确保所有 alloca 在入口块,避免支配性违规。
|
||
"""
|
||
if builder is None or ty is None:
|
||
return None
|
||
return llvmlite.build_alloca_at_entry(builder, ty)
|
||
|
||
|
||
# ============================================================
|
||
# get_or_create_var — 查找或创建变量 alloca(旧版兼容)
|
||
# ============================================================
|
||
def get_or_create_var(pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
vars_ptr: VarEntry | t.CPtr,
|
||
var_count: int,
|
||
name: str,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""查找或创建变量 alloca"""
|
||
existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name)
|
||
if existing is not None:
|
||
return existing
|
||
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
|
||
if alloca is None:
|
||
return None
|
||
if add_var(vars_ptr, var_count, name, alloca) != 0:
|
||
return None
|
||
return alloca
|
||
|
||
|
||
# ============================================================
|
||
# _create_scope — 创建新作用域节点(内部辅助函数)
|
||
# ============================================================
|
||
def _create_scope(pool: memhub.MemBuddy | t.CPtr,
|
||
parent: Scope | t.CPtr,
|
||
kind: int) -> Scope | t.CPtr:
|
||
"""创建并初始化作用域节点"""
|
||
scope: Scope | t.CPtr = pool.alloc(Scope.__sizeof__())
|
||
if scope is None:
|
||
return None
|
||
string.memset(scope, 0, Scope.__sizeof__())
|
||
scope.Parent = parent
|
||
scope.Vars = init_vars(pool)
|
||
scope.VarCount = 0
|
||
scope.Kind = kind
|
||
if scope.Vars is None:
|
||
return None
|
||
return scope
|
||
|
||
|
||
# ============================================================
|
||
# init_symbol_table — 创建符号表(含模块级根作用域)
|
||
# ============================================================
|
||
def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> SymbolTable | t.CPtr:
|
||
"""创建并初始化符号表,包含模块级根作用域"""
|
||
if pool is None:
|
||
return None
|
||
symtab: SymbolTable | t.CPtr = pool.alloc(SymbolTable.__sizeof__())
|
||
if symtab is None:
|
||
return None
|
||
string.memset(symtab, 0, SymbolTable.__sizeof__())
|
||
symtab.Pool = pool
|
||
|
||
# 创建根作用域(模块级)
|
||
root: Scope | t.CPtr = _create_scope(pool, None, SCOPE_MODULE)
|
||
if root is None:
|
||
return None
|
||
|
||
symtab.Root = root
|
||
symtab.Current = root
|
||
return symtab
|
||
|
||
|
||
# ============================================================
|
||
# enter_scope — 进入新作用域
|
||
# ============================================================
|
||
def enter_scope(symtab: SymbolTable | t.CPtr,
|
||
kind: int) -> Scope | t.CPtr:
|
||
"""进入新作用域,返回新创建的作用域"""
|
||
if symtab is None:
|
||
return None
|
||
pool: memhub.MemBuddy | t.CPtr = symtab.Pool
|
||
scope: Scope | t.CPtr = _create_scope(pool, symtab.Current, kind)
|
||
if scope is None:
|
||
return None
|
||
symtab.Current = scope
|
||
return scope
|
||
|
||
|
||
# ============================================================
|
||
# exit_scope — 退出当前作用域
|
||
# ============================================================
|
||
def exit_scope(symtab: SymbolTable | t.CPtr):
|
||
"""退出当前作用域,恢复到父作用域"""
|
||
if symtab is not None and symtab.Current is not None:
|
||
symtab.Current = symtab.Current.Parent
|
||
|
||
|
||
# ============================================================
|
||
# define_var — 在当前作用域定义变量
|
||
# ============================================================
|
||
def define_var(symtab: SymbolTable | t.CPtr,
|
||
name: str,
|
||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""在当前作用域定义变量,返回 0 成功"""
|
||
if symtab is None or name is None or alloca is None:
|
||
return 1
|
||
scope: Scope | t.CPtr = symtab.Current
|
||
if scope is None:
|
||
return 1
|
||
ret: int = add_var(scope.Vars, scope.VarCount, name, alloca)
|
||
if ret == 0:
|
||
scope.VarCount = scope.VarCount + 1
|
||
return ret
|
||
|
||
|
||
# ============================================================
|
||
# define_module_var — 在模块作用域定义变量
|
||
# ============================================================
|
||
def define_module_var(symtab: SymbolTable | t.CPtr,
|
||
name: str,
|
||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""在模块作用域定义变量,返回 0 成功"""
|
||
if symtab is None or name is None or alloca is None:
|
||
return 1
|
||
scope: Scope | t.CPtr = symtab.Root
|
||
if scope is None:
|
||
return 1
|
||
ret: int = add_var(scope.Vars, scope.VarCount, name, alloca)
|
||
if ret == 0:
|
||
scope.VarCount = scope.VarCount + 1
|
||
return ret
|
||
|
||
|
||
# ============================================================
|
||
# lookup_var — 从当前作用域逐级向上查找变量
|
||
# ============================================================
|
||
def lookup_var(symtab: SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从当前作用域逐级向上查找变量,返回 alloca 或 None"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: Scope | t.CPtr = symtab.Current
|
||
while scope is not None:
|
||
result: llvmlite.Value | t.CPtr = find_var(
|
||
scope.Vars, scope.VarCount, name)
|
||
if result is not None:
|
||
return result
|
||
scope = scope.Parent
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# lookup_current — 仅在当前作用域查找变量
|
||
# ============================================================
|
||
def lookup_current(symtab: SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""仅在当前作用域查找变量"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: Scope | t.CPtr = symtab.Current
|
||
if scope is None:
|
||
return None
|
||
return find_var(scope.Vars, scope.VarCount, name)
|
||
|
||
|
||
# ============================================================
|
||
# lookup_module_var — 在模块作用域查找变量
|
||
# ============================================================
|
||
def lookup_module_var(symtab: SymbolTable | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""在模块作用域查找变量"""
|
||
if symtab is None or name is None:
|
||
return None
|
||
scope: Scope | t.CPtr = symtab.Root
|
||
if scope is None:
|
||
return None
|
||
return find_var(scope.Vars, scope.VarCount, name)
|
||
|
||
|
||
# ============================================================
|
||
# get_or_create_sym — 查找或创建变量(在当前作用域)
|
||
# ============================================================
|
||
def get_or_create_sym(symtab: SymbolTable | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
name: str,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""查找或创建变量 alloca(在当前作用域)"""
|
||
existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name)
|
||
if existing is not None:
|
||
return existing
|
||
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
|
||
if alloca is None:
|
||
return None
|
||
define_var(symtab, name, alloca)
|
||
return alloca
|