refactor: 重构语义分析上下文类

- 优化 Context 类的结构和功能,提高可读性和可维护性- 添加当前模块名管理方法,增强模块作用域支持
- 改进类型解析方法,支持更复杂的类型查找逻辑
- 统一错误收集和日志输出接口
This commit is contained in:
Luke 2025-08-29 17:02:14 +08:00
parent 4a64659856
commit 1a34e3e436

View File

@ -9,47 +9,61 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* {@code Context} 表示语义分析阶段的全局上下文环境 * {@code Context} 表示语义分析阶段的全局上下文环境贯穿于编译器语义分析流程中
* <p> * <p>
* 该类贯穿整个语义分析流程集中管理以下内容 * 主要负责
* <ul> * <ul>
* <li>模块信息管理所有已加载模块包括源模块和内置模块</li> * <li>模块信息的统一管理含模块结构体类型</li>
* <li>错误收集集中存储语义分析期间产生的 {@link SemanticError}</li> * <li>收集和存储语义分析阶段产生的所有错误</li>
* <li>日志输出控制可选支持调试信息</li> * <li>根据配置输出调试日志</li>
* <li>分析器调度通过 {@link AnalyzerRegistry} 分发对应分析器</li> * <li>调度各类语义分析器执行</li>
* <li>类型解析包括内建类型数组类型结构体等自定义类型</li>
* </ul> * </ul>
* <p> * 该类为所有分析器提供便捷的访问查找和工具方法
* 提供便捷的 getter 方法和类型解析工具方法
* </p>
*/ */
public class Context { public class Context {
/** /**
* 模块表模块名 {@link ModuleInfo}用于模块查找与跨模块引用 * 所有模块信息表
* <p>
* 键为模块名值为 {@link ModuleInfo} 实例用于支持跨模块类型/结构体引用
*/ */
private final Map<String, ModuleInfo> modules; private final Map<String, ModuleInfo> modules;
/** /**
* 错误列表语义分析过程中收集的所有 {@link SemanticError} * 语义分析期间收集的所有错误对象
* <p>
* 每当发现语义错误时 {@link SemanticError} 添加到该列表
*/ */
private final List<SemanticError> errors; private final List<SemanticError> errors;
/** /**
* 日志开关若为 true将启用 {@link #log(String)} 输出日志信息 * 日志输出开关
* <p>
* true 调用 {@link #log(String)} 会输出日志信息用于调试
*/ */
private final boolean verbose; private final boolean verbose;
/** /**
* 语义分析器注册表用于按节点类型动态调度分析器 * 语义分析器注册表
* <p>
* 用于根据语法树节点类型动态分派对应的分析器
*/ */
private final AnalyzerRegistry registry; private final AnalyzerRegistry registry;
/** /**
* 构造语义分析上下文对象 * 当前正在处理的模块名
* <p>
* 主要用于类型解析时限定结构体查找的作用域
*/
private String currentModuleName;
/**
* 构造一个新的语义分析上下文实例
* *
* @param modules 已注册的模块信息集合 * @param modules 所有已加载模块的映射表
* @param errors 错误收集器分析器将所有语义错误写入此列表 * @param errors 用于收集错误的列表
* @param verbose 是否启用调试日志输出 * @param verbose 是否输出日志
* @param registry 分析器注册表提供类型到分析器的映射与调度能力 * @param registry 分析器注册表
*/ */
public Context(Map<String, ModuleInfo> modules, public Context(Map<String, ModuleInfo> modules,
List<SemanticError> errors, List<SemanticError> errors,
@ -61,102 +75,137 @@ public class Context {
this.registry = registry; this.registry = registry;
} }
// ------------------ 模块信息 ------------------ // ==== Getter 方法基本访问器 ====
/** /**
* 获取所有模块信息映射表 * 获取所有模块信息表模块名 ModuleInfo
* */
* @return 模块名到模块信息{@link ModuleInfo}的映射表 public Map<String, ModuleInfo> modules() {
return modules;
}
/**
* 获取所有模块信息表 {@link #modules()} 等价
*/ */
public Map<String, ModuleInfo> getModules() { public Map<String, ModuleInfo> getModules() {
return modules; return modules;
} }
/** /**
* 模块信息 getter快捷方式 * 获取语义分析期间收集的所有错误
*
* @return 模块名到模块信息{@link ModuleInfo}的映射表
*/ */
public Map<String, ModuleInfo> modules() { public List<SemanticError> errors() {
return modules; return errors;
} }
// ------------------ 错误收集 ------------------
/** /**
* 获取语义分析过程中记录的所有错误 * 获取语义分析期间收集的所有错误 {@link #errors()} 等价
*
* @return 错误列表
*/ */
public List<SemanticError> getErrors() { public List<SemanticError> getErrors() {
return errors; return errors;
} }
/** /**
* 错误列表 getter快捷方式 * 获取语义分析器注册表
*
* @return 错误列表
*/
public List<SemanticError> errors() {
return errors;
}
// ------------------ 分析器注册表 ------------------
/**
* 获取分析器注册表用于分发语句与表达式分析器
*
* @return {@link AnalyzerRegistry} 实例
*/ */
public AnalyzerRegistry getRegistry() { public AnalyzerRegistry getRegistry() {
return registry; return registry;
} }
/** /**
* 注册表 getter快捷方式 * 输出语义分析日志信息 verbose 控制
* *
* @return {@link AnalyzerRegistry} 实例 * @param msg 日志消息内容
*/
public AnalyzerRegistry registry() {
return registry;
}
// ------------------ 日志输出 ------------------
/**
* 打印日志信息仅当 {@code verbose} true 时生效
*
* @param msg 日志内容
*/ */
public void log(String msg) { public void log(String msg) {
if (verbose) { if (verbose) System.out.println("[semantic] " + msg);
System.out.println("[SemanticAnalyzer] " + msg);
}
} }
// ------------------ 工具函数 ------------------ // ==== 当前模块管理 ====
/** /**
* 将类型名称字符串解析为对应的类型实例支持多维数组后缀 * 获取当前正在分析的模块名
* <p>
* 例如"int" int 类型"int[][]" 二维整型数组类型
* </p>
* *
* @param name 类型名称支持 "[]" 数组后缀 * @return 当前模块名可能为 null
* @return 对应的 {@link Type} 实例若无法识别返回 null
*/ */
public Type parseType(String name) { public String getCurrentModule() {
int dims = 0; return currentModuleName;
}
/**
* 设置当前正在分析的模块名
* <p>
* 用于限定结构体查找的优先作用域
*
* @param moduleName 当前模块名
*/
public void setCurrentModule(String moduleName) {
this.currentModuleName = moduleName;
}
// ==== 类型解析工具 ====
/**
* 解析类型字符串为 {@link Type} 实例
* <p>
* 支持内建类型数组类型 "[]" 后缀用户自定义结构体类型
* 类型解析的查找顺序为<br>
* 1. 内建类型<br>
* 2. 当前模块定义的结构体类型<br>
* 3. 当前模块导入模块中的结构体类型<br>
* 4. 全局所有模块的结构体类型
*
* @param typeName 类型名称字符串 "int""Foo""Bar[][]"
* @return 解析出的 {@link Type} 实例若找不到则返回 null
*/
public Type parseType(String typeName) {
if (typeName == null) return null; // 处理空输入
String name = typeName; // 剥离数组后缀前的基本类型名
int dims = 0; // 记录数组维度
// 支持多维数组 "int[][]" -> dims=2
while (name.endsWith("[]")) { while (name.endsWith("[]")) {
name = name.substring(0, name.length() - 2); name = name.substring(0, name.length() - 2);
dims++; dims++;
} }
// 1) 优先查找内建类型
Type base = BuiltinTypeRegistry.BUILTIN_TYPES.get(name); Type base = BuiltinTypeRegistry.BUILTIN_TYPES.get(name);
if (base == null) return null;
Type t = base; // 2) 如果不是内建类型则尝试查找结构体类型
for (int i = 0; i < dims; i++) { if (base == null) {
t = new ArrayType(t); // 2.1 当前模块下的结构体
if (currentModuleName != null && modules.containsKey(currentModuleName)) {
ModuleInfo mi = modules.get(currentModuleName);
if (mi.getStructs().containsKey(name)) {
base = mi.getStructs().get(name);
} else {
// 2.2 当前模块导入的模块中的结构体
for (String imp : mi.getImports()) {
ModuleInfo im = modules.get(imp);
if (im != null && im.getStructs().containsKey(name)) {
base = im.getStructs().get(name);
break;
}
}
}
}
// 2.3 全局所有模块的结构体作为兜底
if (base == null) {
for (ModuleInfo im : modules.values()) {
if (im.getStructs().containsKey(name)) {
base = im.getStructs().get(name);
break;
}
}
}
} }
if (base == null) return null; // 所有路径均未找到
// 包装数组类型根据数组维度递归封装
Type t = base;
for (int i = 0; i < dims; i++) t = new ArrayType(t);
return t; return t;
} }
} }