修改注释

This commit is contained in:
Luke 2025-05-07 17:48:54 +08:00
parent b26ff57f4e
commit 919f68550f
12 changed files with 211 additions and 135 deletions

View File

@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
import org.jcnc.snow.compiler.parser.ast.ParameterNode;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
* FunctionBuilder 负责将 AST 中的 FunctionNode 构建为可执行的 IRFunction
*

View File

@ -8,36 +8,68 @@ import org.jcnc.snow.compiler.parser.ast.ReturnNode;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
* 负责语句节点到 IR 的转换
* StatementBuilder 负责将解析器生成的语句 AST 节点StatementNode
* 转换为编译器中间表示IR中的指令序列
* <p>
* 支持的语句类型包括
* <ul>
* <li>表达式语句ExpressionStatementNode</li>
* <li>赋值语句AssignmentNode</li>
* <li>声明语句DeclarationNode</li>
* <li>返回语句ReturnNode</li>
* </ul>
* 对于不支持的节点类型方法会抛出 IllegalStateException
*/
public class StatementBuilder {
/** 当前的 IR 上下文,用于生成指令和管理作用域 */
private final IRContext ctx;
/** 用于生成表达式对应的 IR 寄存器和指令的构建器 */
private final ExpressionBuilder exprBuilder;
/**
* 构造函数初始化 IR 上下文并创建 ExpressionBuilder 实例
*
* @param ctx IR 上下文对象包含当前函数的作用域指令列表等信息
*/
public StatementBuilder(IRContext ctx) {
this.ctx = ctx;
this.exprBuilder = new ExpressionBuilder(ctx);
}
/**
* 入口根据不同语句类型分发
* 根据不同的语句节点类型将其转换为相应的 IR 指令
* <ul>
* <li>ExpressionStatementNode生成表达式指令忽略返回值</li>
* <li>AssignmentNode生成右侧表达式指令将结果绑定到变量第一次声明或更新</li>
* <li>DeclarationNode如带初始化器则先生成初始化表达式指令并声明变量否则只声明变量</li>
* <li>ReturnNode如带返回表达式则生成带返回值的指令否则生成无返回值指令</li>
* </ul>
*
* @param stmt 要构建的语句 AST 节点
* @throws IllegalStateException 如果遇到不支持的语句类型则抛出此异常
*/
public void build(StatementNode stmt) {
if (stmt instanceof ExpressionStatementNode(org.jcnc.snow.compiler.parser.ast.base.ExpressionNode expression)) {
// 表达式语句: 仅生成表达式对应的 IR 指令不关注结果
if (stmt instanceof ExpressionStatementNode(
org.jcnc.snow.compiler.parser.ast.base.ExpressionNode expression)) {
exprBuilder.build(expression);
return;
}
// 赋值语句: 先生成右侧表达式指令获取寄存器再声明或更新变量的值绑定
if (stmt instanceof AssignmentNode(
String variable, org.jcnc.snow.compiler.parser.ast.base.ExpressionNode value
)) {
IRVirtualRegister vr = exprBuilder.build(value);
if (ctx.getScope().lookup(variable) == null) {
// 首次赋值声明变量并绑定寄存器
ctx.getScope().declare(variable, vr);
} else {
// 变量已存在更新绑定的寄存器
ctx.getScope().put(variable, vr);
}
return;
}
// 声明语句: 如有初始化表达式则先构建初始化值并声明否则直接声明变量
if (stmt instanceof DeclarationNode dn) {
if (dn.getInitializer().isPresent()) {
IRVirtualRegister init = exprBuilder.build(dn.getInitializer().get());
@ -47,6 +79,7 @@ public class StatementBuilder {
}
return;
}
// 返回语句: 区分有返回值和无返回值两种情况
if (stmt instanceof ReturnNode rn) {
if (rn.getExpression().isPresent()) {
IRVirtualRegister vr = exprBuilder.build(rn.getExpression().get());
@ -56,6 +89,7 @@ public class StatementBuilder {
}
return;
}
// 不支持的语句类型
throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName());
}
}

View File

@ -6,79 +6,98 @@ import java.util.ArrayList;
import java.util.List;
/**
* 表示一个函数级别的中间表示IR
* 每个 IRFunction 包含函数名称指令列表函数体和用于管理寄存器编号的计数器
* IRFunction 表示一个函数级别的中间表示IR实体
* <p>
* 每个 IRFunction 包含
* <ul>
* <li>函数名称</li>
* <li>函数体的指令列表</li>
* <li>用于分配虚拟寄存器编号的计数器</li>
* </ul>
*
* 该类提供虚拟寄存器分配指令添加和调试输出等功能
*/
public class IRFunction {
// 函数的名称
/** 函数名称 */
private final String name;
// 存放函数体中的指令列表
/** 存放函数体中所有中间表示指令 */
private final List<IRInstruction> body = new ArrayList<>();
// 寄存器编号计数器用于为新建的虚拟寄存器分配唯一编号
/**
* 虚拟寄存器编号计数器
* 每调用一次 newRegister()计数器自增并分配唯一编号
*/
private int regCounter = 0;
/**
* 构造函数创建一个新的 IRFunction 实例
* 构造函数初始化 IRFunction 实例并设置函数名称
*
* @param name 函数名称
* @param name 函数名称
*/
public IRFunction(String name) {
this.name = name;
}
/* —— API —— */
/* —— 公共 API —— */
/**
* 创建一个新的虚拟寄存器并自动分配一个唯一的编号
* 创建并返回一个新的虚拟寄存器
*
* @return 新建的虚拟寄存器
* @return 分配了唯一编号的 IRVirtualRegister 实例
*/
public IRVirtualRegister newRegister() {
return new IRVirtualRegister(regCounter++);
}
/**
* 向函数体中添加一条指令
* 向函数体中添加一条中间表示指令
*
* @param inst 要添加的中间表示指令
* @param inst 要添加的 IRInstruction 对象
*/
public void add(IRInstruction inst) {
body.add(inst);
}
/**
* 获取函数体的全部指令列表
* 获取函数体的所有中间表示指令
*
* @return 包含所有指令的列表
* @return 包含所有 IRInstruction 的列表
*/
public List<IRInstruction> body() {
return body;
}
/**
* 获取函数的名称
* 获取函数的名称
*
* @return 函数名称
* @return 函数名称字符串
*/
public String name() {
return name;
}
/**
* 获取当前已分配的寄存器数量
* 获取当前已分配的虚拟寄存器数量
*
* @return 当前寄存器计数值
* @return 当前寄存器计数
*/
public int registerCount() {
return regCounter;
}
/**
* 将整个函数包括函数名和函数体转换为字符串形式便于打印或调试
* 将整个 IRFunction 对象格式化为字符串便于打印和调试
* 输出示例
* <pre>
* func 方法名 {
* 指令1
* 指令2
* ...
* }
* </pre>
*
* @return 函数的字符串表示
* @return 格式化后的函数字符串表示
*/
@Override
public String toString() {

View File

@ -5,36 +5,36 @@ import java.util.Collections;
import java.util.List;
/**
* IRProgram 表示一份完整的中间表示IR程序
* IRProgram 表示一份完整的中间表示IR程序
* <p>
* 每个 IRProgram 由多个函数IRFunction组成
* 是编译器后端生成目标代码的基础单位
* 每个 IRProgram 由多个 IRFunction 组成
* 是编译器后端进行目标代码生成的核心数据结构
*/
public final class IRProgram {
// 存储程序中所有函数的列表
/** 存储程序中所有函数的列表 */
private final List<IRFunction> functions = new ArrayList<>();
/**
* 程序中添加一个函数
* IRProgram 中添加一个函数
*
* @param fn 要添加的 IRFunction
* @param fn 要添加的 IRFunction 对象
*/
public void add(IRFunction fn) {
functions.add(fn);
}
/**
* 获取所有函数的不可变列表
* 获取程序中所有函数的不可变视图
*
* @return 包含所有 IRFunction 不可修改视图
* @return 包含所有 IRFunction 只读列表
*/
public List<IRFunction> functions() {
return Collections.unmodifiableList(functions);
}
/**
* 将整个 IRProgram 转换成字符串表示
* 每个函数占一行适合打印调试
* 将整个 IRProgram 转换为字符串表示方便打印或调试
* 每个函数据单独一行
*
* @return 程序的字符串表示
*/

View File

@ -5,15 +5,17 @@ import org.jcnc.snow.compiler.ir.value.IRLabel;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
/**
* IRValue 表示在中间表示IR系统中能作为操作数使用的基本单位
* IRValue 表示在中间表示IR系统中可用于指令操作数的基本单位
* <p>
* 包括
* IRVirtualRegister虚拟寄存器
* IRConstant常量
* IRLabel跳转标签
* <p>
* 本接口使用 sealed 限定明确列出所有允许实现它的子类型
* 保证类型安全并便于在编译时做穷尽检查
* 支持的具体类型包括
* <ul>
* <li>{@link IRVirtualRegister} 虚拟寄存器代表计算中间结果的临时存储</li>
* <li>{@link IRConstant} 常量值表示字面量或计算常量</li>
* <li>{@link IRLabel} 跳转标签用于控制流跳转目标</li>
* </ul>
*
* 本接口使用 sealed 限定明确列出了所有允许的实现子类型
* 有助于在编译期进行穷尽性对齐和类型安全检查
*/
public sealed interface IRValue
permits IRVirtualRegister, IRConstant, IRLabel {

View File

@ -8,30 +8,31 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
* 表示一个二元运算指令Binary Operation Instruction
* 格式为dest = lhs (OP) rhs
* 其中 dest 是结果寄存器lhs rhs 是操作数OP 是操作符如加法减法等
* BinaryOperationInstruction 表示一个二元运算指令格式dest = lhs OP rhs
* <p>
* 支持的操作符由 IROpCode 定义例如加法减法乘法除法等
* lhs rhs 两个操作数进行指定 OP 运算并将结果存储到 dest 虚拟寄存器中
*/
public final class BinaryOperationInstruction extends IRInstruction {
// 二元操作符例如加法减法乘法除法等
/** 二元运算操作符,如 ADD、SUB、MUL、DIV 等 */
private final IROpCode op;
// 存放运算结果的虚拟寄存器
/** 运算结果存放的目标虚拟寄存器 */
private final IRVirtualRegister dest;
// 左操作数
/** 左操作数 */
private final IRValue lhs;
// 右操作数
/** 右操作数 */
private final IRValue rhs;
/**
* 构造函数创建一个二元运算指令实例
*
* @param op 运算操作符
* @param dest 运算结果存放的目标寄存器
* @param lhs 左侧操作数
* @param rhs 右侧操作数
* @param op 指定的二元运算操作符
* @param dest 结果存放的目标虚拟寄存器
* @param lhs 左侧参与运算的操作数
* @param rhs 右侧参与运算的操作数
*/
public BinaryOperationInstruction(IROpCode op, IRVirtualRegister dest, IRValue lhs, IRValue rhs) {
this.op = op;
@ -41,9 +42,9 @@ public final class BinaryOperationInstruction extends IRInstruction {
}
/**
* 获取指令对应的操作符
* 获取指令的操作符
*
* @return 操作符
* @return 当前指令使用的 IROpCode 操作符
*/
@Override
public IROpCode op() {
@ -53,7 +54,7 @@ public final class BinaryOperationInstruction extends IRInstruction {
/**
* 获取指令结果存放的目标寄存器
*
* @return 目标寄存器
* @return 目标虚拟寄存器
*/
@Override
public IRVirtualRegister dest() {
@ -61,9 +62,9 @@ public final class BinaryOperationInstruction extends IRInstruction {
}
/**
* 获取此指令所使用的操作数左操作数和右操作数
* 获取指令使用的操作数列表
*
* @return 操作数列表
* @return 包含 lhs rhs 列表
*/
@Override
public List<IRValue> operands() {
@ -71,10 +72,9 @@ public final class BinaryOperationInstruction extends IRInstruction {
}
/**
* 将指令转换成字符串表示用于调试和打印
* 格式示例v1 = add v2, v3
* 将指令格式化为字符串样式dest = op lhs, rhs
*
* @return 字符串表示
* @return 指令的字符串表示方便打印与调试
*/
@Override
public String toString() {

View File

@ -9,22 +9,22 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
* 表示常量加载指令Load IRConstant Instruction
* 格式为dest = CONST k
* 其中 dest 是结果寄存器k 是要加载的常量值
* LoadConstInstruction 表示一个常量加载指令格式dest = CONST k
* <p>
* 将字面量常量 k 加载到目标虚拟寄存器 dest 以便后续指令使用该常量值
*/
public final class LoadConstInstruction extends IRInstruction {
// 要加载的常量值
/** 要加载的常量值 */
private final IRConstant k;
// 存放常量的目标虚拟寄存器
/** 存放常量的目标虚拟寄存器 */
private final IRVirtualRegister dest;
/**
* 构造函数创建一个常量加载指令实例
*
* @param dest 目标寄存器用于存放常量
* @param k 要加载的常量
* @param dest 目标寄存器用于存放常量
* @param k 要加载的常量
*/
public LoadConstInstruction(IRVirtualRegister dest, IRConstant k) {
this.dest = dest;
@ -44,7 +44,7 @@ public final class LoadConstInstruction extends IRInstruction {
/**
* 获取指令结果存放的目标寄存器
*
* @return 目标虚拟寄存器
* @return 存放常量的虚拟寄存器
*/
@Override
public IRVirtualRegister dest() {
@ -52,9 +52,9 @@ public final class LoadConstInstruction extends IRInstruction {
}
/**
* 获取此指令所用的操作数只有一个常量
* 获取此指令的操作数列表仅包含要加载的常量 k
*
* @return 包含常量 k 操作数列表
* @return 包含常量 k 单元素列表
*/
@Override
public List<IRValue> operands() {
@ -62,10 +62,9 @@ public final class LoadConstInstruction extends IRInstruction {
}
/**
* 将指令转换成字符串表示用于调试和打印
* 格式示例v1 = CONST 42
* 将指令转换为字符串表示格式dest = CONST k
*
* @return 字符串表示
* @return 指令的字符串形式便于打印和调试
*/
@Override
public String toString() {

View File

@ -8,20 +8,28 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
* 表示函数的返回指令Return Instruction
* 格式为return [val]
* ReturnInstruction 表示函数返回指令格式return [value]
* <p>
* - 如果是 void 返回即没有返回值val null
* - 否则返回指定寄存器中的值
* 支持两种形式
* <ul>
* <li>无返回值void: value null生成无参 RET 指令</li>
* <li>有返回值: value 为要返回的虚拟寄存器生成带参数 RET 指令</li>
* </ul>
*
* 返回指令用于结束函数执行并将可选的返回值传递给调用者
*/
public final class ReturnInstruction extends IRInstruction {
// 返回值对应的虚拟寄存器如果是 void 返回则为 null
/**
* 要返回的虚拟寄存器
* 如果是 void 返回则为 null
*/
private final IRVirtualRegister value;
/**
* 构造函数创建一个返回指令实例
*
* @param value 要返回的虚拟寄存器如果是 void 返回则传入 null
* @param value 要返回的寄存器
* 如果函数不返回值void则传入 null
*/
public ReturnInstruction(IRVirtualRegister value) {
this.value = value;
@ -38,9 +46,11 @@ public final class ReturnInstruction extends IRInstruction {
}
/**
* 获取此指令的操作数列表
* - 如果是 void 返回返回空列表
* - 否则返回包含返回值寄存器的列表
* 获取此指令的操作数列表
* <ul>
* <li>如果无返回值返回空列表</li>
* <li>否则返回包含要返回的寄存器</li>
* </ul>
*
* @return 操作数列表
*/
@ -50,21 +60,24 @@ public final class ReturnInstruction extends IRInstruction {
}
/**
* 获取要返回的虚拟寄存器
* 获取要返回的寄存器
*
* @return 返回值寄存器 null表示 void 返回
* @return 返回值寄存器如果为 void 返回则为 null
*/
public IRVirtualRegister value() {
return value;
}
/**
* 将返回指令转换成字符串表示用于调试和打印
* 格式示例
* - "RET" 无返回值
* - "RET v1"返回寄存器 v1 的值
* 将返回指令转换为字符串形式便于打印和调试
*
* @return 字符串表示
* 格式
* <ul>
* <li>无返回值: "RET"</li>
* <li>有返回值: "RET <寄存器>"</li>
* </ul>
*
* @return 指令的字符串表示
*/
@Override
public String toString() {

View File

@ -8,29 +8,32 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
* 表示一元运算指令Unary Operation Instruction
* 格式为dest = OP val
* UnaryOperationInstruction 表示一个一元运算指令格式dest = OP val
* <p>
* - dest运算结果存放的目标寄存器
* - OP一元操作符如取负按位取反等
* - val操作数
* 支持的操作符由 IROpCode 定义例如
* <ul>
* <li>NEG 取负</li>
* <li>NOT 按位取反或逻辑非</li>
* </ul>
*
* 将单一操作数 val 进行指定 OP 运算并将结果存储到目标寄存器 dest
*/
public final class UnaryOperationInstruction extends IRInstruction {
// 一元操作符例如 NEG取负NOT逻辑非
/** 一元运算操作符,如 NEG、NOT 等 */
private final IROpCode op;
// 运算结果存放的目标虚拟寄存器
/** 运算结果存放的目标虚拟寄存器 */
private final IRVirtualRegister dest;
// 一元运算的操作数
/** 一元运算的操作数 */
private final IRValue val;
/**
* 构造函数创建一个一元运算指令实例
*
* @param op 一元操作符
* @param dest 结果存放的目标寄存器
* @param val 操作数
* @param op 指定的一元操作符
* @param dest 运算结果存放的目标寄存器
* @param val 参与运算的操作数
*/
public UnaryOperationInstruction(IROpCode op, IRVirtualRegister dest, IRValue val) {
this.op = op;
@ -41,7 +44,7 @@ public final class UnaryOperationInstruction extends IRInstruction {
/**
* 获取此指令对应的操作符
*
* @return 一元操作符
* @return 当前指令使用的一元操作符
*/
@Override
public IROpCode op() {
@ -59,9 +62,9 @@ public final class UnaryOperationInstruction extends IRInstruction {
}
/**
* 获取此指令所使用的操作数只有一个操作数
* 获取此指令的操作数列表仅包含一个操作数 val
*
* @return 仅包含 val 的操作数列表
* @return 单元素列表其中元素为 val
*/
@Override
public List<IRValue> operands() {
@ -69,10 +72,11 @@ public final class UnaryOperationInstruction extends IRInstruction {
}
/**
* 将指令转换为字符串表示形式用于调试和打印
* 格式示例v1 = NEG v2
* 将一元运算指令转换为字符串表示格式dest = OP val
* <p>
* 示例"v1 = NEG v2"
*
* @return 字符串表示
* @return 指令的字符串形式用于打印和调试
*/
@Override
public String toString() {

View File

@ -3,15 +3,16 @@ package org.jcnc.snow.compiler.ir.value;
import org.jcnc.snow.compiler.ir.core.IRValue;
/**
* IRConstant 表示一个常量值例如整数常量字符串常量等
* IRConstant 表示中间表示IR系统中的常量值
* <p>
* 在中间表示IR常量通常是不可变的直接使用的值而不是寄存器或临时变量
* 常量是不可变的字面量或编译期计算结果
* 可以是整数浮点数字符串等类型
* IR 常量直接作为操作数使用而不需要寄存器
*/
public record IRConstant(Object value) implements IRValue {
/**
* 将常量值转换为字符串表示
* 主要用于打印 IR 指令时显示常量内容
* 将常量值转换为字符串表示用于 IR 指令打印和调试
*
* @return 常量的字符串形式
*/

View File

@ -3,20 +3,21 @@ package org.jcnc.snow.compiler.ir.value;
import org.jcnc.snow.compiler.ir.core.IRValue;
/**
* IRLabel 表示 IR 中的跳转目标标签
*
* 在中间表示IR控制流指令 JUMPJUMP_IF_ZERO需要依赖标签来指定跳转位置
* 本类通过名字字符串唯一标识一个标签
*
* IRLabel 也是一种 IRValue因此可以作为指令的操作数
* IRLabel 表示中间表示IR系统中的跳转目标标签
* <p>
* 在控制流指令 JUMPJUMP_IF_ZEROJUMP_IF_NONZERO
* 标签用于标识跳转目的地确保程序执行流程的可控分支
* 本类通过唯一的字符串名称 name 来标识一个标签实例
* <p>
* IRLabel 同时实现 IRValue 接口可以直接作为操作数传递给 IRInstruction
*/
public record IRLabel(String name) implements IRValue {
/**
* 将标签转换为字符串形式
* 打印时在标签名后添加冒号例如 "L1:"
* 将标签转换为字符串表示用于 IR 打印和调试
* 格式为name:例如 "L1:"
*
* @return 标签字符串表示
* @return 带冒号的标签字符串
*/
@Override
public String toString() {

View File

@ -3,23 +3,25 @@ package org.jcnc.snow.compiler.ir.value;
import org.jcnc.snow.compiler.ir.core.IRValue;
/**
* IRVirtualRegister 表示一个 SSA静态单赋值虚拟寄存器
* <p>
* 在中间表示IR每个中间值都存储在一个虚拟寄存器中
* IRVirtualRegister 表示一个静态单赋值SSA形式的虚拟寄存器
* <p>
* 在中间表示IR系统中每个中间计算结果都分配到一个唯一的虚拟寄存器
* 特点
* - 每个寄存器都有唯一的 id通常由 IRBuilder 自动分配
* - 遵循 SSA 形式即每个寄存器只被赋值一次
* <p>
* IRVirtualRegister 也是一种 IRValue可以作为指令的操作数
* <ul>
* <li>每个寄存器都有唯一的 id IRFunction.newRegister() 自动生成</li>
* <li>遵循 SSA 形式每个寄存器仅在创建时被赋值一次</li>
* </ul>
*
* IRVirtualRegister 同时实现 IRValue 接口可作为 IRInstruction 的操作数
*
* @param id 寄存器的唯一编号
*/
public record IRVirtualRegister(int id) implements IRValue {
/**
* 将虚拟寄存器转换为字符串形式
* 通常以 % 开头例如 "%0""%1"
* 将虚拟寄存器转换为字符串表示格式为 "%<id>"便于打印和调试
*
* @return 寄存器的字符串表示
* @return 带有百分号前缀的寄存器编号字符串
*/
@Override
public String toString() {