增加注释
This commit is contained in:
parent
c0d47ae3ef
commit
2b8f648e54
@ -6,93 +6,139 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An intermediate‑representation function (IRFunction).
|
||||
*
|
||||
* <p>For every source‑level function we build one IRFunction that records:</p>
|
||||
* <ul>
|
||||
* <li>the function’s name,</li>
|
||||
* <li>a list of IR instructions (the <em>body</em>),</li>
|
||||
* <li>a list of <strong>formal parameters</strong> (in declaration order),</li>
|
||||
* <li>a counter that hands out unique register numbers.</li>
|
||||
* </ul>
|
||||
* 表示单个函数的中间表示(IR)。
|
||||
* <p>
|
||||
* IRFunction 跟踪代码生成和优化所需的所有信息,
|
||||
* 包括函数标识符、IR 指令序列、
|
||||
* 声明参数列表以及生成唯一虚拟寄存器的机制。
|
||||
* </p>
|
||||
*/
|
||||
public class IRFunction {
|
||||
|
||||
/* ---------- basic info ---------- */
|
||||
|
||||
/** function name */
|
||||
/**
|
||||
* 函数名,对应源级函数的标识。
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/** linear list of IR instructions */
|
||||
/**
|
||||
* IR 指令列表,组成函数体。
|
||||
*/
|
||||
private final List<IRInstruction> body = new ArrayList<>();
|
||||
|
||||
/* ---------- virtual‑register management ---------- */
|
||||
|
||||
/** running counter for new virtual registers */
|
||||
/**
|
||||
* 用于生成新的虚拟寄存器编号的计数器。
|
||||
*/
|
||||
private int regCounter = 0;
|
||||
|
||||
/** list of formal‑parameter registers in declaration order */
|
||||
/**
|
||||
* 正式参数所对应的虚拟寄存器列表,按声明顺序排列。
|
||||
*/
|
||||
private final List<IRVirtualRegister> parameters = new ArrayList<>();
|
||||
|
||||
/* ---------- construction ---------- */
|
||||
|
||||
/**
|
||||
* 构造一个具有指定名称的 IRFunction 实例。
|
||||
*
|
||||
* @param name 要关联的函数名称
|
||||
*/
|
||||
public IRFunction(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/* ---------- register helpers ---------- */
|
||||
|
||||
/** Allocates and returns a brand‑new virtual register. */
|
||||
/**
|
||||
* 分配一个新的虚拟寄存器。
|
||||
* 每次调用会生成一个带有唯一编号的 IRVirtualRegister。
|
||||
*
|
||||
* @return 新分配的虚拟寄存器
|
||||
*/
|
||||
public IRVirtualRegister newRegister() {
|
||||
return new IRVirtualRegister(regCounter++);
|
||||
}
|
||||
|
||||
/* ---------- parameter helpers ---------- */
|
||||
|
||||
/**
|
||||
* Adds a virtual register to the formal‑parameter list.
|
||||
* Call this once for each parameter <em>in declaration order</em>
|
||||
* when building the IR.
|
||||
* 将一个虚拟寄存器添加到函数的正式参数列表中。
|
||||
* <p>
|
||||
* 应按源函数签名中参数的声明顺序逐一调用此方法。
|
||||
* </p>
|
||||
*
|
||||
* @param vr 表示函数某个参数的虚拟寄存器
|
||||
*/
|
||||
public void addParameter(IRVirtualRegister vr) {
|
||||
parameters.add(vr);
|
||||
}
|
||||
|
||||
/** Returns the immutable list of formal parameters. */
|
||||
/**
|
||||
* 获取函数正式参数的只读列表。
|
||||
*
|
||||
* @return 按声明顺序排列的虚拟寄存器列表
|
||||
*/
|
||||
public List<IRVirtualRegister> parameters() {
|
||||
return parameters;
|
||||
return List.copyOf(parameters);
|
||||
}
|
||||
|
||||
/* ---------- body helpers ---------- */
|
||||
/**
|
||||
* 向函数体末尾追加一条 IR 指令。
|
||||
*
|
||||
* @param inst 要追加的 IRInstruction 实例
|
||||
*/
|
||||
public void add(IRInstruction inst) {
|
||||
body.add(inst);
|
||||
}
|
||||
|
||||
/** Appends an IR instruction to the function body. */
|
||||
public void add(IRInstruction inst) { body.add(inst); }
|
||||
/**
|
||||
* 获取函数体中所有指令的只读列表。
|
||||
*
|
||||
* @return 表示函数体的 IRInstruction 列表
|
||||
*/
|
||||
public List<IRInstruction> body() {
|
||||
return List.copyOf(body);
|
||||
}
|
||||
|
||||
/** Returns all instructions. */
|
||||
public List<IRInstruction> body() { return body; }
|
||||
/**
|
||||
* 获取函数的源级名称。
|
||||
*
|
||||
* @return 函数名称
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/* ---------- meta data ---------- */
|
||||
|
||||
public String name() { return name; }
|
||||
public int registerCount() { return regCounter; }
|
||||
|
||||
/* ---------- debugging ---------- */
|
||||
/**
|
||||
* 获取已分配的虚拟寄存器总数。
|
||||
*
|
||||
* @return 虚拟寄存器计数
|
||||
*/
|
||||
public int registerCount() {
|
||||
return regCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以IR代码表示,示例:
|
||||
* <pre>
|
||||
* func 名称(%0, %1, ...) {
|
||||
* 指令0
|
||||
* 指令1
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @return 函数的 IR 文本表示
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
// Print function header with explicit parameter list: func name(%0, %1) {
|
||||
StringBuilder sb = new StringBuilder("func ")
|
||||
.append(name)
|
||||
.append('(');
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
sb.append(parameters.get(i));
|
||||
if (i < parameters.size() - 1) sb.append(", ");
|
||||
if (i < parameters.size() - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(") {\n");
|
||||
|
||||
// Body instructions indented by two spaces
|
||||
body.forEach(i -> sb.append(" ").append(i).append('\n'));
|
||||
|
||||
return sb.append('}').toString();
|
||||
for (IRInstruction inst : body) {
|
||||
sb.append(" ").append(inst).append('\n');
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,40 +7,56 @@ import java.util.List;
|
||||
* IRInstruction —— 所有 IR(中间表示)指令的抽象基类。
|
||||
* <p>
|
||||
* 本类定义了编译器中间表示系统中所有指令的基本结构和行为。
|
||||
* 子类需实现具体的操作码(Opcode)和指令行为。
|
||||
* 这是采用“访问者模式”设计的一部分,便于对指令进行统一访问和操作。
|
||||
* 具体指令通过继承此类并实现各自的操作码(Opcode)和访问者方法,
|
||||
* 以支持统一的指令处理和访问模式。
|
||||
* </p>
|
||||
*/
|
||||
public abstract class IRInstruction {
|
||||
|
||||
/**
|
||||
* 获取该指令的操作码(Opcode)。
|
||||
* 每条具体指令子类都必须实现此方法以返回对应的操作码枚举。
|
||||
* <p>
|
||||
* 每个具体指令子类必须实现此方法,返回对应的 IROpCode 枚举值。
|
||||
* </p>
|
||||
*
|
||||
* @return 表示该指令类型的 IROpCode 实例
|
||||
* @return 表示指令类型的 IROpCode 实例
|
||||
*/
|
||||
public abstract IROpCode op();
|
||||
|
||||
/**
|
||||
* 获取该指令的目标虚拟寄存器(destination register)。
|
||||
* 默认为 null。部分子类(如赋值、运算类指令)应重写以返回具体目标寄存器。
|
||||
* 获取指令的目标虚拟寄存器(destination register)。
|
||||
* <p>
|
||||
* 默认实现返回 null;只有具有目标寄存器的指令(如赋值、算术运算)
|
||||
* 应重写此方法以返回相应的 IRVirtualRegister。
|
||||
* </p>
|
||||
*
|
||||
* @return 指令的目标虚拟寄存器,或为 null(若无目标寄存器)
|
||||
* @return 目标虚拟寄存器,若无目标寄存器则返回 null
|
||||
*/
|
||||
public IRVirtualRegister dest() { return null; }
|
||||
public IRVirtualRegister dest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该指令的操作数列表。
|
||||
* 默认为空列表。子类应重写以提供实际使用的操作数集合。
|
||||
* 获取指令的操作数列表。
|
||||
* <p>
|
||||
* 默认实现返回空列表;具体指令子类应根据需要重写此方法,
|
||||
* 提供所有参与运算或调用的 IRValue 操作数集合。
|
||||
* </p>
|
||||
*
|
||||
* @return 一个包含所有操作数(IRValue)的列表
|
||||
* @return 包含本指令所有操作数的列表
|
||||
*/
|
||||
public List<IRValue> operands() { return List.of(); }
|
||||
public List<IRValue> operands() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收一个 IRVisitor 实例,实现访问者模式的入口。
|
||||
* 子类必须实现此方法,以允许访问者根据具体类型进行相应处理。
|
||||
* 接受一个 IRVisitor 实例,实现访问者模式的入口。
|
||||
* <p>
|
||||
* 具体指令子类必须实现此方法,以便 IRVisitor 根据指令类型
|
||||
* 调用相应的访问逻辑。
|
||||
* </p>
|
||||
*
|
||||
* @param visitor 实现 IRVisitor 接口的访问者实例
|
||||
* @param visitor 实现 IRVisitor 接口的访问者对象
|
||||
*/
|
||||
public abstract void accept(IRVisitor visitor);
|
||||
}
|
||||
}
|
||||
@ -1,95 +1,79 @@
|
||||
package org.jcnc.snow.compiler.ir.core;
|
||||
|
||||
/**
|
||||
* IROpCode —— IR 层支持的操作码(Opcode)枚举类型。
|
||||
* {@code IROpCode} 枚举类型定义了中间表示(IR)层支持的全部操作码。
|
||||
* <p>
|
||||
* 本枚举类定义了中间表示层可用的所有基本指令类型,供 {@link IRInstruction} 使用。
|
||||
* 每个枚举值代表一种语义明确的 IR 操作,涵盖不同位宽的整数和浮点算术、逻辑、数据操作和控制流指令。
|
||||
* 可根据后续需求继续扩展。
|
||||
* 每个操作码代表一种低层次、语义明确的中间指令,用于构建目标函数的中间表示。
|
||||
* 这些操作涵盖了不同数据位宽的整数与浮点数算术运算、逻辑与比较操作、
|
||||
* 数据加载与存储指令、控制流指令(如跳转、条件跳转、标签)、
|
||||
* 以及函数调用与返回等功能。
|
||||
* <p>
|
||||
* 本枚举用于 {@link IRInstruction} 体系结构中,是 IR 指令识别和转换的核心部分,
|
||||
* </p>
|
||||
*/
|
||||
public enum IROpCode {
|
||||
|
||||
/* ───── 算术运算 (8位整数: byte) ───── */
|
||||
/** 8位整型加法 (byte): a = b + c */
|
||||
ADD_B8,
|
||||
/** 8位整型减法 */
|
||||
SUB_B8,
|
||||
/** 8位整型乘法 */
|
||||
MUL_B8,
|
||||
/** 8位整型除法 */
|
||||
DIV_B8,
|
||||
/** 8位整型取负 */
|
||||
NEG_B8,
|
||||
/* ───── 算术运算(8位整数:byte)───── */
|
||||
ADD_B8, // 8位整型加法:a = b + c
|
||||
SUB_B8, // 8位整型减法:a = b - c
|
||||
MUL_B8, // 8位整型乘法:a = b * c
|
||||
DIV_B8, // 8位整型除法:a = b / c
|
||||
NEG_B8, // 8位整型取负:a = -b
|
||||
|
||||
/* ───── 算术运算 (16位整数: short) ───── */
|
||||
/** 16位整型加法 (short) */
|
||||
ADD_S16,
|
||||
/** 16位整型减法 */
|
||||
SUB_S16,
|
||||
/** 16位整型乘法 */
|
||||
MUL_S16,
|
||||
/** 16位整型除法 */
|
||||
DIV_S16,
|
||||
/** 16位整型取负 */
|
||||
NEG_S16,
|
||||
/* ───── 算术运算(16位整数:short)───── */
|
||||
ADD_S16, // 16位整型加法
|
||||
SUB_S16, // 16位整型减法
|
||||
MUL_S16, // 16位整型乘法
|
||||
DIV_S16, // 16位整型除法
|
||||
NEG_S16, // 16位整型取负
|
||||
|
||||
/* ───── 算术运算 (32位整数: int) ───── */
|
||||
/** 32位整型加法 (int) */
|
||||
ADD_I32,
|
||||
/** 32位整型减法 */
|
||||
SUB_I32,
|
||||
/** 32位整型乘法 */
|
||||
MUL_I32,
|
||||
/** 32位整型除法 */
|
||||
DIV_I32,
|
||||
/** 32位整型取负 */
|
||||
NEG_I32,
|
||||
/* ───── 算术运算(32位整数:int)───── */
|
||||
ADD_I32, // 32位整型加法
|
||||
SUB_I32, // 32位整型减法
|
||||
MUL_I32, // 32位整型乘法
|
||||
DIV_I32, // 32位整型除法
|
||||
NEG_I32, // 32位整型取负
|
||||
|
||||
/* ───── 算术运算 (64位整数: long) ───── */
|
||||
/** 64位整型加法 (long) */
|
||||
ADD_L64,
|
||||
/** 64位整型减法 */
|
||||
SUB_L64,
|
||||
/** 64位整型乘法 */
|
||||
MUL_L64,
|
||||
/** 64位整型除法 */
|
||||
DIV_L64,
|
||||
/** 64位整型取负 */
|
||||
NEG_L64,
|
||||
/* ───── 算术运算(64位整数:long)───── */
|
||||
ADD_L64, // 64位整型加法
|
||||
SUB_L64, // 64位整型减法
|
||||
MUL_L64, // 64位整型乘法
|
||||
DIV_L64, // 64位整型除法
|
||||
NEG_L64, // 64位整型取负
|
||||
|
||||
/* ───── 算术运算 (单精度浮点: float) ───── */
|
||||
ADD_F32,
|
||||
SUB_F32,
|
||||
MUL_F32,
|
||||
DIV_F32,
|
||||
NEG_F32,
|
||||
/* ───── 算术运算(32位浮点数:float)───── */
|
||||
ADD_F32, // 32位浮点加法
|
||||
SUB_F32, // 32位浮点减法
|
||||
MUL_F32, // 32位浮点乘法
|
||||
DIV_F32, // 32位浮点除法
|
||||
NEG_F32, // 32位浮点取负
|
||||
|
||||
/* ───── 算术运算 (双精度浮点: double) ───── */
|
||||
ADD_D64,
|
||||
SUB_D64,
|
||||
MUL_D64,
|
||||
DIV_D64,
|
||||
NEG_D64,
|
||||
/* ───── 算术运算(64位浮点数:double)───── */
|
||||
ADD_D64, // 64位浮点加法
|
||||
SUB_D64, // 64位浮点减法
|
||||
MUL_D64, // 64位浮点乘法
|
||||
DIV_D64, // 64位浮点除法
|
||||
NEG_D64, // 64位浮点取负
|
||||
|
||||
/* ───── 逻辑/比较运算 ───── */
|
||||
CMP_EQ,
|
||||
CMP_NE,
|
||||
CMP_LT,
|
||||
CMP_GT,
|
||||
CMP_LE,
|
||||
CMP_GE,
|
||||
/* ───── 逻辑与比较运算指令 ───── */
|
||||
CMP_EQ, // 相等比较:a == b
|
||||
CMP_NE, // 不等比较:a != b
|
||||
CMP_LT, // 小于比较:a < b
|
||||
CMP_GT, // 大于比较:a > b
|
||||
CMP_LE, // 小于等于:a <= b
|
||||
CMP_GE, // 大于等于:a >= b
|
||||
|
||||
/* ───── 数据搬运 ───── */
|
||||
LOAD,
|
||||
STORE,
|
||||
CONST,
|
||||
/* ───── 数据访问与常量操作 ───── */
|
||||
LOAD, // 从内存加载数据至寄存器
|
||||
STORE, // 将寄存器数据写回内存
|
||||
CONST, // 将常量写入目标寄存器
|
||||
|
||||
/* ───── 控制流 ───── */
|
||||
JUMP,
|
||||
JUMP_IF_ZERO,
|
||||
LABEL,
|
||||
/* ───── 控制流指令 ───── */
|
||||
JUMP, // 无条件跳转至标签
|
||||
JUMP_IF_ZERO, // 若寄存器为零则跳转
|
||||
LABEL, // 标签定义
|
||||
|
||||
/* ───── 函数调用相关 ───── */
|
||||
CALL,
|
||||
RET
|
||||
/* ───── 函数调用与返回 ───── */
|
||||
CALL, // 函数调用
|
||||
RET // 函数返回
|
||||
}
|
||||
@ -5,20 +5,25 @@ import org.jcnc.snow.compiler.ir.instruction.IRJumpInstruction;
|
||||
import org.jcnc.snow.compiler.ir.instruction.IRReturnInstruction;
|
||||
|
||||
/**
|
||||
* IRPrinter —— 一个示例访问者(Visitor),用于打印 IR 指令的信息。
|
||||
* {@code IRPrinter} 是一个用于打印 IR 指令的访问者实现。
|
||||
* <p>
|
||||
* 本类实现了 IRVisitor 接口,用于演示如何使用访问者模式处理 IRInstruction 子类。
|
||||
* 每个 visit 方法负责处理特定类型的 IR 指令。此实现以控制台输出(System.out)形式展示指令内容。
|
||||
* 本类实现 {@link IRVisitor} 接口,通过覆盖各类指令的访问方法,
|
||||
* 提供对不同类型 IR 指令的格式化输出,通常用于调试或测试。
|
||||
* 默认行为是在控制台(System.out)输出指令的基本信息。
|
||||
* </p>
|
||||
* <p>
|
||||
* 子类可扩展该类以进行更复杂的打印或格式化,或添加对更多 IR 指令类型的支持。
|
||||
* 可通过继承该类进一步扩展对更多指令类型的支持,或重写输出格式以适配不同的前端/后端需求。
|
||||
* </p>
|
||||
*/
|
||||
public abstract class IRPrinter implements IRVisitor {
|
||||
|
||||
/**
|
||||
* 处理 IRAddInstruction 类型的指令。
|
||||
* 打印加法指令的基本信息。
|
||||
* 访问 {@link IRAddInstruction} 加法指令。
|
||||
* <p>
|
||||
* 默认输出形式为 "Add: <inst>",其中 <inst> 为指令对象的字符串表示。
|
||||
* </p>
|
||||
*
|
||||
* @param inst 被访问的加法指令
|
||||
* @param inst 加法 IR 指令实例
|
||||
*/
|
||||
@Override
|
||||
public void visit(IRAddInstruction inst) {
|
||||
@ -26,10 +31,12 @@ public abstract class IRPrinter implements IRVisitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 IRJumpInstruction 类型的指令。
|
||||
* 打印跳转指令的基本信息。
|
||||
* 访问 {@link IRJumpInstruction} 跳转指令。
|
||||
* <p>
|
||||
* 默认输出形式为 "Jump: <inst>"。
|
||||
* </p>
|
||||
*
|
||||
* @param inst 被访问的跳转指令
|
||||
* @param inst 跳转 IR 指令实例
|
||||
*/
|
||||
@Override
|
||||
public void visit(IRJumpInstruction inst) {
|
||||
@ -37,14 +44,16 @@ public abstract class IRPrinter implements IRVisitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 IRReturnInstruction 类型的指令。
|
||||
* 打印返回指令的基本信息。
|
||||
* 访问 {@link IRReturnInstruction} 返回指令。
|
||||
* <p>
|
||||
* 默认输出形式为 "Return: <inst>"。
|
||||
* </p>
|
||||
*
|
||||
* @param inst 被访问的返回指令
|
||||
* @param inst 返回 IR 指令实例
|
||||
*/
|
||||
@Override
|
||||
public void visit(IRReturnInstruction inst) {
|
||||
System.out.println("Return: " + inst);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -5,42 +5,51 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IRProgram 表示一份完整的中间表示(IR)程序。
|
||||
* {@code IRProgram} 表示一份完整的中间表示(Intermediate Representation, IR)程序。
|
||||
* <p>
|
||||
* 本类作为编译器后端的主要数据结构之一,承载着所有 IRFunction 的集合。
|
||||
* 每个函数封装一段 IR 指令序列,整体表示源代码编译后的结构化中间结果。
|
||||
* 通常用于代码生成、优化、分析等阶段。
|
||||
* 它作为编译器后端处理阶段的核心结构,承载所有由源代码翻译得到的 {@link IRFunction} 实例,
|
||||
* 形成整体性的中间表示单元,便于进行后续的优化、目标代码生成或静态分析。
|
||||
* </p>
|
||||
*/
|
||||
public final class IRProgram {
|
||||
|
||||
/** 存储程序中所有函数的列表 */
|
||||
/**
|
||||
* 存储程序中所有函数的有序集合。
|
||||
*/
|
||||
private final List<IRFunction> functions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 向 IRProgram 中添加一个函数。
|
||||
* 将一个 {@link IRFunction} 添加到程序中。
|
||||
* <p>
|
||||
* 函数会按添加顺序保留在内部集合中。
|
||||
* </p>
|
||||
*
|
||||
* @param irFunction 要添加的 IRFunction 对象
|
||||
* @param irFunction 要加入的 IR 函数对象
|
||||
*/
|
||||
public void add(IRFunction irFunction) {
|
||||
functions.add(irFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取程序中所有函数的不可变视图。
|
||||
* 获取程序中全部函数的只读视图。
|
||||
* <p>
|
||||
* 返回的列表不能被外部修改,确保 IRProgram 的封装性和安全性。
|
||||
* 外部调用者无法通过返回的列表修改函数集合,从而确保封装性与结构完整性。
|
||||
* </p>
|
||||
*
|
||||
* @return 包含所有 IRFunction 的只读列表
|
||||
* @return 不可变的函数列表
|
||||
*/
|
||||
public List<IRFunction> functions() {
|
||||
return Collections.unmodifiableList(functions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将整个 IRProgram 转换为字符串表示,方便打印或调试。
|
||||
* 每个函数调用其 toString 方法,占据单独一行。
|
||||
* 返回该 IR 程序的字符串形式。
|
||||
* <p>
|
||||
* 每个函数按其 {@code toString()} 表示输出,换行分隔。
|
||||
* 通常用于调试与日志输出。
|
||||
* </p>
|
||||
*
|
||||
* @return 程序的字符串表示
|
||||
* @return 表示整个 IR 程序的格式化字符串
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@ -5,24 +5,23 @@ import org.jcnc.snow.compiler.ir.value.IRLabel;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
/**
|
||||
* IRValue —— 表示在中间表示(IR)系统中可作为指令操作数的基本单位。
|
||||
* {@code IRValue} 表示 IR 指令系统中可被操作的值类型。
|
||||
* <p>
|
||||
* 本接口定义了 IR 指令可接受的值类型,是一个“值对象”的抽象。
|
||||
* 所有实现 IRInstruction 的类在定义操作数时,其元素类型均为 IRValue。
|
||||
* <p>
|
||||
* 典型用途包括操作数、跳转目标、返回值、函数参数等。
|
||||
* <p>
|
||||
* 支持的具体子类型包括:
|
||||
* 它定义了所有 IR 指令在使用操作数、参数、结果或跳转目标时的统一抽象。
|
||||
* 实现该接口的类型可以作为 {@link IRInstruction} 中的操作数出现。
|
||||
* </p>
|
||||
*
|
||||
* <p>当前支持的 IR 值类型包括:</p>
|
||||
* <ul>
|
||||
* <li>{@link IRVirtualRegister} —— 虚拟寄存器,用于存储计算结果或中间值</li>
|
||||
* <li>{@link IRConstant} —— 常量值,如字面整型常数等</li>
|
||||
* <li>{@link IRLabel} —— 跳转标签,用于表示代码中的控制流目标</li>
|
||||
* <li>{@link IRVirtualRegister}:虚拟寄存器,表示计算结果或中间变量</li>
|
||||
* <li>{@link IRConstant}:常量值,表示不可变的字面量或数值</li>
|
||||
* <li>{@link IRLabel}:标签,表示跳转指令的目标地址</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* 本接口为 <code>sealed interface</code>,仅允许指定的子类型实现它。
|
||||
* 这保证了类型系统的封闭性,便于编译器在处理 IRValue 时进行穷尽性检查,
|
||||
* 增强类型安全与维护性。
|
||||
* 该接口声明为 {@code sealed interface},限制只能被上述类型实现。
|
||||
* 这种设计允许编译器对 {@code IRValue} 的使用进行静态穷尽性检查,
|
||||
* 有助于提升类型安全性与维护性。
|
||||
* </p>
|
||||
*/
|
||||
public sealed interface IRValue
|
||||
|
||||
@ -3,57 +3,78 @@ package org.jcnc.snow.compiler.ir.core;
|
||||
import org.jcnc.snow.compiler.ir.instruction.*;
|
||||
|
||||
/**
|
||||
* IRVisitor —— 访问者接口,用于对不同类型的 IR 指令进行操作。
|
||||
* {@code IRVisitor} 是中间表示(IR)指令体系的访问者接口。
|
||||
* <p>
|
||||
* 本接口定义了“访问者模式”的核心机制。通过将每种 IRInstruction 子类对应为一个独立的 visit 方法,
|
||||
* 可实现类型安全的指令操作逻辑分离,例如打印、优化、代码生成等。
|
||||
* <p>
|
||||
* 使用场景包括:
|
||||
* 它定义了访问者模式的核心机制,通过对每种 {@link IRInstruction} 子类
|
||||
* 提供独立的 {@code visit} 方法,实现对指令的分发与处理。
|
||||
* 不同的访问者实现可用于执行不同任务,例如:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>IRPrinter:打印每条 IR 指令的内容</li>
|
||||
* <li>IROptimizer:对 IR 进行模式匹配和重写优化</li>
|
||||
* <li>IRCodeGenerator:将 IR 转换为目标平台指令</li>
|
||||
* <li>{@code IRPrinter}:打印指令内容</li>
|
||||
* <li>{@code IROptimizer}:分析与重写 IR 以优化性能</li>
|
||||
* <li>{@code IRCodeGenerator}:生成平台相关的机器码或汇编代码</li>
|
||||
* </ul>
|
||||
*
|
||||
* 每添加一种新的指令子类,通常也需在本接口中添加对应的 visit 方法,以保持访问能力的完备。
|
||||
* <p>
|
||||
* 每当添加新的 {@code IRInstruction} 子类,应同步扩展该接口,
|
||||
* 以确保访问行为的一致性与完整性。
|
||||
* </p>
|
||||
*/
|
||||
public interface IRVisitor {
|
||||
|
||||
/**
|
||||
* 访问加法指令(简化形式)。
|
||||
* 访问加法指令(示例实现)。
|
||||
*
|
||||
* @param inst 加法指令实例
|
||||
*/
|
||||
void visit(IRAddInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问跳转指令。
|
||||
*
|
||||
* @param inst 跳转指令实例
|
||||
*/
|
||||
void visit(IRJumpInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问返回指令(简化形式)。
|
||||
* 访问返回指令(无返回值)。
|
||||
*
|
||||
* @param inst 返回指令实例
|
||||
*/
|
||||
void visit(IRReturnInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问通用的二元运算指令,如 ADD_I32、SUB_I32 等。
|
||||
* 访问二元运算指令(如加减乘除等)。
|
||||
*
|
||||
* @param inst 二元运算 IR 指令实例
|
||||
*/
|
||||
void visit(BinaryOperationInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问加载常量的指令(将常量加载到虚拟寄存器)。
|
||||
* 访问加载常量的指令。
|
||||
*
|
||||
* @param inst 常量加载指令实例
|
||||
*/
|
||||
void visit(LoadConstInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问更通用的返回指令(可带返回值)。
|
||||
* 访问返回指令(支持返回值)。
|
||||
*
|
||||
* @param inst 通用返回指令实例
|
||||
*/
|
||||
void visit(ReturnInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问一元运算指令,如 NEG_I32。
|
||||
* 访问一元运算指令(如取负等)。
|
||||
*
|
||||
* @param inst 一元运算指令实例
|
||||
*/
|
||||
void visit(UnaryOperationInstruction inst);
|
||||
|
||||
/**
|
||||
* 访问函数调用指令。
|
||||
*
|
||||
* @param instruction 函数调用指令实例
|
||||
*/
|
||||
void visit(CallInstruction instruction);
|
||||
|
||||
}
|
||||
|
||||
@ -6,28 +6,41 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TokenScanner 接口:定义所有词法扫描器的通用规范。
|
||||
* 每种 Token 类型(如标识符、数字、字符串等)都应该实现此接口。
|
||||
* {@code TokenScanner} 接口定义了所有词法扫描器的统一行为规范。
|
||||
* <p>
|
||||
* 编译器前端中的词法分析阶段将源代码字符流解析为语义上有意义的记号(token),
|
||||
* 每种类型的记号(如标识符、数字、字符串、符号等)应有对应的 {@code TokenScanner} 实现类。
|
||||
* 词法分析器根据当前输入字符判断并分派给能处理该字符的扫描器进行处理。
|
||||
* </p>
|
||||
* <p>
|
||||
* 实现类通常会结合 {@link LexerContext} 提供的流访问与状态接口,
|
||||
* 完成一个完整 Token 的提取,并将其添加到结果集中。
|
||||
* </p>
|
||||
*/
|
||||
public interface TokenScanner {
|
||||
|
||||
/**
|
||||
* 判断当前字符是否可以由该扫描器处理。
|
||||
* 词法分析器会遍历所有已注册的 TokenScanner,
|
||||
* 用此方法来找到合适的处理器。
|
||||
* <p>
|
||||
* 词法分析器会按顺序查询已注册的 {@code TokenScanner} 实例,
|
||||
* 使用该方法决定当前字符是否可由某个扫描器识别与处理。
|
||||
* </p>
|
||||
*
|
||||
* @param c 当前字符
|
||||
* @param ctx 词法分析上下文,提供字符流访问和辅助方法
|
||||
* @return 如果该扫描器能处理当前字符,则返回 true
|
||||
* @param c 当前读取的字符
|
||||
* @param ctx 当前词法分析上下文,提供字符流和辅助状态
|
||||
* @return 若该扫描器可处理当前字符,则返回 {@code true},否则返回 {@code false}
|
||||
*/
|
||||
boolean canHandle(char c, LexerContext ctx);
|
||||
|
||||
/**
|
||||
* 处理当前字符起始的 token,并将生成的 Token 添加到列表中。
|
||||
* 实现中通常会读取多个字符,直到确定该 token 的结束。
|
||||
* 处理以当前字符为起始的 token,并将扫描结果添加至 tokens 列表中。
|
||||
* <p>
|
||||
* 扫描器需消费一定数量的字符,构建合法的 {@link Token} 实例,
|
||||
* 并调用 {@code tokens.add(...)} 添加至结果集中。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 词法分析上下文,用于读取字符和获取位置信息
|
||||
* @param tokens Token 列表,扫描出的 token 应添加到该列表中
|
||||
* @param ctx 当前词法上下文
|
||||
* @param tokens 存储扫描结果的 token 列表
|
||||
*/
|
||||
void handle(LexerContext ctx, List<Token> tokens);
|
||||
}
|
||||
}
|
||||
@ -3,31 +3,35 @@ package org.jcnc.snow.compiler.lexer.core;
|
||||
import org.jcnc.snow.compiler.lexer.base.TokenScanner;
|
||||
|
||||
/**
|
||||
* {@code LexerContext} 是词法分析中的状态管理器,负责追踪当前字符位置、
|
||||
* 行号、列号,并提供字符读取、匹配等功能。
|
||||
* {@code LexerContext} 是词法分析阶段的上下文状态管理器。
|
||||
* <p>
|
||||
* 它是 {@link LexerEngine} 和 {@link TokenScanner}
|
||||
* 之间共享的上下文对象,用于读取字符并记录位置信息。
|
||||
* 该类提供对源代码字符流的读取访问,追踪当前行号与列号,
|
||||
* 并支持字符匹配、回看与指针推进等操作,是 {@link TokenScanner} 实现进行词法识别的重要支撑工具。
|
||||
* </p>
|
||||
* <p>
|
||||
* 所有源代码输入在构造时统一将 Windows 风格的换行符(\r\n)转换为 Unix 风格(\n),
|
||||
* 保证换行行为一致性。
|
||||
* </p>
|
||||
*/
|
||||
public class LexerContext {
|
||||
/** 源代码文本,换行符统一替换为 \n */
|
||||
|
||||
/** 源代码字符串,换行符已标准化为 \n */
|
||||
private final String source;
|
||||
|
||||
/** 当前在源代码中的偏移位置 */
|
||||
/** 当前扫描位置(从 0 开始的偏移) */
|
||||
private int pos = 0;
|
||||
|
||||
/** 当前行号,从 1 开始计数 */
|
||||
/** 当前行号,从 1 开始 */
|
||||
private int line = 1;
|
||||
|
||||
/** 当前列号,从 1 开始计数 */
|
||||
/** 当前列号,从 1 开始 */
|
||||
private int col = 1;
|
||||
|
||||
/** 上一个字符的列号(用于生成准确的 Token 位置信息) */
|
||||
/** 上一个字符对应的列号(用于位置精确记录) */
|
||||
private int lastCol = 1;
|
||||
|
||||
/**
|
||||
* 创建一个新的 {@code LexerContext} 实例,并初始化源代码内容。
|
||||
* 所有 \r\n(Windows 换行)会被标准化为 \n。
|
||||
* 构造一个新的 {@code LexerContext} 实例,并标准化换行符。
|
||||
*
|
||||
* @param source 原始源代码字符串
|
||||
*/
|
||||
@ -36,19 +40,18 @@ public class LexerContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已到达源代码末尾。
|
||||
* 判断是否已读取到源代码末尾。
|
||||
*
|
||||
* @return 如果读取完毕返回 true,否则返回 false
|
||||
* @return 若已结束,返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
public boolean isAtEnd() {
|
||||
return pos >= source.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取当前字符,并将指针移动到下一个字符位置。
|
||||
* 同时更新行号与列号。
|
||||
* 消费当前字符并前进一个位置,自动更新行列信息。
|
||||
*
|
||||
* @return 当前字符,若已结束返回 '\0'
|
||||
* @return 当前字符,若已结束则返回空字符('\0')
|
||||
*/
|
||||
public char advance() {
|
||||
if (isAtEnd()) return '\0';
|
||||
@ -64,28 +67,28 @@ public class LexerContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看当前字符,但不会前进指针。
|
||||
* 查看当前位置的字符,但不前进。
|
||||
*
|
||||
* @return 当前字符,若已结束返回 '\0'
|
||||
* @return 当前字符,若结束则返回空字符
|
||||
*/
|
||||
public char peek() {
|
||||
return isAtEnd() ? '\0' : source.charAt(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看下一个字符,但不会前进指针。
|
||||
* 查看下一个字符,但不改变位置。
|
||||
*
|
||||
* @return 下一个字符,若已结束返回 '\0'
|
||||
* @return 下一个字符,若结束则返回空字符
|
||||
*/
|
||||
public char peekNext() {
|
||||
return pos + 1 >= source.length() ? '\0' : source.charAt(pos + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果当前字符是指定字符,则前进指针并返回 true。
|
||||
* 若当前字符与期望字符相同,则前进并返回 {@code true},否则不动并返回 {@code false}。
|
||||
*
|
||||
* @param expected 要匹配的字符
|
||||
* @return 是否成功匹配并前进
|
||||
* @param expected 期待匹配的字符
|
||||
* @return 是否匹配成功并消费
|
||||
*/
|
||||
public boolean match(char expected) {
|
||||
if (isAtEnd() || source.charAt(pos) != expected) return false;
|
||||
@ -94,18 +97,18 @@ public class LexerContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前行号。
|
||||
* 获取当前位置的行号。
|
||||
*
|
||||
* @return 当前行,从 1 开始计数
|
||||
* @return 当前行号(从 1 开始)
|
||||
*/
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前列号。
|
||||
* 获取当前位置的列号。
|
||||
*
|
||||
* @return 当前列,从 1 开始计数
|
||||
* @return 当前列号(从 1 开始)
|
||||
*/
|
||||
public int getCol() {
|
||||
return col;
|
||||
@ -113,9 +116,8 @@ public class LexerContext {
|
||||
|
||||
/**
|
||||
* 获取上一个字符所在的列号。
|
||||
* 主要用于生成换行符等 Token 的精确列号。
|
||||
*
|
||||
* @return 上一个字符的列号
|
||||
* @return 上一个字符对应的列位置
|
||||
*/
|
||||
public int getLastCol() {
|
||||
return lastCol;
|
||||
|
||||
@ -8,55 +8,58 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 词法分析器(LexerEngine),用于将源代码字符串转换为一系列语法标记(Token)。
|
||||
* {@code LexerEngine} 是编译器前端的词法分析器核心实现。
|
||||
* <p>
|
||||
* 它使用多个 {@link TokenScanner} 实现类处理不同类型的词法单元(数字、标识符、运算符、注释等),
|
||||
* 并追踪位置信息(行号、列号)以便后续语法分析或错误报告。
|
||||
* 它负责将源代码字符串按顺序扫描并转换为一系列 {@link Token} 实例,
|
||||
* 每个 Token 表示语法上可识别的最小单位(如标识符、关键字、常量、运算符等)。
|
||||
* <p>
|
||||
* 分析流程通过注册多个 {@link TokenScanner} 扫描器实现类型识别,
|
||||
* 并由 {@link LexerContext} 提供字符流与位置信息支持。
|
||||
* </p>
|
||||
*/
|
||||
public class LexerEngine {
|
||||
/** 所有已识别的 Token(含 EOF) */
|
||||
|
||||
/** 扫描生成的 Token 序列(含 EOF) */
|
||||
private final List<Token> tokens = new ArrayList<>();
|
||||
|
||||
/** 扫描上下文,记录当前扫描位置、行列号等 */
|
||||
/** 词法上下文,提供字符流读取与位置信息 */
|
||||
private final LexerContext context;
|
||||
|
||||
/** Token 扫描器列表,按优先级顺序处理不同类型的 Token */
|
||||
/** Token 扫描器集合,按优先级顺序组织,用于识别不同类别的 Token */
|
||||
private final List<TokenScanner> scanners;
|
||||
|
||||
/**
|
||||
* 创建并初始化 LexerEngine,构建扫描器列表并立即开始扫描源代码。
|
||||
* 构造一个 {@code LexerEngine} 实例,并初始化内部扫描器与上下文。
|
||||
* 调用构造函数时即开始词法扫描,生成完整 Token 序列。
|
||||
*
|
||||
* @param source 输入的源代码字符串
|
||||
* @param source 原始源代码文本
|
||||
*/
|
||||
public LexerEngine(String source) {
|
||||
this.context = new LexerContext(source);
|
||||
|
||||
// 注册所有 Token 扫描器(按优先级顺序)
|
||||
// 按优先级注册所有支持的 Token 扫描器
|
||||
this.scanners = List.of(
|
||||
new WhitespaceTokenScanner(), // 跳过空格、制表符等
|
||||
new NewlineTokenScanner(), // 处理换行符,生成 NEWLINE Token
|
||||
new CommentTokenScanner(), // 处理行注释与块注释
|
||||
new NumberTokenScanner(), // 处理数字字面量(整数、小数)
|
||||
new IdentifierTokenScanner(), // 处理标识符及关键字
|
||||
new StringTokenScanner(), // 处理字符串字面量
|
||||
new OperatorTokenScanner(), // 处理运算符(==、!=、&& 等)
|
||||
new SymbolTokenScanner(), // 处理符号(括号、逗号等)
|
||||
new UnknownTokenScanner() // 默认处理器,捕捉未知字符
|
||||
new CommentTokenScanner(), // 处理单行/多行注释
|
||||
new NumberTokenScanner(), // 识别整数与浮点数
|
||||
new IdentifierTokenScanner(), // 识别标识符与关键字
|
||||
new StringTokenScanner(), // 处理字符串常量
|
||||
new OperatorTokenScanner(), // 处理运算符
|
||||
new SymbolTokenScanner(), // 处理括号、分号等符号
|
||||
new UnknownTokenScanner() // 捕捉无法识别的字符
|
||||
);
|
||||
|
||||
scanAllTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描整个源代码,识别并构建 Token 序列。
|
||||
* 执行主扫描流程,将整个源代码转换为 Token 序列。
|
||||
* <p>
|
||||
* 每次迭代:
|
||||
* <ul>
|
||||
* <li>获取当前位置字符</li>
|
||||
* <li>尝试交由扫描器处理</li>
|
||||
* <li>若无扫描器可处理,则标记为 UNKNOWN</li>
|
||||
* </ul>
|
||||
* 最后追加 EOF(文件结束)Token。
|
||||
* 每次扫描尝试依次使用各个 {@link TokenScanner},直到某一扫描器能够处理当前字符。
|
||||
* 若无匹配扫描器,交由 {@code UnknownTokenScanner} 处理。
|
||||
* 扫描结束后自动附加一个 EOF(文件结束)Token。
|
||||
* </p>
|
||||
*/
|
||||
private void scanAllTokens() {
|
||||
while (!context.isAtEnd()) {
|
||||
@ -73,13 +76,12 @@ public class LexerEngine {
|
||||
tokens.add(Token.eof(context.getLine()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回所有扫描到的 Token(包含 EOF)。
|
||||
* 返回词法分析生成的所有 Token(含 EOF)。
|
||||
*
|
||||
* @return Token 的不可变副本列表
|
||||
*/
|
||||
public List<Token> getAllTokens() {
|
||||
return List.copyOf(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,12 +8,22 @@ import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 抽象 TokenScanner 实现,封装常用的扫描行为和模板方法。
|
||||
* 子类只需实现 {@code scanToken} 方法,关注 token 的核心逻辑,
|
||||
* 行列追踪和 token 添加交由此类统一处理。
|
||||
* {@code AbstractTokenScanner} 是 {@link TokenScanner} 的抽象实现,
|
||||
* 封装了常用的扫描行为与模板逻辑,简化子类的实现负担。
|
||||
* <p>
|
||||
* 子类只需实现 {@link #scanToken(LexerContext, int, int)} 方法,
|
||||
* 专注于处理具体的 Token 构造逻辑,
|
||||
* 而位置信息提取、Token 添加等通用操作由本类统一完成。
|
||||
* </p>
|
||||
*/
|
||||
public abstract class AbstractTokenScanner implements TokenScanner {
|
||||
|
||||
/**
|
||||
* 处理当前字符起始的 Token,附带行列信息并加入 Token 列表。
|
||||
*
|
||||
* @param ctx 当前词法分析上下文
|
||||
* @param tokens 存储扫描结果的 Token 列表
|
||||
*/
|
||||
@Override
|
||||
public void handle(LexerContext ctx, List<Token> tokens) {
|
||||
int line = ctx.getLine();
|
||||
@ -25,21 +35,25 @@ public abstract class AbstractTokenScanner implements TokenScanner {
|
||||
}
|
||||
|
||||
/**
|
||||
* 子类实现的具体扫描逻辑。
|
||||
* 抽象方法:由子类实现具体的扫描逻辑。
|
||||
* <p>
|
||||
* 实现应消费一定字符并根据规则构造 Token。
|
||||
* 若无需生成 Token,可返回 null。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 扫描上下文
|
||||
* @param ctx 当前扫描上下文
|
||||
* @param line 当前行号
|
||||
* @param col 当前列号
|
||||
* @return 构建的 Token,如果为 null 表示无需添加
|
||||
* @return 构造的 Token 或 null
|
||||
*/
|
||||
protected abstract Token scanToken(LexerContext ctx, int line, int col);
|
||||
|
||||
/**
|
||||
* 连续读取字符直到不满足条件。
|
||||
* 工具方法:连续读取字符直到遇到不满足指定条件的字符。
|
||||
*
|
||||
* @param ctx 扫描上下文
|
||||
* @param predicate 字符判断条件
|
||||
* @return 匹配的字符串
|
||||
* @param ctx 当前词法上下文
|
||||
* @param predicate 字符匹配条件
|
||||
* @return 满足条件的字符组成的字符串
|
||||
*/
|
||||
protected String readWhile(LexerContext ctx, Predicate<Character> predicate) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@ -48,4 +62,4 @@ public abstract class AbstractTokenScanner implements TokenScanner {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user