From f820b9e9c0ee0030144a9035e4ef3b27881ff569 Mon Sep 17 00:00:00 2001
From: Luke
{@code
* loop:
- * initializer:
- * declare i:int = 0
- * condition:
- * i < 10
- * update:
- * i = i + 1
- * body:
- * print(i)
- * end body
+ * init:
+ * declare i: int = 0
+ * cond:
+ * i < 10
+ * step:
+ * i = i + 1
+ * body:
+ * …
+ * end body
* end loop
* }
*
* 各区块说明:
* + * 该类用于封装词法分析(lexical analysis)阶段发现的错误,包括错误位置(文件名、行号、列号) + * 以及错误描述信息,便于定位和调试。 + *
+ */ public class LexicalError { + /** + * 出错所在的源文件名。 + */ private final String file; + + /** + * 出错所在的行号(从1开始)。 + */ private final int line; + + /** + * 出错所在的列号(从1开始)。 + */ private final int column; + + /** + * 错误的详细描述信息。 + */ private final String message; + /** + * 构造一个新的 {@code LexicalError} 实例。 + * + * @param file 出错的源文件名 + * @param line 出错所在的行号(从1开始) + * @param column 出错所在的列号(从1开始) + * @param message 错误的详细描述信息 + */ public LexicalError(String file, int line, int column, String message) { this.file = file; this.line = line; @@ -13,6 +43,11 @@ public class LexicalError { this.message = message; } + /** + * 以易于阅读的字符串形式返回错误信息。 + * + * @return 格式化的错误信息字符串,包含文件名、行号、列号和错误描述 + */ @Override public String toString() { return file + ": 行 " + line + ", 列 " + column + ": " + message; From cd6413714859bf715b3782360756f50d2884bde5 Mon Sep 17 00:00:00 2001 From: Luke* 例: - * main.s:2:19: Lexical error: Illegal character sequence '@' at 2:19 + * main.s:2:19: 词法错误:非法字符序列 '@' at 2:19 **/ public class LexicalException extends RuntimeException { From 3d35e81a97a1f68133e9da1ae9c6d501a1500175 Mon Sep 17 00:00:00 2001 From: Luke
* 例: - * main.s:2:19: 词法错误:非法字符序列 '@' at 2:19 + * Main.snow: 行 7, 列 20: 词法错误:非法字符序列 '@' **/ public class LexicalException extends RuntimeException { From f540d7fad5215b00d0563c5ee9342d624c8d77ce Mon Sep 17 00:00:00 2001 From: Luke
* 该命令会依次执行依赖解析、源码编译和产物打包阶段。 *
* *- * 用法示例: + * 用法示例: * $ snow build **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/CleanCommand.java b/src/main/java/org/jcnc/snow/cli/commands/CleanCommand.java index 0c65244..a53cf4e 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/CleanCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/CleanCommand.java @@ -6,13 +6,13 @@ import org.jcnc.snow.pkg.lifecycle.LifecyclePhase; import org.jcnc.snow.pkg.tasks.CleanTask; /** - * CLI 命令:清理构建输出和本地缓存目录。 + * CLI 命令: 清理构建输出和本地缓存目录。 *
* 用于清除项目生成的 build、dist 等中间产物,保持工作区整洁。 *
* *- * 用法示例: + * 用法示例: * $ snow clean **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java b/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java index 993e1cb..277c8b5 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java @@ -13,17 +13,17 @@ import java.util.Collections; import java.util.List; /** - * CLI 命令:编译当前项目。 + * CLI 命令: 编译当前项目。 * - *
工作模式说明:
+ *工作模式说明:
*两种模式均将最终参数交由 {@link CompileTask} 处理。
@@ -67,12 +67,12 @@ public final class CompileCommand implements CLICommand { } } - /* 源码目录:build.srcDir -> 默认 src */ + /* 源码目录: build.srcDir -> 默认 src */ String srcDir = project.getBuild().get("srcDir", "src"); argList.add("-d"); argList.add(srcDir); - /* 输出名称:build.output -> fallback to artifact */ + /* 输出名称: build.output -> fallback to artifact */ String output = project.getBuild().get("output", project.getArtifact()); argList.add("-o"); argList.add(output); diff --git a/src/main/java/org/jcnc/snow/cli/commands/GenerateCommand.java b/src/main/java/org/jcnc/snow/cli/commands/GenerateCommand.java index b83a28d..cc78ec2 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/GenerateCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/GenerateCommand.java @@ -12,19 +12,19 @@ import java.nio.file.Path; import java.nio.file.Paths; /** - * CLI 命令:根据 project.cloud 生成项目目录结构。 + * CLI 命令: 根据 project.cloud 生成项目目录结构。 ** 负责解析云项目描述文件,并通过 {@link GenerateTask} * 在 INIT 生命周期阶段内生成基础目录结构。 *
* *- * 用法示例: + * 用法示例: * $ snow generate ** *
- * 注意事项: + * 注意事项: * - 若当前目录不存在 project.cloud,则提示用户先执行 `snow init`。 * - 执行成功后,会输出已创建的目录/文件。 *
diff --git a/src/main/java/org/jcnc/snow/cli/commands/InitCommand.java b/src/main/java/org/jcnc/snow/cli/commands/InitCommand.java index d9cbf92..1986e2f 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/InitCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/InitCommand.java @@ -8,13 +8,13 @@ import java.nio.file.Path; import java.nio.file.Paths; /** - * CLI 命令:初始化项目配置文件。 + * CLI 命令: 初始化项目配置文件。 ** 用于快速生成 DSL 配置文件(project.cloud)。 *
* *- * 用法示例: + * 用法示例: * $ snow init **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java b/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java index 6199602..09eb9b3 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java @@ -8,13 +8,13 @@ import org.jcnc.snow.pkg.resolver.DependencyResolver; import java.nio.file.Paths; /** - * CLI 命令:解析并下载项目依赖到本地缓存。 + * CLI 命令: 解析并下载项目依赖到本地缓存。 *
* 适用于离线使用和依赖预热场景,会自动读取项目描述文件并处理依赖缓存。 *
* *- * 用法示例: + * 用法示例: * $ snow install **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java b/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java index 658e799..347aeff 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java @@ -10,14 +10,14 @@ import org.jcnc.snow.pkg.tasks.PublishTask; import java.nio.file.Paths; /** - * CLI 命令:将已构建的项目包发布到远程仓库。 + * CLI 命令: 将已构建的项目包发布到远程仓库。 *
* 用于持续集成、交付或分发场景。 * 支持自动读取 DSL 项目描述文件,并注册和执行发布生命周期阶段的任务。 *
* *- * 用法示例: + * 用法示例: * $ snow publish **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java b/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java index 0aeffe6..159dcb5 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java @@ -4,14 +4,14 @@ import org.jcnc.snow.cli.api.CLICommand; import org.jcnc.snow.pkg.tasks.RunTask; /** - * CLI 命令:运行已编译的 VM 字节码文件(.water)。 + * CLI 命令: 运行已编译的 VM 字节码文件(.water)。 *
* 仅解析参数并委托给 {@link RunTask}, * 将 VM 运行逻辑下沉至 pkg 层,保持 CLI 无状态、薄封装。 *
* *- * 用法示例: + * 用法示例: * $ snow run main.water **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java b/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java index d2989b5..94fc6e7 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java @@ -4,13 +4,13 @@ import org.jcnc.snow.cli.SnowCLI; import org.jcnc.snow.cli.api.CLICommand; /** - * CLI 子命令:输出当前 Snow 工具的版本号。 + * CLI 子命令: 输出当前 Snow 工具的版本号。 *
* 用于显示当前 CLI 工具版本,便于诊断、升级、兼容性确认等场景。 *
* *- * 用法示例: + * 用法示例: * $ snow version **/ diff --git a/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java b/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java index 10e50a9..c7a1c11 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java @@ -15,7 +15,7 @@ import java.util.Map; * 各虚拟寄存器实际对应的物理寄存器或栈槽号。采用简单的线性扫描分配策略。 * *
- * 分配过程如下: + * 分配过程如下: *
- * 键:虚拟寄存器 {@link IRVirtualRegister}; - * 值:对应分配的槽编号 {@link Integer}。 + * 键: 虚拟寄存器 {@link IRVirtualRegister}; + * 值: 对应分配的槽编号 {@link Integer}。 *
*/ private final Map- * 分配顺序说明: + * 分配顺序说明: *
- * 工作流程简述: + * 工作流程简述: *
- * 键:IR 指令类型(Class对象), - * 值:对应的指令生成器实例。 + * 键: IR 指令类型(Class对象), + * 值: 对应的指令生成器实例。 *
*/ private final Map
* 本类用于编译器后端,将所有生成的 VM 指令(包括分支和调用指令)统一存储、管理。
* 支持符号(如函数入口、标签地址)的延迟解析与回填(fix-up)机制,
@@ -22,7 +22,7 @@ public final class VMProgramBuilder {
/** 未解析目标的分支指令(JUMP/IC_* 等待修补) */
private record BranchFix(int index, String label) {}
- /** 占位符:用于表示尚未确定的符号地址 */
+ /** 占位符: 用于表示尚未确定的符号地址 */
private static final String PLACEHOLDER = "-1";
/** 按顺序存放的 VM 指令文本 */
@@ -102,7 +102,7 @@ public final class VMProgramBuilder {
/**
* 生成 CALL 指令。
- * 支持延迟修补:若目标已知,直接写入地址;否则写入占位并登记 fix-up。
+ * 支持延迟修补: 若目标已知,直接写入地址;否则写入占位并登记 fix-up。
* @param target 目标函数名
* @param nArgs 参数个数
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/doc/README.md b/src/main/java/org/jcnc/snow/compiler/backend/doc/README.md
index c9edc59..1808833 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/doc/README.md
+++ b/src/main/java/org/jcnc/snow/compiler/backend/doc/README.md
@@ -5,22 +5,22 @@
## 项目简介
**后端模块(Backend)** 是 [Snow 编译器]() 的核心组成部分之一,承接中间表示(IR)与运行时虚拟机(VM)之间的桥梁。
-它主要完成以下工作:
+它主要完成以下工作:
-1. **寄存器分配**:将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
-2. **指令生成与调度**:为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
-3. **程序构建**:管理函数入口、标签定义、延迟修补(fix-up)CALL/JUMP 等控制流指令地址;
-4. **操作码与常量映射**:提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
+1. **寄存器分配**: 将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
+2. **指令生成与调度**: 为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
+3. **程序构建**: 管理函数入口、标签定义、延迟修补(fix-up)CALL/JUMP 等控制流指令地址;
+4. **操作码与常量映射**: 提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
-后端模块设计注重可扩展性:各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
+后端模块设计注重可扩展性: 各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
## 核心功能
-* **线性扫描寄存器分配**:`RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。
-* **指令生成器体系**:`InstructionGenerator
类型提升优先级:D > F > L > I > S > B
+ *类型提升优先级: D > F > L > I > S > B
*/ public class BinaryOpGenerator implements InstructionGenerator* 在进行数值类型运算、比较等操作时,低优先级的类型会被提升为高优先级类型参与运算。 * 例如 int + long 运算,int 会被提升为 long,最终运算结果类型为 long。 *
- * 类型优先级从高到低依次为: - * D(double):6 - * F(float) :5 - * L(long) :4 - * I(int) :3 - * S(short) :2 - * B(byte) :1 - * 未识别类型 :0 + * 类型优先级从高到低依次为: + * D(double): 6 + * F(float) : 5 + * L(long) : 4 + * I(int) : 3 + * S(short) : 2 + * B(byte) : 1 + * 未识别类型 : 0 */ public class TypePromoteUtils { /** * 返回数值类型的宽度优先级,数值越大类型越宽。 - * 类型及优先级映射如下: + * 类型及优先级映射如下: * D(double): 6 * F(float) : 5 * L(long) : 4 @@ -69,8 +69,8 @@ public class TypePromoteUtils { * 获取类型转换指令名(例如 "I2L", "F2D"),表示从源类型到目标类型的转换操作。 * 如果源类型和目标类型相同,则返回 null,表示无需转换。 *
- * 支持的类型标记字符包括:B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
- * 所有可能的类型转换均已覆盖,如下所示:
+ * 支持的类型标记字符包括: B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
+ * 所有可能的类型转换均已覆盖,如下所示:
* B → S/I/L/F/D
* S → B/I/L/F/D
* I → B/S/L/F/D
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
index bb8c32e..d56103a 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
@@ -19,7 +19,7 @@ import java.util.*;
* 该类负责将抽象语法树(AST)的表达式节点转换为中间表示(IR)指令和虚拟寄存器,
* 是编译器IR生成阶段的核心工具。
*
- * 主要职责包括:
+ * 主要职责包括:
*
会根据节点的实际类型分别处理: + *
会根据节点的实际类型分别处理: *
-x(取负,生成 NEG_I32 指令)与x == 0 比较指令)- * 构建过程包括: + * 构建过程包括: *
主要功能包括: + *
主要功能包括: *
本类提供以下核心功能: + *
本类提供以下核心功能: *
包内可见:仅限 builder 包内部使用。 + *
包内可见: 仅限 builder 包内部使用。 * * @return IRBuilderScope 实例 */ diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java index 225743e..d32a544 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java @@ -13,7 +13,7 @@ import java.util.List; /** * 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram。 * - *
主要职责: + *
主要职责: *
封装规则: + *
封装规则: *
- * 实现方式:dest = src + 0(即加上常量 0)。 + * 实现方式: dest = src + 0(即加上常量 0)。 *
* * @param ctx 当前 IR 上下文 @@ -92,7 +92,7 @@ public class InstructionFactory { if (src == dest) { return; } - // 回退实现:dest = src + 0 + // 回退实现: dest = src + 0 IRVirtualRegister zero = loadConst(ctx, 0); ctx.addInstruction(new BinaryOperationInstruction(IROpCode.ADD_I32, dest, src, zero)); } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java index 7472269..47bd7ca 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java @@ -150,7 +150,7 @@ public class StatementBuilder { /** * 构建循环语句(for/while)。 - * 处理流程:初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。 + * 处理流程: 初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。 * * @param loop 循环节点 */ @@ -176,7 +176,7 @@ public class StatementBuilder { /** * 构建分支语句(if/else)。 - * 处理流程:条件判断 → then 分支 → else 分支(可选)。 + * 处理流程: 条件判断 → then 分支 → else 分支(可选)。 * * @param ifNode if 语句节点 */ diff --git a/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java b/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java index db6502c..7105704 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java @@ -22,8 +22,8 @@ public final class GlobalFunctionTable { /** * 存储全局函数返回类型映射表。 *
* func 名称(%0, %1, ...) {
* 指令0
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/core/IROpCode.java b/src/main/java/org/jcnc/snow/compiler/ir/core/IROpCode.java
index 1e6b3e7..41342da 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/core/IROpCode.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/core/IROpCode.java
@@ -24,95 +24,95 @@ public enum IROpCode {
CONV_D64_TO_F32,
- /* ───── 算术运算(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
+ /* ───── 算术运算(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位整型取负
- /* ───── 算术运算(32位整数:int)───── */
+ /* ───── 算术运算(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位整型取负
- /* ───── 算术运算(32位浮点数:float)───── */
+ /* ───── 算术运算(32位浮点数: float)───── */
ADD_F32, // 32位浮点加法
SUB_F32, // 32位浮点减法
MUL_F32, // 32位浮点乘法
DIV_F32, // 32位浮点除法
NEG_F32, // 32位浮点取负
- /* ───── 算术运算(64位浮点数:double)───── */
+ /* ───── 算术运算(64位浮点数: double)───── */
ADD_D64, // 64位浮点加法
SUB_D64, // 64位浮点减法
MUL_D64, // 64位浮点乘法
DIV_D64, // 64位浮点除法
NEG_D64, // 64位浮点取负
- /* ───── 逻辑与比较运算指令(8位整数:byte) ───── */
- CMP_BEQ, // 8位整数相等比较:a == b
- CMP_BNE, // 8位整数不等比较:a != b
- CMP_BLT, // 8位整数小于比较:a < b
- CMP_BGT, // 8位整数大于比较:a > b
- CMP_BLE, // 8位整数小于等于:a <= b
- CMP_BGE, // 8位整数大于等于:a >= b
+ /* ───── 逻辑与比较运算指令(8位整数: byte) ───── */
+ CMP_BEQ, // 8位整数相等比较: a == b
+ CMP_BNE, // 8位整数不等比较: a != b
+ CMP_BLT, // 8位整数小于比较: a < b
+ CMP_BGT, // 8位整数大于比较: a > b
+ CMP_BLE, // 8位整数小于等于: a <= b
+ CMP_BGE, // 8位整数大于等于: a >= b
- /* ───── 逻辑与比较运算指令(16位整数:int) ───── */
- CMP_SEQ, // 16位整数相等比较:a == b
- CMP_SNE, // 16位整数不等比较:a != b
- CMP_SLT, // 16位整数小于比较:a < b
- CMP_SGT, // 16位整数大于比较:a > b
- CMP_SLE, // 16位整数小于等于:a <= b
- CMP_SGE, // 16位整数大于等于:a >= b
+ /* ───── 逻辑与比较运算指令(16位整数: int) ───── */
+ CMP_SEQ, // 16位整数相等比较: a == b
+ CMP_SNE, // 16位整数不等比较: a != b
+ CMP_SLT, // 16位整数小于比较: a < b
+ CMP_SGT, // 16位整数大于比较: a > b
+ CMP_SLE, // 16位整数小于等于: a <= b
+ CMP_SGE, // 16位整数大于等于: a >= b
- /* ───── 逻辑与比较运算指令(32位整数:int) ───── */
- CMP_IEQ, // 32位整数相等比较:a == b
- CMP_INE, // 32位整数不等比较:a != b
- CMP_ILT, // 32位整数小于比较:a < b
- CMP_IGT, // 32位整数大于比较:a > b
- CMP_ILE, // 32位整数小于等于:a <= b
- CMP_IGE, // 32位整数大于等于:a >= b
+ /* ───── 逻辑与比较运算指令(32位整数: int) ───── */
+ CMP_IEQ, // 32位整数相等比较: a == b
+ CMP_INE, // 32位整数不等比较: a != b
+ CMP_ILT, // 32位整数小于比较: a < b
+ CMP_IGT, // 32位整数大于比较: a > b
+ CMP_ILE, // 32位整数小于等于: a <= b
+ CMP_IGE, // 32位整数大于等于: a >= b
- /* ───── 逻辑与比较运算指令(64位整数:long) ───── */
- CMP_LEQ, // 64位整数相等比较:a == b
- CMP_LNE, // 64位整数不等比较:a != b
- CMP_LLT, // 64位整数小于比较:a < b
- CMP_LGT, // 64位整数大于比较:a > b
- CMP_LLE, // 64位整数小于等于:a <= b
- CMP_LGE, // 64位整数大于等于:a >= b
+ /* ───── 逻辑与比较运算指令(64位整数: long) ───── */
+ CMP_LEQ, // 64位整数相等比较: a == b
+ CMP_LNE, // 64位整数不等比较: a != b
+ CMP_LLT, // 64位整数小于比较: a < b
+ CMP_LGT, // 64位整数大于比较: a > b
+ CMP_LLE, // 64位整数小于等于: a <= b
+ CMP_LGE, // 64位整数大于等于: a >= b
- /* ───── 逻辑与比较运算指令(32位浮点数:float) ───── */
- CMP_FEQ, // 32位浮点相等比较:a == b
- CMP_FNE, // 32位浮点不等比较:a != b
- CMP_FLT, // 32位浮点小于比较:a < b
- CMP_FGT, // 32位浮点大于比较:a > b
- CMP_FLE, // 32位浮点小于等于:a <= b
- CMP_FGE, // 32位浮点大于等于:a >= b
+ /* ───── 逻辑与比较运算指令(32位浮点数: float) ───── */
+ CMP_FEQ, // 32位浮点相等比较: a == b
+ CMP_FNE, // 32位浮点不等比较: a != b
+ CMP_FLT, // 32位浮点小于比较: a < b
+ CMP_FGT, // 32位浮点大于比较: a > b
+ CMP_FLE, // 32位浮点小于等于: a <= b
+ CMP_FGE, // 32位浮点大于等于: a >= b
- /* ───── 逻辑与比较运算指令(64位浮点数:double) ───── */
- CMP_DEQ, // 64位浮点相等比较:a == b
- CMP_DNE, // 64位浮点不等比较:a != b
- CMP_DLT, // 64位浮点小于比较:a < b
- CMP_DGT, // 64位浮点大于比较:a > b
- CMP_DLE, // 64位浮点小于等于:a <= b
- CMP_DGE, // 64位浮点大于等于:a >= b
+ /* ───── 逻辑与比较运算指令(64位浮点数: double) ───── */
+ CMP_DEQ, // 64位浮点相等比较: a == b
+ CMP_DNE, // 64位浮点不等比较: a != b
+ CMP_DLT, // 64位浮点小于比较: a < b
+ CMP_DGT, // 64位浮点大于比较: a > b
+ CMP_DLE, // 64位浮点小于等于: a <= b
+ CMP_DGE, // 64位浮点大于等于: a >= b
/* ───── 数据访问与常量操作 ───── */
LOAD, // 从内存加载数据至寄存器
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/core/IRValue.java b/src/main/java/org/jcnc/snow/compiler/ir/core/IRValue.java
index ab520f6..fcfb708 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/core/IRValue.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/core/IRValue.java
@@ -11,11 +11,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
* 实现该接口的类型可以作为 {@link IRInstruction} 中的操作数出现。
*
*
- * 当前支持的 IR 值类型包括:
+ * 当前支持的 IR 值类型包括:
* diff --git a/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java b/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java index 82231f9..5506f0e 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java @@ -7,12 +7,12 @@ import org.jcnc.snow.compiler.ir.instruction.*; *
* 它定义了访问者模式的核心机制,通过对每种 {@link IRInstruction} 子类 * 提供独立的 {@code visit} 方法,实现对指令的分发与处理。 - * 不同的访问者实现可用于执行不同任务,例如: + * 不同的访问者实现可用于执行不同任务,例如: *
*diff --git a/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md b/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md index 142b59f..8ee8212 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md +++ b/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md @@ -11,27 +11,27 @@ IR 模块以类 SSA(Static Single Assignment)形式设计,通过统一的 ## 核心功能 -* **统一的中间表示模型**:表达控制流与数据流,支持函数、指令、值等核心结构 -* **IR 构建器体系**:模块化构建函数、表达式与语句 IR,简化前端对接 -* **灵活的指令层级结构**:支持二元操作、跳转、返回等多种基本指令 -* **寄存器与常量模型**:统一管理虚拟寄存器、常量、标签等值类型 -* **IR 打印与调试支持**:辅助输出 IR 文本格式,支持可视化与调试 +* **统一的中间表示模型**: 表达控制流与数据流,支持函数、指令、值等核心结构 +* **IR 构建器体系**: 模块化构建函数、表达式与语句 IR,简化前端对接 +* **灵活的指令层级结构**: 支持二元操作、跳转、返回等多种基本指令 +* **寄存器与常量模型**: 统一管理虚拟寄存器、常量、标签等值类型 +* **IR 打印与调试支持**: 辅助输出 IR 文本格式,支持可视化与调试 ## 模块结构 ``` ir/ - ├── builder/ // 构建器模块:负责构造表达式、函数与语句的 IR - ├── core/ // 核心定义:IR 基础结构,如函数、指令、程序、访问器等 - ├── instruction/ // 指令实现:具体的 IR 指令类型(如加法、跳转、返回等) - ├── utils/ // 工具模块:提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等) - └── value/ // 值模型:常量、标签、虚拟寄存器等 + ├── builder/ // 构建器模块: 负责构造表达式、函数与语句的 IR + ├── core/ // 核心定义: IR 基础结构,如函数、指令、程序、访问器等 + ├── instruction/ // 指令实现: 具体的 IR 指令类型(如加法、跳转、返回等) + ├── utils/ // 工具模块: 提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等) + └── value/ // 值模型: 常量、标签、虚拟寄存器等 ``` ## 开发环境 * JDK 24 或更高版本 * Maven 构建管理 -* 推荐 IDE:IntelliJ IDEA +* 推荐 IDE: IntelliJ IDEA --- diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java index e42df97..cd83dde 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java @@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import java.util.List; /** - * BinaryOperationInstruction —— 表示一个二元运算指令,格式为:dest = lhs OP rhs + * BinaryOperationInstruction —— 表示一个二元运算指令,格式为: dest = lhs OP rhs *
* 该类用于描述形如 a = b + c 或 a = x * y 的二元运算指令。
* 运算类型(OP)由 {@link IROpCode} 指定,包括加法、减法、乘法、除法等。
@@ -76,7 +76,7 @@ public final class BinaryOperationInstruction extends IRInstruction {
/**
* 转换为字符串格式,便于调试与打印。
- * 例:v1 = ADD_I32 v2, v3
+ * 例: v1 = ADD_I32 v2, v3
*
* @return 指令的字符串表示形式
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
index 13db658..dd963d9 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
@@ -46,7 +46,7 @@ public class CallInstruction extends IRInstruction {
return isVoidReturn() ? null : dest;
}
- /** 操作数列表:void 调用不包含 dest */
+ /** 操作数列表: void 调用不包含 dest */
@Override
public List
* 本类是一个具体的 IRInstruction 子类,表示将两个值相加,并将结果写入目标寄存器的操作。
* 虽然功能与通用的 {@link BinaryOperationInstruction} 类似,但它作为更简化明确的指令实现,
@@ -40,7 +40,7 @@ public class IRAddInstruction extends IRInstruction {
}
/**
- * 返回该指令的操作码:ADD_I32。
+ * 返回该指令的操作码: ADD_I32。
*
* @return 加法操作码
*/
@@ -81,7 +81,7 @@ public class IRAddInstruction extends IRInstruction {
/**
* 返回指令的字符串形式,方便调试。
- * 例如:v1 = v2 + v3
+ * 例如: v1 = v2 + v3
*
* @return 字符串表示形式
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java
index 9c34401..74d472d 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java
@@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.ir.core.IRVisitor;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
/**
- * “比较 + 条件跳转” 复合指令:
+ * “比较 + 条件跳转” 复合指令:
* if ( left
* 其中 cmpOp 只能是 IROpCode.CMP_* 六种比较操作码。
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java
index 51d5c9a..96b83ce 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java
@@ -25,7 +25,7 @@ public class IRJumpInstruction extends IRInstruction {
}
/**
- * 获取该指令对应的操作码:JUMP。
+ * 获取该指令对应的操作码: JUMP。
*
* @return IROpCode.JUMP
*/
@@ -55,7 +55,7 @@ public class IRJumpInstruction extends IRInstruction {
/**
* 将指令转为字符串形式,便于打印与调试。
- * 例如:jump L1
+ * 例如: jump L1
*
* @return 指令的字符串表示
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java
index edf5034..0aa5071 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java
@@ -29,7 +29,7 @@ public class IRReturnInstruction extends IRInstruction {
}
/**
- * 获取该指令的操作码:RET。
+ * 获取该指令的操作码: RET。
*
* @return IROpCode.RET,表示返回操作
*/
@@ -60,7 +60,7 @@ public class IRReturnInstruction extends IRInstruction {
/**
* 转换为字符串形式,便于调试与打印。
- * 示例:ret v1
+ * 示例: ret v1
*
* @return 字符串形式的返回指令
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java
index 0b9a73e..3ef925a 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java
@@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
- * LoadConstInstruction —— 表示一个常量加载指令,格式为:dest = CONST k
+ * LoadConstInstruction —— 表示一个常量加载指令,格式为: dest = CONST k
*
* 该指令的功能是将一个常量(字面量或编译期已知值)加载到一个虚拟寄存器中,
* 供后续指令使用。例如,在表达式计算、参数传递、初始化等场景中常用。
@@ -66,7 +66,7 @@ public final class LoadConstInstruction extends IRInstruction {
/**
* 返回该指令的字符串形式,便于调试或打印。
- * 例如:v1 = CONST 42
+ * 例如: v1 = CONST 42
*
* @return 指令的字符串表示
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java
index 759c3ff..f689e99 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java
@@ -9,11 +9,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
- * ReturnInstruction —— 表示函数返回指令,格式:RET 或 RET
- * 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
- * - 无返回值(void):生成无参的 RET 指令
- * - 有返回值:将指定虚拟寄存器中的值返回给调用者
+ * 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
+ * - 无返回值(void): 生成无参的 RET 指令
+ * - 有返回值: 将指定虚拟寄存器中的值返回给调用者
*
* 与 {@link IRReturnInstruction} 类似,但更通用,适配多种函数返回风格。
*/
@@ -36,7 +36,7 @@ public final class ReturnInstruction extends IRInstruction {
}
/**
- * 返回该指令的操作码类型:RET。
+ * 返回该指令的操作码类型: RET。
*
* @return IROpCode.RET
*/
@@ -68,8 +68,8 @@ public final class ReturnInstruction extends IRInstruction {
/**
* 转换为字符串形式,便于调试与输出。
- * - 无返回值:RET
- * - 有返回值:RET v1
+ * - 无返回值: RET
+ * - 有返回值: RET v1
*
* @return 字符串表示的返回指令
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java
index 25b9e96..0e02b76 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java
@@ -9,14 +9,14 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List;
/**
- * UnaryOperationInstruction —— 表示一个一元运算指令,格式:dest = OP val
+ * UnaryOperationInstruction —— 表示一个一元运算指令,格式: dest = OP val
*
* 用于对单个操作数 val 执行指定的一元运算 OP(例如取负 NEG),
* 并将结果写入目标虚拟寄存器 dest。
*
- * 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
+ * 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
*
- * 主要功能:
+ * 主要功能:
* - 解析字面量常量,自动推断类型
* - 自动匹配并选择适合的算术/比较操作码
* - 表达式类型的合并与类型提升
@@ -138,7 +138,7 @@ public final class ExpressionUtils {
}
/**
- * 兼容旧逻辑:仅凭操作符直接返回 int32 比较指令。
+ * 兼容旧逻辑: 仅凭操作符直接返回 int32 比较指令。
*
* @param op 比较操作符
* @return int32 类型的比较操作码
@@ -148,7 +148,7 @@ public final class ExpressionUtils {
}
/**
- * 推荐调用:根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码。
+ * 推荐调用: 根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码。
*
* @param variables 变量名到类型的映射
* @param op 比较符号
@@ -196,7 +196,7 @@ public final class ExpressionUtils {
/**
* 返回两个类型后缀中的最大类型(宽度优先)。
- * 优先级:d > f > l > i > s > b > '\0'
+ * 优先级: d > f > l > i > s > b > '\0'
*
* @param l 类型后缀1
* @param r 类型后缀2
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/value/IRConstant.java b/src/main/java/org/jcnc/snow/compiler/ir/value/IRConstant.java
index 1af295c..776d688 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/value/IRConstant.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/value/IRConstant.java
@@ -9,18 +9,18 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
* 与 {@link IRVirtualRegister} 不同,常量不需要通过寄存器存储,
* 可直接作为 IR 指令的操作数使用。
*
- * 典型应用:
- * - 加载常量指令:v1 = CONST 42
- * - 计算表达式:v2 = ADD v1, 100
+ * 典型应用:
+ * - 加载常量指令: v1 = CONST 42
+ * - 计算表达式: v2 = ADD v1, 100
*/
public record IRConstant(Object value) implements IRValue {
/**
* 将常量值转换为字符串,用于打印 IR 指令或调试输出。
*
- * 例如:
- * - 整数常量:42
- * - 字符串常量:"hello"
+ * 例如:
+ * - 整数常量: 42
+ * - 字符串常量: "hello"
*
* @return 常量的字符串表示
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java b/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java
index f4bdaa3..cb022f8 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java
@@ -8,11 +8,11 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
* 在 IR 系统中,虚拟寄存器用于存储每个中间计算结果,是 SSA(Static Single Assignment)形式的核心。
* 每个虚拟寄存器在程序中只被赋值一次,其值来源于一条明确的指令输出。
*
- * 特点:
+ * 特点:
*
- * 设计要点:
+ * 设计要点:
* 采用“先扫描 → 后批量校验 → 统一报告”策略:
+ * 采用“先扫描 → 后批量校验 → 统一报告”策略:
*
* 实现应消费一定字符并根据规则构造 Token。
* 若无需生成 Token,可返回 null。
@@ -49,7 +49,7 @@ public abstract class AbstractTokenScanner implements TokenScanner {
protected abstract Token scanToken(LexerContext ctx, int line, int col);
/**
- * 工具方法:连续读取字符直到遇到不满足指定条件的字符。
+ * 工具方法: 连续读取字符直到遇到不满足指定条件的字符。
*
* @param ctx 当前词法上下文
* @param predicate 字符匹配条件
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/CommentTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/CommentTokenScanner.java
index 90204ce..efe5054 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/CommentTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/CommentTokenScanner.java
@@ -8,17 +8,17 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
/**
* {@code CommentTokenScanner} —— 注释解析器,基于有限状态机(FSM)。
*
- * 负责将源码中的两种注释形式切分为 {@link TokenType#COMMENT COMMENT} token: 负责将源码中的两种注释形式切分为 {@link TokenType#COMMENT COMMENT} token: 本扫描器遵循“发现即捕获”原则:注释文本被完整保留在 Token 中,供后续的文档提取、源映射等分析使用。 本扫描器遵循“发现即捕获”原则: 注释文本被完整保留在 Token 中,供后续的文档提取、源映射等分析使用。 错误处理策略 标识符的识别遵循以下规则: 标识符的识别遵循以下规则:
* 用于记录行的分界,辅助语法分析阶段进行行敏感的判断或保持结构清晰。
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
index 88592b9..7b983d7 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
@@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
/**
* NumberTokenScanner —— 基于有限状态机(FSM)的数字字面量解析器。
*
- * 该扫描器负责将源码中的数字字符串切分为 NUMBER_LITERAL token,当前支持:
+ * 该扫描器负责将源码中的数字字符串切分为 NUMBER_LITERAL token,当前支持:
* 负责在词法分析阶段识别由 = ! < > | & % 等字符
- * 起始的单字符或双字符运算符,并生成相应 {@link Token}:
- *
*/
@@ -76,7 +76,7 @@ public final class UnaryOperationInstruction extends IRInstruction {
/**
* 将该指令格式化为字符串,便于打印与调试。
- * 形式:dest = OP val,例如:v1 = NEG v2
+ * 形式: dest = OP val,例如: v1 = NEG v2
*
* @return 字符串形式的指令
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java
index 2cf8828..75f388d 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java
@@ -16,11 +16,11 @@ import java.util.Map;
* 支持自动类型提升,保证 int、long、float、double 等类型的比较均能得到正确的 IR 指令。
*
- *
*/
public final class ComparisonUtils {
@@ -39,7 +39,7 @@ public final class ComparisonUtils {
}
/**
- * 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
+ * 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
* - D (double): 6
* - F (float): 5
* - L (long): 4
@@ -106,7 +106,7 @@ public final class ComparisonUtils {
}
/**
- * 内部工具方法:根据表达式节点和变量表推断类型标记字符。
+ * 内部工具方法: 根据表达式节点和变量表推断类型标记字符。
* 字面量支持 B/S/I/L/F/D(大小写均可),浮点数默认 double;
* 标识符类型按变量表映射,未知则默认 int。
*
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
index c12525d..a8d4561 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
@@ -14,7 +14,7 @@ import java.util.Map;
/**
* 表达式分析与操作符选择工具类。
*
*
*
* 适用于表达式求值、参数传递、函数返回值、临时变量等所有中间值场景。
@@ -23,7 +23,7 @@ public record IRVirtualRegister(int id) implements IRValue {
/**
* 将虚拟寄存器转换为字符串格式,方便输出和调试。
- * 格式为:%
*
* \r\n) 转换为 Unix 风格 (\n)。
*
+ * 目前包含三条规则:
* 1. Dot-Prefix'.' 不能作标识符前缀
* 2. Declare-Ident declare 后必须紧跟合法标识符,并且只能一个
* 3. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余
@@ -149,6 +149,6 @@ public class LexerEngine {
/** 构造统一的 LexicalError */
private LexicalError err(Token t, String msg) {
- return new LexicalError(absPath, t.getLine(), t.getCol(), "非法的标记序列:" + msg);
+ return new LexicalError(absPath, t.getLine(), t.getCol(), "非法的标记序列: " + msg);
}
}
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
index ad81965..836ae99 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
@@ -10,8 +10,8 @@ package org.jcnc.snow.compiler.lexer.core;
*
- * 例:
- * Main.snow: 行 7, 列 20: 词法错误:非法字符序列 '@'
+ * 例:
+ * Main.snow: 行 7, 列 20: 词法错误: 非法字符序列 '@'
*
*/
public class LexicalException extends RuntimeException {
@@ -24,7 +24,7 @@ public class LexicalException extends RuntimeException {
/**
* 构造词法异常
- * @param reason 错误原因(如:非法字符描述)
+ * @param reason 错误原因(如: 非法字符描述)
* @param line 出错行号
* @param column 出错列号
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/doc/README.md b/src/main/java/org/jcnc/snow/compiler/lexer/doc/README.md
index c203e85..f294e93 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/doc/README.md
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/doc/README.md
@@ -11,11 +11,11 @@
## 核心功能
-- **词法分析引擎**:从源代码提取标准化 Token 流
-- **模块化扫描器体系**:按需扩展不同类型的 Token 识别
-- **灵活的上下文管理**:跟踪源代码位置,支持错误处理
-- **统一的 Token 工厂**:集中创建 Token 实例
-- **工具支持**:Token 打印与调试辅助
+- **词法分析引擎**: 从源代码提取标准化 Token 流
+- **模块化扫描器体系**: 按需扩展不同类型的 Token 识别
+- **灵活的上下文管理**: 跟踪源代码位置,支持错误处理
+- **统一的 Token 工厂**: 集中创建 Token 实例
+- **工具支持**: Token 打印与调试辅助
## 模块结构
@@ -33,6 +33,6 @@ lexer/
* JDK 24 或更高版本
* Maven 构建管理
-* 推荐 IDE:IntelliJ IDEA
+* 推荐 IDE: IntelliJ IDEA
---
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java
index 917b2c1..a539744 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java
@@ -35,7 +35,7 @@ public abstract class AbstractTokenScanner implements TokenScanner {
}
/**
- * 抽象方法:由子类实现具体的扫描逻辑。
+ * 抽象方法: 由子类实现具体的扫描逻辑。
*
- *
*
- * */ 结束,可跨多行。*/ 结束,可跨多行。
- *
*/
public class CommentTokenScanner extends AbstractTokenScanner {
@@ -61,7 +61,7 @@ public class CommentTokenScanner extends AbstractTokenScanner {
break;
case SINGLE_LINE:
- // 单行注释处理:读取直到行尾
+ // 单行注释处理: 读取直到行尾
if (ctx.isAtEnd() || ctx.peek() == '\n') {
// 如果遇到换行符,停止读取并返回注释内容
return new Token(TokenType.COMMENT, literal.toString(), line, col);
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/IdentifierTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/IdentifierTokenScanner.java
index 1e18cbb..333ff84 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/IdentifierTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/IdentifierTokenScanner.java
@@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
/**
* {@code IdentifierTokenScanner} —— 标识符扫描器,负责识别源代码中的标识符(如变量名、函数名等)。
*
- * */,抛出 {@link LexicalException}。*/,抛出 {@link LexicalException}。
*
*
- * 状态机简述:
+ * 状态机简述:
* INT_PART --'.'--> DEC_POINT
* | |
* | v
@@ -27,28 +27,28 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
* v
* DEC_POINT --digit--> FRAC_PART
*
- * 状态说明:
+ * 状态说明:
*
- *
*
- * 错误处理策略:
+ * 错误处理策略:
*
*
*
- * 支持的单字符类型后缀包括:b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set
如果无法匹配到合法组合,将返回 {@link TokenType#UNKNOWN}。
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java index a610d06..8c696e8 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java @@ -5,9 +5,9 @@ import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.lexer.token.TokenType; /** - * 字符串扫描器:处理双引号包裹的字符串字面量,支持基本的转义字符。 + * 字符串扫描器: 处理双引号包裹的字符串字面量,支持基本的转义字符。 *- * 支持格式示例: + * 支持格式示例: *
- * 支持的符号包括: + * 支持的符号包括: *
* 生成的 Token 类型根据字符分别对应 {@link TokenType} 枚举中的定义。 diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java index b7cc295..5552d4b 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java @@ -11,7 +11,7 @@ import org.jcnc.snow.compiler.lexer.token.Token; * 由本类处理并抛出 {@link LexicalException},终止词法分析流程。 *
*- * 主要作用:保证所有非法、不可识别的字符(如@、$等)不会被静默跳过或误当作合法 Token, + * 主要作用: 保证所有非法、不可识别的字符(如@、$等)不会被静默跳过或误当作合法 Token, * 而是在词法阶段立刻定位并报错,有助于尽早发现源代码问题。 *
*/ @@ -50,6 +50,6 @@ public class UnknownTokenScanner extends AbstractTokenScanner { if (lexeme.isEmpty()) lexeme = String.valueOf(ctx.advance()); // 抛出词法异常,并带上错误片段与具体位置 - throw new LexicalException("词法错误:非法字符序列 '" + lexeme + "'", line, col); + throw new LexicalException("词法错误: 非法字符序列 '" + lexeme + "'", line, col); } } diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/WhitespaceTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/WhitespaceTokenScanner.java index 36c9768..07e109d 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/WhitespaceTokenScanner.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/WhitespaceTokenScanner.java @@ -4,7 +4,7 @@ import org.jcnc.snow.compiler.lexer.core.LexerContext; import org.jcnc.snow.compiler.lexer.token.Token; /** - * 空白符扫描器:跳过非换行的空白字符,不生成任何 Token。 + * 空白符扫描器: 跳过非换行的空白字符,不生成任何 Token。 ** 支持的空白字符包括空格、制表符(Tab)等,但不包括换行符(由 {@link NewlineTokenScanner} 处理)。 *
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java index e94c54b..27ef96b 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java @@ -12,7 +12,7 @@ import java.util.Set; *
* *- * 主要功能与特性: + * 主要功能与特性: *
- * 优先级顺序为:类型(TYPE) > 关键字(KEYWORD) > 标识符(IDENTIFIER) > 未知(UNKNOWN)。 + * 优先级顺序为: 类型(TYPE) > 关键字(KEYWORD) > 标识符(IDENTIFIER) > 未知(UNKNOWN)。 * 若原始字符串同时属于多类,则按优先级最高者处理。 *
* @@ -52,7 +52,7 @@ public class TokenFactory { /** * 判断并推断给定字符串的 {@link TokenType} 类型。 *- * 优先级依次为:TYPE > KEYWORD > IDENTIFIER > UNKNOWN。 + * 优先级依次为: TYPE > KEYWORD > IDENTIFIER > UNKNOWN。 *
* * @param raw 原始词素字符串 @@ -106,7 +106,7 @@ public class TokenFactory { ** 合法标识符需以字母(a-z/A-Z)或下划线(_)开头, * 后续可包含字母、数字或下划线。 - * 例如:_abc, a1b2, name_123 均为合法标识符。 + * 例如: _abc, a1b2, name_123 均为合法标识符。 *
* * @param raw 输入的字符串 diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/utils/TokenPrinter.java b/src/main/java/org/jcnc/snow/compiler/lexer/utils/TokenPrinter.java index e9e4e59..0935b48 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/utils/TokenPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/utils/TokenPrinter.java @@ -17,7 +17,7 @@ public class TokenPrinter { /** * 将给定的 Token 列表打印到标准输出(控制台)。 *- * 输出格式: + * 输出格式: *
* line col type lexeme
* ----------------------------------------------------
@@ -33,7 +33,7 @@ public class TokenPrinter {
* 都应包含有效的行号、列号、类型和词素信息
*/
public static void print(List tokens) {
- // 打印表头:列名对齐,宽度分别为 6、6、16
+ // 打印表头: 列名对齐,宽度分别为 6、6、16
System.out.printf("%-6s %-6s %-16s %s%n", "line", "col", "type", "lexeme");
System.out.println("----------------------------------------------------");
@@ -45,7 +45,7 @@ public class TokenPrinter {
.replace("\t", "\\t")
.replace("\r", "\\r");
- // 按照固定格式输出:行号、列号、类型、词素
+ // 按照固定格式输出: 行号、列号、类型、词素
System.out.printf("%-6d %-6d %-16s %s%n",
token.getLine(),
token.getCol(),
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java
index ec56cc2..2ba82e5 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java
@@ -25,7 +25,7 @@ public record BinaryExpressionNode(
/**
* 返回该二元运算表达式的字符串表示形式。
*
- * 输出格式为:{@code left + " " + operator + " " + right},
+ * 输出格式为: {@code left + " " + operator + " " + right},
* 适用于调试或打印语法树结构。
*
*
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
index 9b1d821..7a52cc4 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
@@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
* {@code ExpressionStatementNode} 表示抽象语法树(AST)中的表达式语句节点。
*
* 表达式语句通常由一个单独的表达式组成,并以语句形式出现。
- * 例如:{@code foo();}、{@code x = 1;}、{@code print("hello");} 等。
+ * 例如: {@code foo();}、{@code x = 1;}、{@code print("hello");} 等。
*
*
* @param expression 表达式主体,通常为函数调用、赋值、方法链式调用等可求值表达式。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java
index d1b29f2..e5fce88 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java
@@ -11,7 +11,7 @@ import java.util.List;
*
* 函数定义通常包含函数名、形参列表、返回类型以及函数体,
* 在语义分析、类型检查与代码生成等阶段具有核心地位。
- * 示例:{@code int add(int a, int b) { return a + b; }}
+ * 示例: {@code int add(int a, int b) { return a + b; }}
*
*
* @param name 函数名称标识符
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
index a45c751..ab4bb90 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
@@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
/**
* {@code ImportNode} 表示抽象语法树(AST)中的 import 语句节点。
*
- * import 语句用于引入外部模块或库文件,其语法形式一般为:
+ * import 语句用于引入外部模块或库文件,其语法形式一般为:
* {@code import my.module;}
*
*
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
index b6d17e1..15d6297 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
@@ -12,7 +12,7 @@ import java.util.Optional;
* return 语句用于从当前函数中返回控制权,并可携带一个可选的返回值表达式。
*
*
- * 示例:
+ * 示例:
*
* - {@code return;}
* - {@code return x + 1;}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
index cc22e6a..c30d7ed 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
@@ -6,10 +6,10 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
/**
* {@code UnaryExpressionNode} —— 前缀一元运算 AST 节点。
*
- * 代表两种受支持的一元前缀表达式:
+ *
代表两种受支持的一元前缀表达式:
*
- * - 取负:{@code -x}
- * - 逻辑非:{@code !x}
+ * - 取负: {@code -x}
+ * - 逻辑非: {@code !x}
*
*
* {@link #equals(Object)}、{@link #hashCode()} 等方法。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java
index 8b1e906..e5d33eb 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java
@@ -3,12 +3,12 @@ package org.jcnc.snow.compiler.parser.ast.base;
/**
* {@code Node} 是抽象语法树(AST)中所有语法节点的统一根接口。
*
- * 作为标记接口(Marker Interface),该接口定义 3 个方法:line()、column() 和 file() 用于定位错误,
- * 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
+ * 作为标记接口(Marker Interface),该接口定义 3 个方法: line()、column() 和 file() 用于定位错误,
+ * 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
*
*
- * - {@link ExpressionNode}:表达式节点,如常量、变量引用、函数调用等
- * - {@link StatementNode}:语句节点,如声明、赋值、条件控制、循环、返回语句等
+ * - {@link ExpressionNode}: 表达式节点,如常量、变量引用、函数调用等
+ * - {@link StatementNode}: 语句节点,如声明、赋值、条件控制、循环、返回语句等
* - 模块、函数、参数等高层结构节点
*
*
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java b/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java
index 93f3547..edf7cad 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java
@@ -70,7 +70,7 @@ public record ParserEngine(ParserContext ctx) {
}
/**
- * 同步:跳过当前行或直到遇到显式注册的顶层关键字。
+ * 同步: 跳过当前行或直到遇到显式注册的顶层关键字。
*
* 该机制用于语法出错后恢复到下一个可能的有效解析点,防止指针停滞导致死循环或重复抛错。
* 同步过程中会优先跳过本行所有未识别 token,并在遇到换行或注册关键字时停止,随后跳过连续空行。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/doc/README.md b/src/main/java/org/jcnc/snow/compiler/parser/doc/README.md
index 3c951d7..401b9be 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/doc/README.md
+++ b/src/main/java/org/jcnc/snow/compiler/parser/doc/README.md
@@ -11,13 +11,13 @@
## 核心功能
-- **抽象语法树(AST)生成**:定义丰富的 AST 节点类型
-- **表达式解析器**:基于 Pratt 解析,支持优先级、调用、成员访问等
-- **语句解析器**:支持 Snow 语言中的声明、控制流等
-- **模块解析器**:处理 `import` 导入声明
-- **函数解析器**:支持函数定义与调用
-- **灵活的解析上下文管理**:错误处理与流式 Token 管理
-- **工具支持**:AST JSON 序列化,便于调试与前后端通信
+- **抽象语法树(AST)生成**: 定义丰富的 AST 节点类型
+- **表达式解析器**: 基于 Pratt 解析,支持优先级、调用、成员访问等
+- **语句解析器**: 支持 Snow 语言中的声明、控制流等
+- **模块解析器**: 处理 `import` 导入声明
+- **函数解析器**: 支持函数定义与调用
+- **灵活的解析上下文管理**: 错误处理与流式 Token 管理
+- **工具支持**: AST JSON 序列化,便于调试与前后端通信
## 模块结构
@@ -39,7 +39,7 @@ parser/
* JDK 24 或更高版本
* Maven 构建管理
-* 推荐 IDE:IntelliJ IDEA
+* 推荐 IDE: IntelliJ IDEA
---
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java
index 113ab94..00382b3 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java
@@ -10,10 +10,10 @@ import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
/**
* {@code UnaryOperatorParselet} —— 前缀一元运算符的 Pratt 解析器。
*
- *
当前 parselet 负责解析两种前缀运算:
+ *
当前 parselet 负责解析两种前缀运算:
*
- * - 取负:{@code -x}
- * - 逻辑非:{@code !x}
+ * - 取负: {@code -x}
+ * - 逻辑非: {@code !x}
*
*
* 解析过程:
@@ -25,7 +25,7 @@ import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
* - 最终生成 {@link UnaryExpressionNode} AST 节点,记录运算符与操作数。
*
此类仅负责语法结构的构建: + *
此类仅负责语法结构的构建: *
- * 不同的实现可以采用不同的解析技术: + * 不同的实现可以采用不同的解析技术: *
- * 每个中缀解析器负责: + * 每个中缀解析器负责: *
* 前缀表达式是以某个词法单元(Token)作为起始的表达式结构, - * 常见类型包括: + * 常见类型包括: *
- * 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分: + * 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分: *
* *- * 每个 {@link SectionDefinition} 包含两个部分:区块起始判断器(基于关键字)与具体的解析逻辑。 + * 每个 {@link SectionDefinition} 包含两个部分: 区块起始判断器(基于关键字)与具体的解析逻辑。 *
* * @param params 参数节点收集容器,解析结果将存入此列表。 @@ -180,7 +180,7 @@ public class FunctionParser implements TopLevelParser { * 解析函数参数列表。 * *- * 支持声明后附加注释,格式示例: + * 支持声明后附加注释,格式示例: *
* parameter:
* declare x: int // 说明文字
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
index 10ca4d5..d46abd3 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
@@ -11,7 +11,7 @@ import java.util.List;
/**
* {@code ImportParser} 类用于解析源码中的 import 导入语句。
*
- * 支持以下格式的语法:
+ * 支持以下格式的语法:
*
* import: module1, module2, module3
*
@@ -23,7 +23,7 @@ public class ImportParser {
/**
* 解析 import 语句,并返回表示被导入模块的语法树节点列表。
*
- * 该方法会依次执行以下操作:
+ * 该方法会依次执行以下操作:
*
* - 确认当前语句以关键字 {@code import} 开头。
* - 确认后跟一个冒号 {@code :}。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java
index fc8ff02..5cc7335 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java
@@ -22,7 +22,7 @@ import java.util.List;
*
*
*
- * 典型模块语法结构:
+ * 典型模块语法结构:
*
* module: mymod
* import ...
@@ -37,7 +37,7 @@ public class ModuleParser implements TopLevelParser {
/**
* 解析一个模块定义块,返回完整的 {@link ModuleNode} 语法树节点。
*
- * 解析过程包括:
+ * 解析过程包括:
*
* - 匹配模块声明起始 {@code module: IDENTIFIER}。
* - 收集模块体内所有 import 和 function 语句,允许穿插空行。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
index a7e6fa3..5cbcc40 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
@@ -10,12 +10,12 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
/**
* {@code DeclarationStatementParser} 类负责解析变量声明语句,是语句级解析器的一部分。
*
- * 本解析器支持以下两种形式的声明语法:
+ * 本解析器支持以下两种形式的声明语法:
*
{@code
* declare myVar:Integer
* declare myVar:Integer = 42 + 3
* }
- * 其中:
+ * 其中:
*
* - {@code myVar} 为变量名(必须为标识符类型);
* - {@code Integer} 为类型标注(必须为类型标记);
@@ -29,7 +29,7 @@ public class DeclarationStatementParser implements StatementParser {
/**
* 解析一条 {@code declare} 声明语句,并返回对应的抽象语法树节点 {@link DeclarationNode}。
*
- * 解析流程如下:
+ * 解析流程如下:
*
* - 匹配关键字 {@code declare};
* - 读取变量名称(标识符类型);
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
index 36af619..7e80851 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
@@ -14,7 +14,7 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
/**
* {@code ExpressionStatementParser} 用于解析通用表达式语句(赋值或普通表达式)。
*
- * 支持以下两种语法结构:
+ * 支持以下两种语法结构:
*
{@code
* x = 1 + 2 // 赋值语句
* doSomething() // 一般表达式语句
@@ -51,7 +51,7 @@ public class ExpressionStatementParser implements StatementParser {
int column = ts.peek().getCol();
String file = ctx.getSourceName();
- // 赋值语句:IDENTIFIER = expr
+ // 赋值语句: IDENTIFIER = expr
if (ts.peek().getType() == TokenType.IDENTIFIER && "=".equals(ts.peek(1).getLexeme())) {
String varName = ts.next().getLexeme();
ts.expect("=");
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java
index 24d6556..aaff612 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java
@@ -15,7 +15,7 @@ import java.util.List;
/**
* {@code IfStatementParser} 类负责解析 if 条件语句,是语句级解析器中的条件分支处理器。
*
- * 本解析器支持以下结构的条件语法:
+ * 本解析器支持以下结构的条件语法:
*
{@code
* if then
*
@@ -23,7 +23,7 @@ import java.util.List;
* ]
* end if
* }
- * 其中:
+ * 其中:
*
* - {@code
} 为任意可解析的布尔或数值表达式,使用 {@link PrattExpressionParser} 解析;
* - {@code
} 与 {@code } 可包含多条语句,自动跳过空行;
@@ -119,7 +119,7 @@ public class IfStatementParser implements StatementParser {
}
// -------------------------
- // 统一结束处理:end if
+ // 统一结束处理: end if
// -------------------------
ts.expect("end");
ts.expect("if");
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java
index 7ffeb74..76bb621 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java
@@ -21,7 +21,7 @@ import java.util.Map;
/**
* {@code LoopStatementParser} 类负责解析自定义结构化的 {@code loop} 语句块。
*
- * 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块:
+ * 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块:
*
{@code
* loop:
* init:
@@ -36,12 +36,12 @@ import java.util.Map;
* end loop
* }
*
- * 各区块说明:
+ * 各区块说明:
*
- * - {@code init}:初始化语句,通常为变量声明。
- * - {@code cond}:循环判断条件,必须为布尔或数值表达式。
- * - {@code step}:每轮执行后更新逻辑,通常为赋值语句。
- * - {@code body}:主执行语句块,支持任意多条语句。
+ * - {@code init}: 初始化语句,通常为变量声明。
+ * - {@code cond}: 循环判断条件,必须为布尔或数值表达式。
+ * - {@code step}: 每轮执行后更新逻辑,通常为赋值语句。
+ * - {@code body}: 主执行语句块,支持任意多条语句。
*
* 本类依赖 {@link FlexibleSectionParser} 实现各区块的统一处理,确保结构明确、可扩展。
*/
@@ -50,7 +50,7 @@ public class LoopStatementParser implements StatementParser {
/**
* 解析 {@code loop} 语句块,构建出对应的 {@link LoopNode} 抽象语法树节点。
*
- * 本方法会按顺序检查各个命名区块(可乱序书写),并分别绑定其对应语义解析器:
+ * 本方法会按顺序检查各个命名区块(可乱序书写),并分别绑定其对应语义解析器:
*
* - 通过 {@link ParserUtils#matchHeader} 匹配区块开头;
* - 通过 {@link FlexibleSectionParser} 派发区块逻辑;
@@ -83,7 +83,7 @@ public class LoopStatementParser implements StatementParser {
// 定义各命名区块的识别与处理逻辑
Map sections = new HashMap<>();
- // init 区块:仅支持一条语句,通常为 declare
+ // init 区块: 仅支持一条语句,通常为 declare
sections.put("init", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("init"),
(ctx1, ts1) -> {
@@ -93,7 +93,7 @@ public class LoopStatementParser implements StatementParser {
}
));
- // cond 区块:支持任意可解析为布尔的表达式
+ // cond 区块: 支持任意可解析为布尔的表达式
sections.put("cond", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("cond"),
(ctx1, ts1) -> {
@@ -104,7 +104,7 @@ public class LoopStatementParser implements StatementParser {
}
));
- // step 区块:目前仅支持单一变量赋值语句
+ // step 区块: 目前仅支持单一变量赋值语句
sections.put("step", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("step"),
(ctx1, ts1) -> {
@@ -122,7 +122,7 @@ public class LoopStatementParser implements StatementParser {
}
));
- // body 区块:支持多条语句,直到遇到 end body
+ // body 区块: 支持多条语句,直到遇到 end body
sections.put("body", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("body"),
(ctx1, ts1) -> {
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java
index 3b4c6c1..f344b80 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java
@@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
/**
* {@code ReturnStatementParser} 负责解析 return 语句,是语句级解析器的一部分。
*
- * 支持以下两种 return 语句形式:
+ * 支持以下两种 return 语句形式:
*
{@code
* return // 无返回值
* return expression // 带返回值
@@ -23,7 +23,7 @@ public class ReturnStatementParser implements StatementParser {
/**
* 解析一条 return 语句,并返回对应的 {@link ReturnNode} 抽象语法树节点。
*
- * 解析逻辑如下:
+ * 解析逻辑如下:
*
* - 匹配起始关键字 {@code return}。
* - 判断其后是否为 {@code NEWLINE},若否则表示存在返回值表达式。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java
index 51ba838..9091af8 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java
@@ -14,7 +14,7 @@ import java.util.*;
* 并可借助 {@code JSONParser.toJson(Object)} 方法将其序列化为 JSON 字符串,用于调试、
* 可视化或跨语言数据传输。
*
- * 支持的节点类型包括(新增对 {@code BoolLiteralNode}、{@code UnaryExpressionNode} 的完整支持):
+ * 支持的节点类型包括(新增对 {@code BoolLiteralNode}、{@code UnaryExpressionNode} 的完整支持):
*
* - {@link ModuleNode}
* - {@link FunctionNode}
@@ -213,7 +213,7 @@ public class ASTJsonSerializer {
"object", exprToMap(object),
"member", member
);
- // 默认兜底处理:只写类型
+ // 默认兜底处理: 只写类型
default -> Map.of("type", expr.getClass().getSimpleName());
};
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java
index 692e5a4..04aeadc 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java
@@ -18,7 +18,7 @@ import java.util.function.Predicate;
*
*
*
- * 典型用途包括:
+ * 典型用途包括:
*
* - 函数体解析中的 {@code params}、{@code returns}、{@code body} 等部分
* - 模块定义中的 {@code imports}、{@code functions} 等部分
@@ -26,7 +26,7 @@ import java.util.function.Predicate;
*
*
*
- * 主要特性:
+ * 主要特性:
*
* - 自动跳过注释与空行
* - 区块入口通过关键字匹配和可选条件判断
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/JSONParser.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/JSONParser.java
index 41eb1fa..84d1823 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/utils/JSONParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/JSONParser.java
@@ -8,14 +8,14 @@ import java.util.Map.Entry;
/**
* JSON 工具类,提供线程安全、可重用的 JSON 解析与序列化能力。
*
- * 主要功能:
+ * 主要功能:
*
- * - 解析:将合法的 JSON 文本转换为 Java 原生对象(Map、List、String、Number、Boolean 或 null)
- * - 序列化:将 Java 原生对象转换为符合 JSON 标准的字符串
+ * - 解析: 将合法的 JSON 文本转换为 Java 原生对象(Map、List、String、Number、Boolean 或 null)
+ * - 序列化: 将 Java 原生对象转换为符合 JSON 标准的字符串
*
*
*
- * 设计要点:
+ * 设计要点:
*
* - 仅提供静态方法入口,无状态,线程安全
* - 解析器内部采用 char[] 缓冲区,支持高性能处理
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/JsonFormatter.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/JsonFormatter.java
index 9ee8744..02eb305 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/utils/JsonFormatter.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/JsonFormatter.java
@@ -8,7 +8,7 @@ public class JsonFormatter {
/**
* 对一个紧凑的 JSON 字符串进行缩进美化。
- * 例如:
+ * 例如:
* {@code
* {"a":1,"b":[2,3]} →
* {
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java
index 3677caf..cce7a9a 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java
@@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.parser.context.TokenStream;
* 提供一系列静态方法用于标准语法结构(如结构头、结构尾)的匹配校验,以及常用的容错处理操作。
* 这些方法可在函数定义、模块定义、循环、条件语句等语法块中复用,有效减少冗余代码,提高解析器稳定性。
*
- * 主要功能包括:
+ *
主要功能包括:
*
* - 匹配结构性语法起始标记(如 {@code loop:}、{@code function:})
* - 匹配结构性语法结尾标记(如 {@code end loop}、{@code end function})
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/AnalyzerRegistry.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/AnalyzerRegistry.java
index 46aad81..d61496c 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/AnalyzerRegistry.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/AnalyzerRegistry.java
@@ -15,7 +15,7 @@ import java.util.Map;
* 它负责根据 AST 节点的类型,查找并返回相应的 {@link StatementAnalyzer} 或 {@link ExpressionAnalyzer} 实例。
* 同时支持注册自定义分析器,并在未找到对应表达式分析器时提供默认兜底处理器。
*
- * 主要职责:
+ * 主要职责:
*
* - 支持注册语句和表达式节点类型对应的分析器;
* - 在语义分析阶段,根据 AST 节点动态查找对应的分析器;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/ExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/ExpressionAnalyzer.java
index df49049..bc01889 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/ExpressionAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/ExpressionAnalyzer.java
@@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
import org.jcnc.snow.compiler.semantic.type.Type;
/**
- * 表达式分析器接口:定义了对 AST 中表达式节点进行语义分析的通用契约。
+ * 表达式分析器接口: 定义了对 AST 中表达式节点进行语义分析的通用契约。
*
* 各种具体的表达式分析器(如调用、二元运算、标识符、字面量等)需实现此接口,
* 在 {@link #analyze(Context, ModuleInfo, FunctionNode, SymbolTable, ExpressionNode)}
@@ -21,7 +21,7 @@ public interface ExpressionAnalyzer {
/**
* 对给定的表达式节点进行语义分析,并返回推导出的类型。
*
- * 实现者应在分析过程中根据节点语义:
+ * 实现者应在分析过程中根据节点语义:
*
* - 校验子表达式类型并递归调用对应的分析器;
* - 检查函数调用、运算符合法性;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/StatementAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/StatementAnalyzer.java
index 7e9d1ca..2d532f0 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/StatementAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/base/StatementAnalyzer.java
@@ -7,11 +7,11 @@ import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
/**
- * 语句分析器接口:定义如何对 AST 中的语句节点执行语义检查。
+ * 语句分析器接口: 定义如何对 AST 中的语句节点执行语义检查。
*
* 各具体的语句分析器(如声明、赋值、分支、循环、返回等)需实现此接口,
* 在 {@link #analyze(Context, ModuleInfo, FunctionNode, SymbolTable, StatementNode)}
- * 方法中完成:
+ * 方法中完成:
*
* - 对自身语义结构进行校验(变量声明、类型匹配、作用域检查等);
* - 递归调用其他已注册的语句或表达式分析器;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java
index c14b83b..672bc47 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/BinaryExpressionAnalyzer.java
@@ -13,7 +13,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code BinaryExpressionAnalyzer} 负责对二元表达式做语义分析并返回其类型。
*
- * 支持特性:
+ * 支持特性:
* 1. 字符串拼接「+」
* 2. 数值运算与自动宽化
* 3. 比较 / 关系运算
@@ -44,20 +44,20 @@ public class BinaryExpressionAnalyzer implements ExpressionAnalyzer>===!=").contains(op)) {
if (left.isNumeric() && right.isNumeric()) {
// 自动数值宽化(如 int + float → float)
@@ -72,7 +72,7 @@ public class BinaryExpressionAnalyzer implements ExpressionAnalyzer
- * 它负责处理类似 {@code callee(arg1, arg2, ...)} 形式的调用表达式,执行如下操作:
+ * 它负责处理类似 {@code callee(arg1, arg2, ...)} 形式的调用表达式,执行如下操作:
*
* - 识别调用目标(支持模块成员函数调用和当前模块函数调用);
* - 根据被调用函数的参数签名检查实参数量和类型的兼容性;
@@ -51,7 +51,7 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer
* 它的主要职责是在给定的局部作用域中查找标识符对应的符号定义,并返回其类型信息。
- * 如果标识符未在当前作用域内声明,则:
+ * 如果标识符未在当前作用域内声明,则:
*
* - 向语义错误列表中添加一条 {@link SemanticError} 记录;
* - 为保证分析过程的连续性,默认返回 {@link BuiltinType#INT} 类型作为降级处理。
@@ -46,7 +46,7 @@ public class IdentifierAnalyzer implements ExpressionAnalyzer {
// 在当前作用域中查找符号(变量或常量)
Symbol sym = locals.resolve(id.name());
if (sym == null) {
- // 未声明标识符:记录语义错误,返回降级类型
+ // 未声明标识符: 记录语义错误,返回降级类型
ctx.getErrors().add(new SemanticError(id,
"未声明的标识符: " + id.name()));
ctx.log("错误: 未声明的标识符 " + id.name());
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NumberLiteralAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NumberLiteralAnalyzer.java
index a59fadd..b26b2c7 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NumberLiteralAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NumberLiteralAnalyzer.java
@@ -12,18 +12,18 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code NumberLiteralAnalyzer} 用于对数字字面量表达式进行语义分析并推断其精确类型。
*
- * 类型判定逻辑如下:
+ * 类型判定逻辑如下:
*
- * - 首先检查字面量末尾是否带有类型后缀(不区分大小写):
+ *
- 首先检查字面量末尾是否带有类型后缀(不区分大小写):
*
- * - {@code b}:byte 类型({@link BuiltinType#BYTE})
- * - {@code s}:short 类型({@link BuiltinType#SHORT})
- * - {@code l}:long 类型({@link BuiltinType#LONG})
- * - {@code f}:float 类型({@link BuiltinType#FLOAT})
- * - {@code d}:double 类型({@link BuiltinType#DOUBLE})
+ * - {@code b}: byte 类型({@link BuiltinType#BYTE})
+ * - {@code s}: short 类型({@link BuiltinType#SHORT})
+ * - {@code l}: long 类型({@link BuiltinType#LONG})
+ * - {@code f}: float 类型({@link BuiltinType#FLOAT})
+ * - {@code d}: double 类型({@link BuiltinType#DOUBLE})
*
*
- * - 若无后缀,则:
+ *
- 若无后缀,则:
*
* - 只要文本中包含 {@code '.'} 或 {@code e/E},即判为 double 类型
* - 否则默认判为 int 类型
@@ -37,7 +37,7 @@ public class NumberLiteralAnalyzer implements ExpressionAnalyzer
- * 分析流程:
+ * 分析流程:
*
* - 若字面量以后缀结尾,直接按后缀映射类型。
* - 否则,若含有小数点或科学计数法标记,则为 double,否则为 int。
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/StringLiteralAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/StringLiteralAnalyzer.java
index 518fa93..86412e5 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/StringLiteralAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/StringLiteralAnalyzer.java
@@ -15,7 +15,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
* 负责分析源代码中的字符串字面量(例如 {@code "hello"}、{@code ""} 等),
* 并确定其类型。根据语言规范,所有字符串字面量默认视为 {@link BuiltinType#STRING} 类型。
*
- * 特点如下:
+ * 特点如下:
*
* - 不依赖符号表、函数上下文或模块信息,属于上下文无关表达式分析器;
* - 恒定返回 {@code STRING} 类型;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java
index 53f6c8f..b5d5217 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java
@@ -13,16 +13,16 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code UnaryExpressionAnalyzer} — 一元表达式的语义分析器。
*
- * 目前实现两种一元运算:
+ *
目前实现两种一元运算:
*
- * - {@code -x} 取负:仅允许作用于数值类型(int / float 等)。
- * - {@code !x} 逻辑非:仅允许作用于 {@code boolean} 类型。
+ * - {@code -x} 取负: 仅允许作用于数值类型(int / float 等)。
+ * - {@code !x} 逻辑非: 仅允许作用于 {@code boolean} 类型。
*
*
- * 分析流程:
+ *
分析流程:
*
* - 递归分析操作数表达式,获取其类型 {@code operandType}。
- * - 根据运算符检查类型合法性:
+ *
- 根据运算符检查类型合法性:
*
* - 若类型不符,记录 {@link SemanticError} 并返回一个占位类型
* (取负返回 {@link BuiltinType#INT},逻辑非返回
@@ -77,7 +77,7 @@ public class UnaryExpressionAnalyzer implements ExpressionAnalyzer
- * 特性说明:
+ * 特性说明:
*
* - 适用于所有未知或暂未实现的表达式类型;
* - 自动记录语义错误并打印日志,方便定位与扩展;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java
index 91056b5..3cd43f4 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/AssignmentAnalyzer.java
@@ -12,7 +12,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code AssignmentAnalyzer} 是赋值语句的语义分析器。
*
- * 负责分析和验证赋值语句的合法性,包括:
+ * 负责分析和验证赋值语句的合法性,包括:
*
* - 变量是否已声明且可赋值(必须为 {@link SymbolKind#VARIABLE} 类型);
* - 赋值右值的类型是否与变量类型兼容;
@@ -54,7 +54,7 @@ public class AssignmentAnalyzer implements StatementAnalyzer {
Type valType = ctx.getRegistry().getExpressionAnalyzer(asg.value())
.analyze(ctx, mi, fn, locals, asg.value());
- // 类型检查:若类型不兼容,则尝试判断是否允许宽化转换
+ // 类型检查: 若类型不兼容,则尝试判断是否允许宽化转换
if (!sym.type().isCompatible(valType)) {
// 数值类型允许自动宽化转换(如 int → double)
if (!(sym.type().isNumeric() && valType.isNumeric()
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java
index f20b55f..6a5eb93 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/DeclarationAnalyzer.java
@@ -13,12 +13,12 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code DeclarationAnalyzer} 是变量声明语句的语义分析器。
*
- * 它负责处理类似 {@code int x = 10;} 的声明语句,具体分析内容包括:
+ * 它负责处理类似 {@code int x = 10;} 的声明语句,具体分析内容包括:
*
- * - 类型解析:将声明中的类型字符串转换为语义层的 {@link Type} 对象;
- * - 符号定义:将变量注册到当前作用域的 {@link SymbolTable} 中;
- * - 重复定义检查:防止同一作用域下的变量名冲突;
- * - 初始化表达式类型校验:检查类型兼容性,支持数值类型宽化(如 int → float)。
+ * - 类型解析: 将声明中的类型字符串转换为语义层的 {@link Type} 对象;
+ * - 符号定义: 将变量注册到当前作用域的 {@link SymbolTable} 中;
+ * - 重复定义检查: 防止同一作用域下的变量名冲突;
+ * - 初始化表达式类型校验: 检查类型兼容性,支持数值类型宽化(如 int → float)。
*
* 若出现类型未识别、重复声明或类型不兼容等问题,将向语义错误列表添加对应错误信息。
*/
@@ -47,7 +47,7 @@ public class DeclarationAnalyzer implements StatementAnalyzer {
"未知类型: " + decl.getType()));
ctx.log("错误: 未知类型 " + decl.getType()
+ " 在声明 " + decl.getName());
- varType = BuiltinType.INT; // 容错处理:默认降级为 int
+ varType = BuiltinType.INT; // 容错处理: 默认降级为 int
}
ctx.log("声明变量: " + decl.getName()
+ " 类型: " + varType);
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java
index 8b82080..48dae2f 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java
@@ -13,14 +13,14 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code IfAnalyzer} 用于分析 if 语句的语义正确性。
*
- * 主要职责如下:
+ * 主要职责如下:
*
- * - 条件表达式类型检查:确认 if 的条件表达式类型为 boolean,否则记录语义错误。
- * - 块级作用域:分别为 then 分支和 else 分支创建独立的符号表(SymbolTable),
+ *
- 条件表达式类型检查: 确认 if 的条件表达式类型为 boolean,否则记录语义错误。
+ * - 块级作用域: 分别为 then 分支和 else 分支创建独立的符号表(SymbolTable),
* 支持分支内变量的块级作用域,防止分支内声明的变量污染外部或互相干扰,允许分支内变量同名遮蔽。
- * - 分支递归分析:对 then 和 else 分支的每条语句递归调用对应的语义分析器,进行语义检查。
- * - 错误记录:若遇到条件类型不符、不支持的语句类型或分支内部其他语义问题,均通过 {@link SemanticError} 记录详细错误信息,并附带代码位置信息。
- * - 健壮性:不会因一处错误立即终止,而是尽量分析全部分支,收集所有能发现的错误,一次性输出。
+ * - 分支递归分析: 对 then 和 else 分支的每条语句递归调用对应的语义分析器,进行语义检查。
+ * - 错误记录: 若遇到条件类型不符、不支持的语句类型或分支内部其他语义问题,均通过 {@link SemanticError} 记录详细错误信息,并附带代码位置信息。
+ * - 健壮性: 不会因一处错误立即终止,而是尽量分析全部分支,收集所有能发现的错误,一次性输出。
*
*
* 该分析器提升了语言的健壮性与可维护性,是支持 SCompiler 块级作用域及全局错误收集能力的关键一环。
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java
index 064d059..9219705 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java
@@ -13,7 +13,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code LoopAnalyzer} 用于分析 for/while 等循环结构的语义正确性。
*
- * 主要职责如下:
+ * 主要职责如下:
*
* - 为整个循环体(包括初始化、条件、更新、循环体本身)创建独立的块级符号表(作用域),保证循环内变量与外部隔离。
* - 依次分析初始化语句、条件表达式、更新语句和循环体各语句,并递归检查嵌套的语法结构。
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ReturnAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ReturnAnalyzer.java
index 3908909..35f2fcf 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ReturnAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ReturnAnalyzer.java
@@ -14,7 +14,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
/**
* {@code ReturnAnalyzer} 是用于分析 {@link ReturnNode} 返回语句的语义分析器。
*
- * 它负责检查函数中的 return 语句是否与函数定义的返回类型匹配。分析流程包括:
+ * 它负责检查函数中的 return 语句是否与函数定义的返回类型匹配。分析流程包括:
*
* - 获取当前函数的返回类型 {@link FunctionType#returnType()};
* - 若 return 语句包含返回值表达式,检查其类型与函数定义是否兼容;
@@ -48,7 +48,7 @@ public class ReturnAnalyzer implements StatementAnalyzer {
.getFunctions()
.get(fn.name());
- // 情况 1:存在返回表达式,需进行类型检查
+ // 情况 1: 存在返回表达式,需进行类型检查
ret.getExpression().ifPresentOrElse(exp -> {
var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(exp);
Type actual = exprAnalyzer.analyze(ctx, mi, fn, locals, exp);
@@ -64,7 +64,7 @@ public class ReturnAnalyzer implements StatementAnalyzer {
ctx.log("错误: return 类型不匹配");
}
- // 情况 2:无返回表达式,但函数定义了非 void 返回类型
+ // 情况 2: 无返回表达式,但函数定义了非 void 返回类型
}, () -> {
if (expected.returnType() != BuiltinType.VOID) {
ctx.getErrors().add(new SemanticError(
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java
index c8de9e0..47af0c2 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java
@@ -12,7 +12,7 @@ import org.jcnc.snow.compiler.semantic.analyzers.statement.*;
* 本类为静态工具类,不可实例化,其唯一公开方法 {@link #registerAll(AnalyzerRegistry)}
* 应在语义分析初始化阶段调用一次,确保所有节点类型都能正确分发到对应分析器。
*
- * 注册内容包括:
+ * 注册内容包括:
*
* - 所有标准语句节点(如变量声明、赋值、条件、循环、返回等)的分析器;
* - 所有标准表达式节点(如字面量、标识符、函数调用、二元表达式等)的分析器;
@@ -41,7 +41,7 @@ public final class AnalyzerRegistrar {
registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer());
registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer());
- // 特殊处理:表达式语句(如 "foo();")作为语句包装表达式
+ // 特殊处理: 表达式语句(如 "foo();")作为语句包装表达式
registry.registerStatementAnalyzer(ExpressionStatementNode.class,
(ctx, mi, fn, locals, stmt) ->
registry.getExpressionAnalyzer(stmt.expression())
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
index 498f4a9..d1566ab 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
@@ -7,7 +7,7 @@ import java.util.Map;
/**
* {@code BuiltinTypeRegistry} 是内置类型和内置模块的集中注册中心。
*
- * 本类主要负责:
+ * 本类主要负责:
*
* - 定义语言中所有可识别的基础类型(如 int、float、string 等);
* - 在语义分析初始化时,将内置模块(如 {@code BuiltinUtils})注册到上下文中;
@@ -18,7 +18,7 @@ import java.util.Map;
public final class BuiltinTypeRegistry {
/**
- * 内置类型映射表:将类型名称字符串映射到对应的 {@link Type} 实例。
+ * 内置类型映射表: 将类型名称字符串映射到对应的 {@link Type} 实例。
*
* 用于类型解析过程(如解析变量声明或函数返回类型)中,
* 将用户源码中的类型字符串转换为语义类型对象。
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/Context.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/Context.java
index 2d051cb..881f083 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/Context.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/Context.java
@@ -10,25 +10,25 @@ import java.util.Map;
/**
* {@code Context} 表示语义分析阶段的共享上下文环境。
*
- * 它贯穿整个语义分析流程,用于维护并提供以下核心服务:
+ * 它贯穿整个语义分析流程,用于维护并提供以下核心服务:
*
- * - 模块信息管理:包含所有已加载模块(源模块与内置模块);
- * - 错误收集:集中存储语义分析期间产生的 {@link SemanticError};
- * - 日志控制:支持按需输出详细调试日志;
- * - 分析器调度:通过 {@link AnalyzerRegistry} 管理语句/表达式的分析器分发。
+ * - 模块信息管理: 包含所有已加载模块(源模块与内置模块);
+ * - 错误收集: 集中存储语义分析期间产生的 {@link SemanticError};
+ * - 日志控制: 支持按需输出详细调试日志;
+ * - 分析器调度: 通过 {@link AnalyzerRegistry} 管理语句/表达式的分析器分发。
*
*/
public class Context {
- /** 模块表:模块名 → {@link ModuleInfo},用于模块查找与跨模块引用 */
+ /** 模块表: 模块名 → {@link ModuleInfo},用于模块查找与跨模块引用 */
private final Map modules;
- /** 错误列表:语义分析过程中收集的所有 {@link SemanticError} */
+ /** 错误列表: 语义分析过程中收集的所有 {@link SemanticError} */
private final List errors;
- /** 日志开关:若为 true,将启用 {@link #log(String)} 输出日志信息 */
+ /** 日志开关: 若为 true,将启用 {@link #log(String)} 输出日志信息 */
private final boolean verbose;
- /** 语义分析器注册表:用于按节点类型动态调度分析器 */
+ /** 语义分析器注册表: 用于按节点类型动态调度分析器 */
private final AnalyzerRegistry registry;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java
index 66385b6..0803ee0 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java
@@ -16,7 +16,7 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType;
* 它逐个遍历所有模块中的函数定义,并对函数体中的每一条语句调用对应的语义分析器,
* 执行类型检查、作用域验证、错误记录等任务。
*
- * 核心职责包括:
+ * 核心职责包括:
*
* - 为每个函数构建局部符号表并注册函数参数为变量;
* - 分发函数体语句至相应的 {@link StatementAnalyzer};
@@ -39,7 +39,7 @@ public record FunctionChecker(Context ctx) {
/**
* 执行函数体检查流程。
*
- * 对所有模块中的所有函数依次进行处理:
+ * 对所有模块中的所有函数依次进行处理:
*
* - 查找模块对应的 {@link ModuleInfo};
* - 创建函数局部符号表 {@link SymbolTable},并注册所有参数变量;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/ModuleInfo.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/ModuleInfo.java
index 074e8fa..0761d50 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/ModuleInfo.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/ModuleInfo.java
@@ -10,7 +10,7 @@ import java.util.*;
* 用于在分析期间管理模块间依赖、函数签名查找等关键任务。
* 每个模块对应一个唯一的 {@code ModuleInfo} 实例。
*
- * 包含信息包括:
+ * 包含信息包括:
*
* - 模块名称(唯一标识);
* - 该模块导入的其他模块名集合;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzer.java
index c3a1493..8bdc377 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzer.java
@@ -12,20 +12,20 @@ import java.util.*;
* 它负责统一协调模块注册、函数签名登记和函数体语义检查等子任务,构建并维护语义上下文 {@link Context},
* 并最终输出所有收集到的语义错误列表 {@link SemanticError}。
*
- * 语义分析流程分为三个阶段:
+ * 语义分析流程分为三个阶段:
*
- * - 模块注册:将所有用户模块的名称添加至全局模块表中,供后续导入检查与引用;
- * - 函数签名注册:提取函数定义的签名(名称与类型),填入每个模块对应的 {@link ModuleInfo};
- * - 函数体检查:遍历每个函数体,对所有语句与表达式执行类型检查和语义验证。
+ * - 模块注册: 将所有用户模块的名称添加至全局模块表中,供后续导入检查与引用;
+ * - 函数签名注册: 提取函数定义的签名(名称与类型),填入每个模块对应的 {@link ModuleInfo};
+ * - 函数体检查: 遍历每个函数体,对所有语句与表达式执行类型检查和语义验证。
*
*
- * 内部使用组件:
+ * 内部使用组件:
*
- * - {@link ModuleRegistry}:注册用户模块;
- * - {@link SignatureRegistrar}:提取函数签名;
- * - {@link FunctionChecker}:分析函数体内语句;
- * - {@link BuiltinTypeRegistry}:初始化内置模块和类型;
- * - {@link AnalyzerRegistrar}:注册语句和表达式分析器。
+ * - {@link ModuleRegistry}: 注册用户模块;
+ * - {@link SignatureRegistrar}: 提取函数签名;
+ * - {@link FunctionChecker}: 分析函数体内语句;
+ * - {@link BuiltinTypeRegistry}: 初始化内置模块和类型;
+ * - {@link AnalyzerRegistrar}: 注册语句和表达式分析器。
*
*/
public class SemanticAnalyzer {
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzerRunner.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzerRunner.java
index 0998114..1175054 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzerRunner.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/SemanticAnalyzerRunner.java
@@ -11,14 +11,14 @@ import java.util.stream.Collectors;
/**
* {@code SemanticAnalyzerRunner} 是语义分析阶段的统一入口与调度器。
*
- * 功能职责:
+ * 功能职责:
*
* - 从原始 AST 列表中过滤并收集所有 {@link ModuleNode} 节点,作为模块分析的起点;
* - 调用 {@link SemanticAnalyzer} 对所有模块节点执行完整语义分析流程;
* - 汇总并报告所有 {@link SemanticError};如有语义错误,自动中止编译流程,防止后续崩溃。
*
*
- * 推荐使用方式:
+ * 推荐使用方式:
*
* SemanticAnalyzerRunner.runSemanticAnalysis(ast, true);
*
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java
index 1b6fc50..e542646 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java
@@ -16,7 +16,7 @@ import java.util.Optional;
/**
* {@code SignatureRegistrar} 负责函数签名登记与导入语义检查。
*
- * 在语义分析初期阶段,它遍历每个模块,完成以下任务:
+ * 在语义分析初期阶段,它遍历每个模块,完成以下任务:
*
* - 验证所有 {@link ImportNode} 导入的模块是否存在于全局模块表 {@link Context#modules()} 中;
* - 将每个 {@link FunctionNode} 的函数签名(参数类型和返回类型)注册到对应 {@link ModuleInfo} 中;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md b/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md
index 8cf0afe..4359674 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md
@@ -11,11 +11,11 @@
## 核心功能
-- **表达式与语句语义分析**:根据 Snow 语言规范校验各类 AST 节点
-- **符号表管理**:支持作用域嵌套、符号绑定与查找
-- **类型系统**:内建基础类型与函数类型推导
-- **语义错误报告**:标准化错误收集与输出
-- **可扩展的分析器体系**:按节点类型组织,便于维护与扩展
+- **表达式与语句语义分析**: 根据 Snow 语言规范校验各类 AST 节点
+- **符号表管理**: 支持作用域嵌套、符号绑定与查找
+- **类型系统**: 内建基础类型与函数类型推导
+- **语义错误报告**: 标准化错误收集与输出
+- **可扩展的分析器体系**: 按节点类型组织,便于维护与扩展
## 模块结构
@@ -36,6 +36,6 @@ semantic/
* JDK 24 或更高版本
* Maven 构建管理
-* 推荐 IDE:IntelliJ IDEA
+* 推荐 IDE: IntelliJ IDEA
---
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java b/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java
index 74ef6b4..ce7bfc4 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java
@@ -14,7 +14,7 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
* - 避免直接输出 AST 节点的默认
toString() 形式。
*
*
- * 示例输出:
+ * 示例输出:
*
* D:\Devs\IdeaProjects\Snow\playground\Main.snow: 行 7, 列 28: 参数类型不匹配 (位置 1): 期望 int, 实际 long
*
@@ -26,7 +26,7 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
public record SemanticError(Node node, String message) {
/**
- * 返回该语义错误的字符串描述,格式如下:
+ * 返回该语义错误的字符串描述,格式如下:
*
* [文件绝对路径: ]行 X, 列 Y: [错误信息]
*
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java
index f6cc9dc..45fa482 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java
@@ -6,11 +6,11 @@ import org.jcnc.snow.compiler.semantic.type.Type;
* {@code Symbol} 表示符号表中的一条符号记录,描述语言中命名实体的语义信息。
*
* 符号是语义分析中的基础单元,通常用于表示变量、函数、参数等具名元素。
- * 每个符号具备以下三个核心属性:
+ * 每个符号具备以下三个核心属性:
*
- * - name:符号的名称,例如变量名或函数名;
- * - type:符号的类型信息,通常为 {@link Type} 的子类实例;
- * - kind:符号的种类,由 {@link SymbolKind} 枚举表示(例如 VARIABLE、FUNCTION 等)。
+ * - name: 符号的名称,例如变量名或函数名;
+ * - type: 符号的类型信息,通常为 {@link Type} 的子类实例;
+ * - kind: 符号的种类,由 {@link SymbolKind} 枚举表示(例如 VARIABLE、FUNCTION 等)。
*
* - 构造器 {@code Symbol(String, Type, SymbolKind)};
* - 访问器方法 {@code name()}, {@code type()}, {@code kind()};
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolKind.java b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolKind.java
index 625b2f4..5034d59 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolKind.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolKind.java
@@ -3,14 +3,14 @@ package org.jcnc.snow.compiler.semantic.symbol;
/**
* {@code SymbolKind} 枚举用于标识符号表中不同类型的命名实体。
*
- * 在语义分析过程中,编译器需要根据符号的种类(Kind)采用不同的处理策略:
+ * 在语义分析过程中,编译器需要根据符号的种类(Kind)采用不同的处理策略:
* 例如变量参与类型推导、函数用于调用匹配、模块用于跨作用域引用等。
*
- * 当前支持的符号种类包括:
+ * 当前支持的符号种类包括:
*
- * - {@link #VARIABLE}:变量符号(局部变量、全局变量、成员变量等);
- * - {@link #FUNCTION}:函数符号(自由函数、方法、构造函数等);
- * - {@link #MODULE}:模块符号(代表命名空间、库或逻辑模块);
+ * - {@link #VARIABLE}: 变量符号(局部变量、全局变量、成员变量等);
+ * - {@link #FUNCTION}: 函数符号(自由函数、方法、构造函数等);
+ * - {@link #MODULE}: 模块符号(代表命名空间、库或逻辑模块);
*
*/
public enum SymbolKind {
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolTable.java b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolTable.java
index 29f81ab..1438bf6 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolTable.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/SymbolTable.java
@@ -9,7 +9,7 @@ import java.util.Map;
* 本类支持嵌套作用域结构(Nested Scope),适用于块级作用域、函数作用域、模块作用域等语义环境建模。
* 每个符号表可挂接一个“父作用域”,以支持多层级作用域链上的符号解析。
*
- * 核心特性包括:
+ *
核心特性包括:
*
* - 符号定义(局部作用域内唯一);
* - 符号查找(向上查找父作用域);
@@ -53,7 +53,7 @@ public class SymbolTable {
/**
* 根据名称解析符号,支持作用域链向上递归查找。
- * 查找策略:
+ *
查找策略:
*
* - 优先在当前作用域中查找该符号名称;
* - 若未找到且存在父作用域,则递归向上查找;
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java b/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java
index 213cd80..48170f5 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/type/BuiltinType.java
@@ -6,7 +6,7 @@ package org.jcnc.snow.compiler.semantic.type;
* 类型涵盖整数、浮点、字符串及 void 类型,广泛应用于变量声明、
* 表达式类型推导、函数签名、类型检查等语义分析环节。
*
- * 支持的类型包括:
+ *
支持的类型包括:
*
* - {@link #BYTE} - 8 位整数
* - {@link #SHORT} - 16 位整数
@@ -19,7 +19,7 @@ package org.jcnc.snow.compiler.semantic.type;
* - {@link #VOID} - 空类型,用于表示无返回值的函数
*
*
- * 每个枚举实例实现了 {@link Type} 接口,提供以下语义特性:
+ *
每个枚举实例实现了 {@link Type} 接口,提供以下语义特性:
*
* - 数值类型判断 {@link #isNumeric()};
* - 类型兼容性判断 {@link #isCompatible(Type)};
@@ -41,7 +41,7 @@ public enum BuiltinType implements Type {
/**
* 判断当前类型是否与指定类型兼容。
*
- * 兼容判断规则:
+ * 兼容判断规则:
*
* - 类型完全相同,视为兼容;
* - 对于数值类型,若目标类型为宽类型(如 int → double),视为兼容;
@@ -64,7 +64,7 @@ public enum BuiltinType implements Type {
/**
* 判断当前类型是否为数值类型。
*
- * 数值类型包括:
+ * 数值类型包括:
* {@link #BYTE}、{@link #SHORT}、{@link #INT}、{@link #LONG}、
* {@link #FLOAT}、{@link #DOUBLE}。
*
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java b/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java
index 3eecaa4..e3c3880 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java
@@ -8,19 +8,19 @@ import java.util.Objects;
*
* 适用于函数声明、函数调用、类型检查等语义分析场景。
*
- * 例如,一个函数接受两个 {@code int} 参数并返回 {@code string},其函数类型为:
+ * 例如,一个函数接受两个 {@code int} 参数并返回 {@code string},其函数类型为:
*
* (int, int) -> string
*
*
- * 该类使用 Java 16+ {@code record} 语法定义,自动提供:
+ *
该类使用 Java 16+ {@code record} 语法定义,自动提供:
*
* - 构造方法;
* - 访问器 {@code paramTypes()} 和 {@code returnType()};
* - {@code equals()}, {@code hashCode()}, {@code toString()} 方法;
*
*
- * 实现接口:{@link Type}
+ *
实现接口: {@link Type}
*
* @param paramTypes 参数类型列表(顺序敏感,不可为 null)
* @param returnType 返回类型(不可为 null)
@@ -43,7 +43,7 @@ public record FunctionType(List paramTypes, Type returnType) implements Ty
/**
* 判断当前函数类型是否与另一个类型兼容。
*
- * 兼容条件:
+ * 兼容条件:
*
* - 对方也是 {@code FunctionType};
* - 返回类型兼容(可宽化或完全匹配);
@@ -62,7 +62,7 @@ public record FunctionType(List paramTypes, Type returnType) implements Ty
/**
* 返回函数类型的标准字符串表示形式。
*
- * 格式为:
+ * 格式为:
*
* (param1, param2, ...) -> returnType
*
@@ -78,7 +78,7 @@ public record FunctionType(List paramTypes, Type returnType) implements Ty
/**
* 判断两个函数类型是否相等。
*
- * 相等条件为:
+ * 相等条件为:
*
* - 引用相同;
* - 或参数类型列表完全相等,且返回类型也相等。
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java b/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java
index deecc05..fc7798f 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/type/Type.java
@@ -1,7 +1,7 @@
package org.jcnc.snow.compiler.semantic.type;
/**
- * 类型接口:所有类型(包括内置类型、函数类型等)均需实现此接口,
+ * 类型接口: 所有类型(包括内置类型、函数类型等)均需实现此接口,
* 用于在语义分析中进行类型兼容性检查和统一表示。
*/
public interface Type {
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
index 91b4487..edeb9a5 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
@@ -7,7 +7,7 @@ import java.util.List;
/**
* {@code SemanticAnalysisReporter} 用于在语义分析结束后汇总并打印所有收集到的
* {@link SemanticError}。为了同时满足“完整错误收集”与“按需快速失败”两种使用场景,
- * 现在提供两个公共 API:
+ * 现在提供两个公共 API:
*
* - {@link #report(List)} ‑ 仅打印,不终止;
* - {@link #reportAndExitIfNecessary(List)} ‑ 若存在错误则 打印并退出。
@@ -25,7 +25,7 @@ public final class SemanticAnalysisReporter {
*/
public static void report(List errors) {
if (hasErrors(errors)) {
- System.err.println("语义分析发现 " + errors.size() + " 个错误:");
+ System.err.println("语义分析发现 " + errors.size() + " 个错误: ");
errors.forEach(err -> System.err.println(" " + err));
} else {
System.out.println("\n## 语义分析通过,没有发现错误\n");
diff --git a/src/main/java/org/jcnc/snow/pkg/doc/README.md b/src/main/java/org/jcnc/snow/pkg/doc/README.md
index ec50ed5..d51a16b 100644
--- a/src/main/java/org/jcnc/snow/pkg/doc/README.md
+++ b/src/main/java/org/jcnc/snow/pkg/doc/README.md
@@ -4,15 +4,15 @@
## 项目简介
-**包管理模块(pkg)** 是 Snow 构建工具的关键组成部分,承担“从配置到产物” 的整条流水线:
+**包管理模块(pkg)** 是 Snow 构建工具的关键组成部分,承担“从配置到产物” 的整条流水线:
-1. **DSL 解析**:读取并解析 `.cloud` 配置文件,生成统一的项目/依赖/构建配置模型;
-2. **生命周期编排**:按 *INIT → RESOLVE\_DEPENDENCIES → COMPILE → PACKAGE → PUBLISH → CLEAN* 的顺序驱动构建流程;
-3. **依赖解析与缓存**:按需下载缺失依赖并存入本地缓存,离线优先;
-4. **任务执行**:在各生命周期阶段调用对应 `Task` 实现(清理、编译、打包、发布等);
-5. **配置模板展开**:支持在配置中使用 `@{key}` 形式的占位符,并在构建前统一替换。
+1. **DSL 解析**: 读取并解析 `.cloud` 配置文件,生成统一的项目/依赖/构建配置模型;
+2. **生命周期编排**: 按 *INIT → RESOLVE\_DEPENDENCIES → COMPILE → PACKAGE → PUBLISH → CLEAN* 的顺序驱动构建流程;
+3. **依赖解析与缓存**: 按需下载缺失依赖并存入本地缓存,离线优先;
+4. **任务执行**: 在各生命周期阶段调用对应 `Task` 实现(清理、编译、打包、发布等);
+5. **配置模板展开**: 支持在配置中使用 `@{key}` 形式的占位符,并在构建前统一替换。
-整个模块强调 **可扩展性** 与 **内聚职责**:DSL → Model、Lifecycle → Task、Resolver → Repository 各自解耦,可独立演进。
+整个模块强调 **可扩展性** 与 **内聚职责**: DSL → Model、Lifecycle → Task、Resolver → Repository 各自解耦,可独立演进。
## 核心功能
@@ -61,4 +61,4 @@ pkg/
* JDK 24 或更高版本
* Maven 构建管理
-* 推荐 IDE:IntelliJ IDEA
\ No newline at end of file
+* 推荐 IDE: IntelliJ IDEA
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/pkg/dsl/CloudDSLParser.java b/src/main/java/org/jcnc/snow/pkg/dsl/CloudDSLParser.java
index 301e11d..195b6ac 100644
--- a/src/main/java/org/jcnc/snow/pkg/dsl/CloudDSLParser.java
+++ b/src/main/java/org/jcnc/snow/pkg/dsl/CloudDSLParser.java
@@ -19,11 +19,11 @@ import java.util.regex.Pattern;
* - 顶级区块(如 project、properties、repositories、dependencies、build)以
sectionName { 开始,以 } 结束
* - 区块内部只识别
key = value 赋值,行尾可有 # 注释
* - build 区块支持嵌套,内部键通过
. 展平,例如 compile.enabled = true
- * - 新增:对
"value" 或 'value' 形式的字面量自动去引号,调用方得到的均是不含引号的裸字符串
+ * - 新增: 对
"value" 或 'value' 形式的字面量自动去引号,调用方得到的均是不含引号的裸字符串
*
*
*
- * 示例 .cloud 文件片段:
+ * 示例 .cloud 文件片段:
* project {
* group = com.example
* artifact = "demo-app"
@@ -117,7 +117,7 @@ public final class CloudDSLParser {
// 检查区块是否全部闭合
if (!sectionStack.isEmpty()) {
- throw new IllegalStateException("文件结束但区块未闭合:" + sectionStack);
+ throw new IllegalStateException("文件结束但区块未闭合: " + sectionStack);
}
// 构建 Project 模型
diff --git a/src/main/java/org/jcnc/snow/pkg/lifecycle/LifecycleManager.java b/src/main/java/org/jcnc/snow/pkg/lifecycle/LifecycleManager.java
index 6c1b5db..6942871 100644
--- a/src/main/java/org/jcnc/snow/pkg/lifecycle/LifecycleManager.java
+++ b/src/main/java/org/jcnc/snow/pkg/lifecycle/LifecycleManager.java
@@ -13,7 +13,7 @@ import java.util.Map;
*
*
*
- * 示例用法:
+ * 示例用法:
* LifecycleManager manager = new LifecycleManager();
* manager.register(LifecyclePhase.INIT, new InitTask());
* manager.executeAll();
diff --git a/src/main/java/org/jcnc/snow/pkg/model/Dependency.java b/src/main/java/org/jcnc/snow/pkg/model/Dependency.java
index 481682e..3b23a91 100644
--- a/src/main/java/org/jcnc/snow/pkg/model/Dependency.java
+++ b/src/main/java/org/jcnc/snow/pkg/model/Dependency.java
@@ -11,7 +11,7 @@ import java.util.regex.Pattern;
*
*
*
- * 示例用法:
+ * 示例用法:
* Dependency dep = Dependency.fromString(
* "core", "com.example:core:@{version}",
* Map.of("version", "1.2.3")
@@ -62,8 +62,8 @@ public record Dependency(
/**
* 生成依赖对应的源码文件路径。
*
- * 路径格式:groupId/artifactId/version/artifactId.snow
- * 例如:com/example/core/1.2.3/core.snow
+ * 路径格式: groupId/artifactId/version/artifactId.snow
+ * 例如: com/example/core/1.2.3/core.snow
*
*
* @return 仓库源码文件的相对路径
diff --git a/src/main/java/org/jcnc/snow/pkg/model/Project.java b/src/main/java/org/jcnc/snow/pkg/model/Project.java
index efedc97..a46aa19 100644
--- a/src/main/java/org/jcnc/snow/pkg/model/Project.java
+++ b/src/main/java/org/jcnc/snow/pkg/model/Project.java
@@ -73,7 +73,7 @@ public final class Project {
}
/**
- * 通过扁平 Map 创建 Project 实例。key 格式约定如下:
+ * 通过扁平 Map 创建 Project 实例。key 格式约定如下:
*
* - project.* —— 项目元数据
* - properties.* —— 额外属性
diff --git a/src/main/java/org/jcnc/snow/pkg/model/Repository.java b/src/main/java/org/jcnc/snow/pkg/model/Repository.java
index 73d97b2..5b22835 100644
--- a/src/main/java/org/jcnc/snow/pkg/model/Repository.java
+++ b/src/main/java/org/jcnc/snow/pkg/model/Repository.java
@@ -7,7 +7,7 @@ package org.jcnc.snow.pkg.model;
*
*
*
- * 示例用法:
+ * 示例用法:
* Repository repo = new Repository("central", "https://");
*
*
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java
index c7431d2..c21b1ad 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java
@@ -14,7 +14,7 @@ import java.util.Comparator;
* 本类为无状态实现,线程安全。
*
*
- * 示例用法:
+ * 示例用法:
* {@code
* Task clean = new CleanTask();
* clean.run();
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
index 4d8e9d1..7ce1633 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
@@ -27,14 +27,14 @@ import java.nio.file.Path;
import java.util.*;
/**
- * CLI 任务:编译 .snow 源文件为 VM 字节码(.water 文件)。
+ * CLI 任务: 编译 .snow 源文件为 VM 字节码(.water 文件)。
*
* 支持单文件、多文件和目录递归编译,并可在编译后立即运行虚拟机。
* 命令行参数支持 run、-o、-d 及直接指定源文件。
*
*
*
- * 用法示例:
+ * 用法示例:
* $ snow compile [run] [-o <name>] [-d <srcDir>] [file1.snow file2.snow ...]
*
*/
@@ -211,7 +211,7 @@ public final class CompileTask implements Task {
Files.write(outputFile, finalCode, StandardCharsets.UTF_8);
System.out.println("Written to " + outputFile.toAbsolutePath());
- // ---------------- 6. 可选:立即运行 VM ----------------
+ // ---------------- 6. 可选: 立即运行 VM ----------------
if (runAfterCompile) {
System.out.println("\n=== Launching VM ===");
VMLauncher.main(new String[]{outputFile.toString()});
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/GenerateTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/GenerateTask.java
index 83b9253..4794994 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/GenerateTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/GenerateTask.java
@@ -16,7 +16,7 @@ import java.util.List;
* main.snow。
*
*
- * 生成内容包括:
+ * 生成内容包括:
*
* src/ —— 源码根目录
* src/{group package}/ —— 按 project.group 创建的包路径
@@ -66,7 +66,7 @@ public final class GenerateTask implements Task {
root.resolve("dist")
));
- /* ---------- 2. 处理 group:追加包目录 ---------- */
+ /* ---------- 2. 处理 group: 追加包目录 ---------- */
String group = project != null ? project.getGroup() : null;
Path srcDir = root.resolve("src");
Path packageDir = srcDir; // 默认直接在 src 下
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/RunTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/RunTask.java
index ce83966..62d51ee 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/RunTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/RunTask.java
@@ -3,7 +3,7 @@ package org.jcnc.snow.pkg.tasks;
import org.jcnc.snow.vm.VMLauncher;
/**
- * 任务:执行已编译的 VM 字节码文件(.water)。
+ * 任务: 执行已编译的 VM 字节码文件(.water)。
*
* 作为 CLI、IDE 插件或其他宿主环境启动虚拟机的统一入口,
* 通过调用 {@link VMLauncher#main(String[])} 启动 VM 并执行指定程序。
diff --git a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
index a9bf75f..8c64ff9 100644
--- a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
+++ b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
@@ -43,7 +43,7 @@ public class LocalVariableStore {
}
/* ------------------------------------------------------------
- * 兼容早期实现:VM 指令译码器可直接调用 store / load
+ * 兼容早期实现: VM 指令译码器可直接调用 store / load
* 而无需关心内部命名差异。
* ------------------------------------------------------------ */
public void store(int index, Object value) { setVariable(index, value); }
From 4a26bd50ca62eea3da5aa154462a5dab7794d120 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 21:34:11 +0800
Subject: [PATCH 025/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AF=8D?=
=?UTF-8?q?=E6=B3=95=E5=88=86=E6=9E=90=E9=94=99=E8=AF=AF=E8=BE=93=E5=87=BA?=
=?UTF-8?q?=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
-将错误信息前的缩进从两个空格改为一个制表符,提高可读性
---
.../java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index 5343ebe..abfc6a0 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -69,7 +69,7 @@ public class LexerEngine {
return;
}
System.err.println("\n词法分析发现 " + errors.size() + " 个错误: ");
- errors.forEach(e -> System.err.println(" " + e));
+ errors.forEach(e -> System.err.println("\t" + e));
}
public List getAllTokens() { return List.copyOf(tokens); }
From c4d9be84034767e5700e6b22ac26f72a189d3a39 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 22:14:40 +0800
Subject: [PATCH 026/100] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=95=B0?=
=?UTF-8?q?=E5=AD=97=E5=AD=97=E9=9D=A2=E9=87=8F=E8=A7=A3=E6=9E=90=E4=B8=AD?=
=?UTF-8?q?=E7=9A=84=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 增加对数字后紧跟未知标识符的错误处理
- 增加对数字后紧跟下划线的错误处理
- 优化数字类型后缀的处理逻辑,防止多字符后缀
---
.../lexer/scanners/NumberTokenScanner.java | 61 +++++++++++++------
1 file changed, 44 insertions(+), 17 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
index 7b983d7..40575c9 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
@@ -8,17 +8,17 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
/**
* NumberTokenScanner —— 基于有限状态机(FSM)的数字字面量解析器。
*
- * 该扫描器负责将源码中的数字字符串切分为 NUMBER_LITERAL token,当前支持:
+ * 该扫描器负责将源码中的数字字符串切分为 NUMBER_LITERAL token,当前支持:
*
* - 十进制整数(如 0,42,123456)
* - 十进制小数(如 3.14,0.5)
* - 单字符类型后缀(如 2.0f,255B,合法集合见 SUFFIX_CHARS)
*
- *
+ *
* 如果后续需要支持科学计数法、下划线分隔符、不同进制等,只需扩展现有状态机的转移规则。
*
*
- * 状态机简述:
+ * 状态机简述:
* INT_PART --'.'--> DEC_POINT
* | |
* | v
@@ -27,21 +27,21 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
* v
* DEC_POINT --digit--> FRAC_PART
*
- * 状态说明:
+ * 状态说明:
*
* - INT_PART : 读取整数部分,遇到 '.' 进入 DEC_POINT,否则结束。
* - DEC_POINT : 已读到小数点,必须下一个字符是数字,否则报错。
* - FRAC_PART : 读取小数部分,遇非法字符则结束主体。
* - END : 主体扫描结束,进入后缀/尾随字符判定。
*
- *
- * 错误处理策略:
+ *
+ * 错误处理策略:
*
* - 数字后跟未知字母(如 42X)—— 抛出 LexicalException
* - 数字与合法后缀间有空白(如 3 L)—— 抛出 LexicalException
* - 小数点后缺失数字(如 1.)—— 抛出 LexicalException
*
- *
+ *
* 支持的单字符类型后缀包括: b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set。
*/
public class NumberTokenScanner extends AbstractTokenScanner {
@@ -125,13 +125,30 @@ public class NumberTokenScanner extends AbstractTokenScanner {
if (!ctx.isAtEnd()) {
char next = ctx.peek();
- /* 2-A. 合法单字符后缀(紧邻数字,不允许空格) */
+ /* 2-A. 合法单字符后缀(紧邻数字,无空格) */
if (SUFFIX_CHARS.indexOf(next) >= 0) {
literal.append(ctx.advance());
- }
- /* 2-B. 未知紧邻字母后缀 —— 报错 */
- else if (Character.isLetter(next)) {
- throw new LexicalException("未知的数字类型后缀 '" + next + "'", line, col);
+
+ /* 后缀只能出现一次:再次出现字母/数字/点即视为非法 */
+ if (!ctx.isAtEnd()) {
+ char peekAfterSuffix = ctx.peek();
+ if (Character.isLetter(peekAfterSuffix)
+ || Character.isDigit(peekAfterSuffix)
+ || peekAfterSuffix == '.') {
+ throw new LexicalException(
+ "数字类型后缀只能是单字符,非法续接 '" + peekAfterSuffix + "'",
+ line, col);
+ }
+ }
+
+ /* 2-B. **非法字母**(既不是后缀,也没有空白隔开) */
+ } else if (Character.isLetter(next)) {
+ throw new LexicalException(
+ "数字后不能紧跟未知标识符 '" + next + "'", line, col);
+ /* 2-C. **非法下划线** */
+ } else if (next == '_') {
+ throw new LexicalException(
+ "数字后不能紧跟下划线 '_'", line, col);
}
/* 其余情况交由外层扫描器处理(包括空白及其它符号) */
}
@@ -140,15 +157,25 @@ public class NumberTokenScanner extends AbstractTokenScanner {
return new Token(TokenType.NUMBER_LITERAL, literal.toString(), line, col);
}
- /** FSM 内部状态定义 */
+ /**
+ * FSM 内部状态定义
+ */
private enum State {
- /** 整数部分 */
+ /**
+ * 整数部分
+ */
INT_PART,
- /** 已读到小数点,但还未读到第一位小数数字 */
+ /**
+ * 已读到小数点,但还未读到第一位小数数字
+ */
DEC_POINT,
- /** 小数部分 */
+ /**
+ * 小数部分
+ */
FRAC_PART,
- /** 主体结束,准备处理后缀或交还控制权 */
+ /**
+ * 主体结束,准备处理后缀或交还控制权
+ */
END
}
}
From 2be48487353cdd3baefcebd37f63ae6e2a609d16 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 22:21:31 +0800
Subject: [PATCH 027/100] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E8=AF=8D?=
=?UTF-8?q?=E6=B3=95=E5=88=86=E6=9E=90=E4=B8=AD=E7=9A=84=E5=BC=82=E5=B8=B8?=
=?UTF-8?q?=E6=8A=9B=E5=87=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index abfc6a0..658182d 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -55,12 +55,6 @@ public class LexerEngine {
TokenPrinter.print(tokens);
/* 4. 统一报告错误 */
report(errors);
- if (!errors.isEmpty()) {
- throw new LexicalException(
- "",
- context.getLine(), context.getCol()
- );
- }
}
public static void report(List errors) {
From f23e15339c904ddc1552ca5a93075816ff01c9d2 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 22:21:56 +0800
Subject: [PATCH 028/100] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4=E4=BA=86?=
=?UTF-8?q?=20LexicalException=20=E7=B1=BB=E4=B8=AD=E7=9A=84=E5=86=97?=
=?UTF-8?q?=E4=BD=99=E7=A9=BA=E8=A1=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/jcnc/snow/compiler/lexer/core/LexicalException.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
index 836ae99..1518a70 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
@@ -36,7 +36,6 @@ public class LexicalException extends RuntimeException {
this.column = column;
}
-
/**
* 屏蔽异常堆栈填充(始终不打印堆栈信息)
*/
From 93a553ea93b7e161a39c5dafebd63d511588b5a0 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 23:16:12 +0800
Subject: [PATCH 029/100] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=95=B0?=
=?UTF-8?q?=E5=AD=97=E5=92=8C=E6=A0=87=E8=AF=86=E7=AC=A6=E5=8C=BA=E5=88=86?=
=?UTF-8?q?=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 skipInvalidLexeme 方法,用于跳过无效的标识符和数字字符
- 修改错误处理逻辑,遇到词法错误时调用 skipInvalidLexeme 方法
---
.../snow/compiler/lexer/core/LexerEngine.java | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index 658182d..7272b77 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -87,7 +87,7 @@ public class LexerEngine {
errors.add(new LexicalError(
absPath, le.getLine(), le.getColumn(), le.getReason()
));
- context.advance(); // 跳过问题字符
+ skipInvalidLexeme();
}
handled = true;
break;
@@ -97,6 +97,20 @@ public class LexerEngine {
}
tokens.add(Token.eof(context.getLine()));
}
+ /**
+ * 跳过当前位置起连续的“标识符 / 数字 / 下划线 / 点”字符。
+ * 这样可以把诸如 {@code 1abc} 的残余 {@code abc}、{@code _}、
+ * {@code .999} 等一次性忽略,避免后续被误识别为新的 token。
+ */
+ private void skipInvalidLexeme() {
+ while (!context.isAtEnd()) {
+ char c = context.peek();
+ if (Character.isWhitespace(c)) break; // 空白 / 换行
+ if (!Character.isLetterOrDigit(c)
+ && c != '_' && c != '.') break; // 符号分隔
+ context.advance(); // 否则继续吞掉
+ }
+ }
/**
* 目前包含三条规则:
From cc106f57e161924a4031e4a84b264f40667e1f10 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 23:37:15 +0800
Subject: [PATCH 030/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E7=BC=96?=
=?UTF-8?q?=E8=AF=91=E6=B5=81=E7=A8=8B=EF=BC=8C=E8=AF=8D=E6=B3=95=E5=88=86?=
=?UTF-8?q?=E6=9E=90=E6=9C=89=E9=94=99=E8=AF=AF=E6=97=B6=E7=AB=8B=E5=8D=B3?=
=?UTF-8?q?=E7=BB=88=E6=AD=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在语法分析之前增加对词法分析错误的检查
- 若词法阶段存在错误,立即终止编译,避免进入后续的语法及语义分析
- 这种优化可以减少不必要的计算,提高编译效率
---
src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
index 7ce1633..f570bee 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
@@ -168,6 +168,11 @@ public final class CompileTask implements Task {
// 词法、语法分析
LexerEngine lexer = new LexerEngine(code, p.toString());
+ // 若词法阶段存在错误,立即终止编译,避免进入后续的语法及语义分析
+ if (!lexer.getErrors().isEmpty()) {
+ return 1;
+ }
+
ParserContext ctx = new ParserContext(lexer.getAllTokens(), p.toString());
allAst.addAll(new ParserEngine(ctx).parse());
}
From 268f1aa09ae126278f35f10689872b82d9d12690 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 16 Jul 2025 23:52:22 +0800
Subject: [PATCH 031/100] =?UTF-8?q?refactor:=20=E7=AE=80=E5=8C=96=E8=AF=8D?=
=?UTF-8?q?=E6=B3=95=E5=BC=82=E5=B8=B8=E9=94=99=E8=AF=AF=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了错误信息中的"词法错误:"前缀,使信息更加简洁
- 保留了非法字符序列和位置信息,确保错误定位准确
---
.../jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java
index 5552d4b..6c91408 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/UnknownTokenScanner.java
@@ -50,6 +50,6 @@ public class UnknownTokenScanner extends AbstractTokenScanner {
if (lexeme.isEmpty())
lexeme = String.valueOf(ctx.advance());
// 抛出词法异常,并带上错误片段与具体位置
- throw new LexicalException("词法错误: 非法字符序列 '" + lexeme + "'", line, col);
+ throw new LexicalException("非法字符序列 '" + lexeme + "'", line, col);
}
}
From 2093201173ae4bfc3fca162d0d981d382f68276a Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 00:04:16 +0800
Subject: [PATCH 032/100] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=E4=B8=BA?=
=?UTF-8?q?=E6=9C=80=E6=96=B0=E7=9A=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/BugFarm/Bug1/Main.snow | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/playground/BugFarm/Bug1/Main.snow b/playground/BugFarm/Bug1/Main.snow
index c77b004..f4fb369 100644
--- a/playground/BugFarm/Bug1/Main.snow
+++ b/playground/BugFarm/Bug1/Main.snow
@@ -2,7 +2,8 @@ module: Main
function: main
return_type: void
body:
- declare 1sum :int =1
+ declare abc!:int =1
+
end body
end function
-end module
\ No newline at end of file
+end module
From 69b4a418badf2c32945c110acce72e85cfa905a2 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 11:18:35 +0800
Subject: [PATCH 033/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AF=8D?=
=?UTF-8?q?=E6=B3=95=E5=88=86=E6=9E=90=E5=99=A8=E5=BC=95=E6=93=8E=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 格式化代码,提高可读性
- 修改错误消息构造方式,简化为接收完整消息字符串- 更新注释,准备后续具体功能改动
---
.../snow/compiler/lexer/core/LexerEngine.java | 38 ++++++++++++-------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index 7272b77..1ac0792 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -21,20 +21,21 @@ import java.util.List;
*/
public class LexerEngine {
- private final List tokens = new ArrayList<>(); // 扫描结果
- private final List errors = new ArrayList<>();
- private final String absPath; // 绝对路径
+ private final List tokens = new ArrayList<>(); // 扫描结果
+ private final List errors = new ArrayList<>();
+ private final String absPath; // 绝对路径
private final LexerContext context; // 字符流
private final List scanners; // 扫描器链
/**
* 创建并立即执行扫描-校验-报告流程。
+ *
* @param source 源代码文本
* @param sourceName 文件名(诊断用)
*/
public LexerEngine(String source, String sourceName) {
- this.absPath = new File(sourceName).getAbsolutePath();
- this.context = new LexerContext(source);
+ this.absPath = new File(sourceName).getAbsolutePath();
+ this.context = new LexerContext(source);
this.scanners = List.of(
new WhitespaceTokenScanner(),
new NewlineTokenScanner(),
@@ -66,8 +67,13 @@ public class LexerEngine {
errors.forEach(e -> System.err.println("\t" + e));
}
- public List getAllTokens() { return List.copyOf(tokens); }
- public List getErrors() { return List.copyOf(errors); }
+ public List getAllTokens() {
+ return List.copyOf(tokens);
+ }
+
+ public List getErrors() {
+ return List.copyOf(errors);
+ }
/**
* 逐字符扫描: 依次尝试各扫描器;扫描器抛出的
@@ -97,6 +103,7 @@ public class LexerEngine {
}
tokens.add(Token.eof(context.getLine()));
}
+
/**
* 跳过当前位置起连续的“标识符 / 数字 / 下划线 / 点”字符。
* 这样可以把诸如 {@code 1abc} 的残余 {@code abc}、{@code _}、
@@ -113,10 +120,9 @@ public class LexerEngine {
}
/**
- * 目前包含三条规则:
- * 1. Dot-Prefix'.' 不能作标识符前缀
- * 2. Declare-Ident declare 后必须紧跟合法标识符,并且只能一个
- * 3. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余
+ * 目前包含2条规则:
+ * 1. Declare-Ident declare 后必须紧跟合法标识符,并且只能一个
+ * 2. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余
*
发现问题仅写入 {@link #errors},不抛异常。
*/
private void validateTokens() {
@@ -146,7 +152,9 @@ public class LexerEngine {
}
}
- /** index 右侧最近非 NEWLINE token;无则 null */
+ /**
+ * index 右侧最近非 NEWLINE token;无则 null
+ */
private Token findNextNonNewline(int index) {
for (int j = index + 1; j < tokens.size(); j++) {
Token t = tokens.get(j);
@@ -155,8 +163,10 @@ public class LexerEngine {
return null;
}
- /** 构造统一的 LexicalError */
+ /**
+ * 构造统一的 LexicalError
+ */
private LexicalError err(Token t, String msg) {
- return new LexicalError(absPath, t.getLine(), t.getCol(), "非法的标记序列: " + msg);
+ return new LexicalError(absPath, t.getLine(), t.getCol(), msg);
}
}
From ac5b73e320c4f0b7422c9a4508be161495a42309 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 11:27:03 +0800
Subject: [PATCH 034/100] =?UTF-8?q?feat:=20=E9=80=82=E9=85=8D=20Windows=20?=
=?UTF-8?q?=E6=8D=A2=E8=A1=8C=E7=AC=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修改 NewlineTokenScanner 以支持 \r\n 换行符
- 增加对 \r 换行符的处理
- 优化 scanToken 方法,兼容不同操作系统换行符
---
.../lexer/scanners/NewlineTokenScanner.java | 35 ++++++++++++-------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NewlineTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NewlineTokenScanner.java
index 6964dfd..a2a8c94 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NewlineTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NewlineTokenScanner.java
@@ -11,12 +11,6 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
*/
public class NewlineTokenScanner extends AbstractTokenScanner {
- // 定义状态枚举
- private enum State {
- INITIAL,
- NEWLINE
- }
-
// 当前状态
private State currentState = State.INITIAL;
@@ -31,7 +25,7 @@ public class NewlineTokenScanner extends AbstractTokenScanner {
@Override
public boolean canHandle(char c, LexerContext ctx) {
// 只有当处于 INITIAL 状态,并且遇到换行符时,才可以处理
- return currentState == State.INITIAL && c == '\n';
+ return currentState == State.INITIAL && (c == '\n' || c == '\r');
}
/**
@@ -45,16 +39,33 @@ public class NewlineTokenScanner extends AbstractTokenScanner {
*/
@Override
protected Token scanToken(LexerContext ctx, int line, int col) {
- // 状态转换为 NEWLINE
currentState = State.NEWLINE;
- // 执行换行符扫描,生成 token
+ char first = ctx.peek();
+ String lexeme;
+
ctx.advance();
- Token newlineToken = new Token(TokenType.NEWLINE, "\n", line, col);
+ if (first == '\r') {
+ // 检查是否是 \r\n
+ if (!ctx.isAtEnd() && ctx.peek() == '\n') {
+ ctx.advance();
+ lexeme = "\r\n";
+ } else {
+ lexeme = "\r";
+ }
+ } else {
+ // 一定是 \n
+ lexeme = "\n";
+ }
- // 扫描完成后,恢复状态为 INITIAL
+ Token newlineToken = new Token(TokenType.NEWLINE, lexeme, line, col);
currentState = State.INITIAL;
-
return newlineToken;
}
+
+ // 定义状态枚举
+ private enum State {
+ INITIAL,
+ NEWLINE
+ }
}
From d0e8cee6bd884196b13a1b100d12b7c916e2782b Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 11:47:19 +0800
Subject: [PATCH 035/100] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=95=B0?=
=?UTF-8?q?=E5=AD=97=E5=AD=97=E9=9D=A2=E9=87=8F=E4=B8=AD=E7=9A=84=E4=B8=8B?=
=?UTF-8?q?=E5=88=92=E7=BA=BF=E5=88=86=E9=9A=94=E7=AC=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 增加了对数字中下划线的处理逻辑
- 添加了防止下划线连续出现、以下划线开头或结尾的校验
- 优化了小数部分的下划线检查
- 修复了数字后紧跟下划线的错误处理
- 最后返回的数字字面量中将移除所有的下划线
---
.../lexer/scanners/NumberTokenScanner.java | 42 +++++++++++++++++--
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
index 40575c9..c655595 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
@@ -80,6 +80,9 @@ public class NumberTokenScanner extends AbstractTokenScanner {
StringBuilder literal = new StringBuilder();
State state = State.INT_PART;
+ boolean lastWasUnderscore = false; // 记录前一个是否是下划线
+ boolean sawDigit = false; // 当前段落是否有数字(防止以下划线开头)
+
/* ───── 1. 主体扫描 —— 整数 / 小数 ───── */
mainLoop:
while (!ctx.isAtEnd() && state != State.END) {
@@ -89,10 +92,25 @@ public class NumberTokenScanner extends AbstractTokenScanner {
case INT_PART:
if (Character.isDigit(ch)) {
literal.append(ctx.advance());
+ lastWasUnderscore = false;
+ sawDigit = true;
+ } else if (ch == '_') {
+ if (!sawDigit)
+ throw new LexicalException("数字不能以下划线开头", line, col);
+ if (lastWasUnderscore)
+ throw new LexicalException("数字中下划线不能连续出现", line, col);
+ literal.append(ctx.advance());
+ lastWasUnderscore = true;
} else if (ch == '.') {
+ if (lastWasUnderscore)
+ throw new LexicalException("下划线不能出现在小数点前", line, col);
state = State.DEC_POINT;
literal.append(ctx.advance());
+ // 不要重置sawDigit!
+ // sawDigit = false; // 移除此句
} else {
+ if (lastWasUnderscore)
+ throw new LexicalException("数字不能以下划线结尾", line, col);
state = State.END;
}
break;
@@ -100,18 +118,30 @@ public class NumberTokenScanner extends AbstractTokenScanner {
/* 已读到小数点,下一字符必须是数字 */
case DEC_POINT:
if (Character.isDigit(ch)) {
- state = State.FRAC_PART;
literal.append(ctx.advance());
+ state = State.FRAC_PART;
+ sawDigit = true;
+ } else if (ch == '_') { // 防止小数点后直接跟下划线
+ throw new LexicalException("小数点后不能直接跟下划线", line, col);
} else {
throw new LexicalException("小数点后必须跟数字", line, col);
}
break;
/* 小数部分 */
+
case FRAC_PART:
if (Character.isDigit(ch)) {
literal.append(ctx.advance());
+ lastWasUnderscore = false;
+ } else if (ch == '_') { // 小数部分下划线检查
+ if (lastWasUnderscore)
+ throw new LexicalException("数字中下划线不能连续出现", line, col);
+ literal.append(ctx.advance());
+ lastWasUnderscore = true;
} else {
+ if (lastWasUnderscore)
+ throw new LexicalException("数字不能以下划线结尾", line, col);
state = State.END;
}
break;
@@ -121,6 +151,10 @@ public class NumberTokenScanner extends AbstractTokenScanner {
}
}
+ // 主体结束后,下划线不能在末尾
+ if (lastWasUnderscore)
+ throw new LexicalException("数字不能以下划线结尾", line, col);
+
/* ───── 2. 后缀及非法尾随字符检查 ───── */
if (!ctx.isAtEnd()) {
char next = ctx.peek();
@@ -141,11 +175,11 @@ public class NumberTokenScanner extends AbstractTokenScanner {
}
}
- /* 2-B. **非法字母**(既不是后缀,也没有空白隔开) */
+ /* 2-B. **非法字母**(既不是后缀,也没有空白隔开) */
} else if (Character.isLetter(next)) {
throw new LexicalException(
"数字后不能紧跟未知标识符 '" + next + "'", line, col);
- /* 2-C. **非法下划线** */
+ /* 2-C. **非法下划线** */
} else if (next == '_') {
throw new LexicalException(
"数字后不能紧跟下划线 '_'", line, col);
@@ -154,7 +188,7 @@ public class NumberTokenScanner extends AbstractTokenScanner {
}
/* ───── 3. 生成并返回 Token ───── */
- return new Token(TokenType.NUMBER_LITERAL, literal.toString(), line, col);
+ return new Token(TokenType.NUMBER_LITERAL, literal.toString().replace("_", ""), line, col);
}
/**
From f185b126205f1ab19d0c07e11a044b6c8a7e7226 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:09:02 +0800
Subject: [PATCH 036/100] =?UTF-8?q?refactor(compiler):=20=E7=A7=BB?=
=?UTF-8?q?=E9=99=A4=20OperatorTokenScanner=20=E4=B8=AD=E7=9A=84=E5=86=97?=
=?UTF-8?q?=E4=BD=99=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 删除了未使用的 State 枚举类
- 移除了冗余的 currentState 变量和相关逻辑
- 简化了代码结构,提高了代码可读性
---
.../lexer/scanners/OperatorTokenScanner.java | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java
index 58bb1a9..9b278fa 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java
@@ -47,10 +47,6 @@ public class OperatorTokenScanner extends AbstractTokenScanner {
char c = ctx.advance();
String lexeme = String.valueOf(c);
TokenType type = TokenType.UNKNOWN;
-
- // 当前状态
- State currentState = State.OPERATOR;
-
switch (c) {
case '=':
if (ctx.match('=')) {
@@ -107,22 +103,10 @@ public class OperatorTokenScanner extends AbstractTokenScanner {
break;
default:
- currentState = State.UNKNOWN;
break;
}
- // 执行完扫描后,重置状态为初始状态
- if (currentState != State.UNKNOWN) {
- currentState = State.START;
- }
-
return new Token(type, lexeme, line, col);
}
- // 定义状态枚举
- private enum State {
- START, // 初始状态
- OPERATOR, // 当前字符是运算符的一部分
- UNKNOWN // 无法识别的状态
- }
}
From 5c6f61f25a2ab47c9ba5370348b0f3584d858fd6 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:09:48 +0800
Subject: [PATCH 037/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20Snow-Lang?=
=?UTF-8?q?=20=E8=AF=AD=E6=B3=95=E8=A7=84=E8=8C=83=E6=96=87=E6=A1=A3?=
=?UTF-8?q?=E9=93=BE=E6=8E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了文档链接末尾的 ".md" 后缀
- 统一文档链接格式,与其他文档链接保持一致
---
README.md | 2 +-
...r-Specification.md.md => Snow-Lang-Grammar-Specification.md} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename docs/Snow-Lang-Syntax/{Snow-Lang-Grammar-Specification.md.md => Snow-Lang-Grammar-Specification.md} (100%)
diff --git a/README.md b/README.md
index da8a7f2..cd31809 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
## 相关文档
[Snow-Lang 指南](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
-[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md)
+[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification)
[Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
similarity index 100%
rename from docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md
rename to docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
From 9acb52a7e1eeb4dedd38b2eea9f07a35932827ce Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:22:15 +0800
Subject: [PATCH 038/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E6=9E=84?=
=?UTF-8?q?=E9=80=A0=E5=87=BD=E6=95=B0=E9=87=8D=E8=BD=BD=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 删除了示例代码中的多余空行
- 修正了示例代码的格式问题
---
docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
index 58fa46e..d8a816a 100644
--- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
+++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
@@ -553,8 +553,6 @@ end module
## 11 · 构造函数重载示例
-**示例: **
-
````snow
struct: Point
declare x: int
From 7f09b0e50171980e1a1dafbfbad793f21325d353 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:09:02 +0800
Subject: [PATCH 039/100] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20Operat?=
=?UTF-8?q?orTokenScanner=20=E4=B8=AD=E7=9A=84=E5=86=97=E4=BD=99=E7=8A=B6?=
=?UTF-8?q?=E6=80=81=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 删除了未使用的 State 枚举类
- 移除了冗余的 currentState 变量和相关逻辑
- 简化了代码结构,提高了代码可读性
---
.../lexer/scanners/OperatorTokenScanner.java | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java
index 58bb1a9..9b278fa 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/OperatorTokenScanner.java
@@ -47,10 +47,6 @@ public class OperatorTokenScanner extends AbstractTokenScanner {
char c = ctx.advance();
String lexeme = String.valueOf(c);
TokenType type = TokenType.UNKNOWN;
-
- // 当前状态
- State currentState = State.OPERATOR;
-
switch (c) {
case '=':
if (ctx.match('=')) {
@@ -107,22 +103,10 @@ public class OperatorTokenScanner extends AbstractTokenScanner {
break;
default:
- currentState = State.UNKNOWN;
break;
}
- // 执行完扫描后,重置状态为初始状态
- if (currentState != State.UNKNOWN) {
- currentState = State.START;
- }
-
return new Token(type, lexeme, line, col);
}
- // 定义状态枚举
- private enum State {
- START, // 初始状态
- OPERATOR, // 当前字符是运算符的一部分
- UNKNOWN // 无法识别的状态
- }
}
From 593930ccfce05307d70f0bd1fec022cc3d76ad29 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:09:48 +0800
Subject: [PATCH 040/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20Snow-Lang?=
=?UTF-8?q?=20=E8=AF=AD=E6=B3=95=E8=A7=84=E8=8C=83=E6=96=87=E6=A1=A3?=
=?UTF-8?q?=E9=93=BE=E6=8E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了文档链接末尾的 ".md" 后缀
- 统一文档链接格式,与其他文档链接保持一致
---
README.md | 2 +-
...r-Specification.md.md => Snow-Lang-Grammar-Specification.md} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename docs/Snow-Lang-Syntax/{Snow-Lang-Grammar-Specification.md.md => Snow-Lang-Grammar-Specification.md} (100%)
diff --git a/README.md b/README.md
index da8a7f2..cd31809 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
## 相关文档
[Snow-Lang 指南](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
-[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md)
+[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification)
[Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
similarity index 100%
rename from docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md
rename to docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
From e4c6faf92321cc63adaa2a516bae9f5340275c24 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:22:15 +0800
Subject: [PATCH 041/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E6=9E=84?=
=?UTF-8?q?=E9=80=A0=E5=87=BD=E6=95=B0=E9=87=8D=E8=BD=BD=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 删除了示例代码中的多余空行
- 修正了示例代码的格式问题
---
docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
index 58fa46e..d8a816a 100644
--- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
+++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
@@ -553,8 +553,6 @@ end module
## 11 · 构造函数重载示例
-**示例: **
-
````snow
struct: Point
declare x: int
From e6ad4ff282f2d28d0d8af3fcbd036550931514f0 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:24:46 +0800
Subject: [PATCH 042/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=AD=97?=
=?UTF-8?q?=E7=AC=A6=E4=B8=B2=E6=89=AB=E6=8F=8F=E5=99=A8=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 优化了 StringTokenScanner 类的文档注释,增加了状态机说明
-重新组织了代码结构,提高了可读性和可维护性
- 添加了对未闭合字符串的处理逻辑,增强了健壮性
- 优化了状态机实现,保证了字符串解析的准确性
---
.../lexer/scanners/StringTokenScanner.java | 111 +++++++++++-------
1 file changed, 69 insertions(+), 42 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java
index 8c696e8..e4c441c 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java
@@ -5,91 +5,118 @@ import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.token.TokenType;
/**
- * 字符串扫描器: 处理双引号包裹的字符串字面量,支持基本的转义字符。
+ * 字符串扫描器(StringTokenScanner)用于处理由双引号包裹的字符串字面量,
+ * 并支持常见转义字符的解析。该扫描器采用有限状态机(状态机)实现,
+ * 保证对各类字符串格式进行准确的词法分析。
*
- * 支持格式示例:
+ * 主要支持如下字符串样式:
*
- * - "hello"
- * - "line\\nbreak"
- * - "escaped \\\" quote"
+ * - "hello"
+ * - "line\\nbreak"
+ * - "escaped \\\" quote"
*
*
- * 扫描器会保留原始字符串的形式(包含双引号和转义符),
- * 并生成 {@code STRING_LITERAL} 类型的 Token。
+ * 扫描器会保留字符串的原始形式(含双引号和转义符),
+ * 并返回{@link TokenType#STRING_LITERAL}类型的Token。
+ *
+ *
+ * 状态机说明:
+ *
+ * - START:起始状态,准备扫描第一个双引号
+ * - STRING:扫描字符串内容
+ * - ESCAPE:处理转义字符
+ *
+ *
+ * @author 你的名字
+ * @since 2024
*/
public class StringTokenScanner extends AbstractTokenScanner {
/**
- * 判断是否可以处理当前位置的字符。
- * 当字符为双引号(")时,认为是字符串字面量的开始。
+ * 判断当前位置的字符是否为字符串起始符号。
+ *
+ * 只有遇到双引号(")时,才由本扫描器处理。
+ *
*
- * @param c 当前字符
- * @param ctx 当前词法上下文
- * @return 如果为字符串起始符,则返回 true
+ * @param c 当前待扫描字符
+ * @param ctx 当前词法分析上下文
+ * @return 如果是字符串起始符号,返回 true,否则返回 false
*/
@Override
public boolean canHandle(char c, LexerContext ctx) {
- return c == '"'; // 只处理字符串开始符号
+ return c == '"'; // 只处理双引号起始
}
/**
- * 执行字符串的扫描逻辑。
- * 从当前位置开始,读取直到匹配结束的双引号。
- * 支持转义字符(如 \"、\\n 等),不会中断字符串扫描。
+ * 执行字符串字面量的具体扫描过程。采用有限状态机处理逻辑,
+ * 从起始的双引号开始,逐字符处理字符串内容,支持基本转义序列(如 \\n、\\t、\\\" 等)。
+ *
+ * 扫描遇到未转义的结尾双引号时即结束,并立即返回Token。
+ * 如果遇到换行或文件结束但未遇到结尾引号,视为字符串未闭合,仍返回已扫描内容。
+ *
*
- * @param ctx 词法上下文
- * @param line 当前行号
- * @param col 当前列号
- * @return 字符串字面量类型的 Token
+ * @param ctx 词法分析上下文,支持字符遍历与回退等操作
+ * @param line 字符串开始行号(用于错误定位)
+ * @param col 字符串开始列号(用于错误定位)
+ * @return 解析得到的字符串字面量类型Token
*/
@Override
protected Token scanToken(LexerContext ctx, int line, int col) {
- StringBuilder sb = new StringBuilder();
- // 当前状态
- State currentState = State.START; // 初始状态为开始扫描字符串
+ StringBuilder sb = new StringBuilder(); // 用于收集字符串原文
+ State currentState = State.START; // 初始状态为START
- // 开始扫描字符串
+ // 主循环,直到文件结束或状态机中止
while (!ctx.isAtEnd()) {
- char c = ctx.advance();
+ char c = ctx.advance(); // 消耗当前字符
sb.append(c);
switch (currentState) {
case START:
- // 开始状态,遇到第一个双引号
+ // 第一个双引号,状态切换到STRING
currentState = State.STRING;
break;
case STRING:
if (c == '\\') {
- // 遇到转义字符,进入 ESCAPE 状态
+ // 遇到转义符,切换到ESCAPE状态
currentState = State.ESCAPE;
} else if (c == '"') {
- // 遇到结束的双引号,结束扫描
- currentState = State.END;
+ // 遇到结束双引号,立即返回Token(字符串扫描完毕)
+ return new Token(TokenType.STRING_LITERAL, sb.toString(), line, col);
+ } else if (c == '\n' || c == '\r') {
+ // 若字符串未闭合且遇到换行,提前返回(可根据需要抛异常或报错)
+ return new Token(TokenType.STRING_LITERAL, sb.toString(), line, col);
}
+ // 其他字符,保持在STRING状态继续扫描
break;
case ESCAPE:
- // 在转义状态下,处理转义字符
- sb.append(ctx.advance()); // 加入转义字符后的字符
- currentState = State.STRING; // 返回字符串状态
+ // ESCAPE状态:下一个字符会作为转义内容,无论是"、n、t等
+ // 注意advance已经处理,所以不需要再append
+ currentState = State.STRING;
break;
-
- case END:
- // 结束状态,字符串扫描完成
- return new Token(TokenType.STRING_LITERAL, sb.toString(), line, col);
}
}
- // 如果没有结束的双引号,则表示错误,或者未正确处理
+ // 若扫描到文件尾仍未遇到结尾引号,则返回当前内容
return new Token(TokenType.STRING_LITERAL, sb.toString(), line, col);
}
- // 定义状态枚举
+ /**
+ * 状态机枚举类型,表示当前字符串解析所处的状态。
+ */
private enum State {
- START, // 开始状态,寻找字符串的开始双引号
- STRING, // 字符串扫描状态,处理字符串中的字符
- ESCAPE, // 处理转义字符状态
- END // 字符串结束状态
+ /**
+ * 起始状态,等待遇到第一个双引号
+ */
+ START,
+ /**
+ * 字符串内容状态,处理实际字符串及普通字符
+ */
+ STRING,
+ /**
+ * 处理转义序列状态,遇到'\\'后切换到此状态
+ */
+ ESCAPE,
}
}
From bfcfcbb1072ae8c0eda1f1e8be940e0539a6be27 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 15:25:25 +0800
Subject: [PATCH 043/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=AD=97?=
=?UTF-8?q?=E7=AC=A6=E4=B8=B2=E6=89=AB=E6=8F=8F=E5=99=A8=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了类 StringTokenScanner 中的作者和年份信息
- 删除了冗余的代码注释,提高了代码的可读性和维护性
---
.../jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java
index e4c441c..fe02988 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/StringTokenScanner.java
@@ -26,9 +26,6 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
* - STRING:扫描字符串内容
* - ESCAPE:处理转义字符
*
- *
- * @author 你的名字
- * @since 2024
*/
public class StringTokenScanner extends AbstractTokenScanner {
@@ -92,7 +89,6 @@ public class StringTokenScanner extends AbstractTokenScanner {
case ESCAPE:
// ESCAPE状态:下一个字符会作为转义内容,无论是"、n、t等
- // 注意advance已经处理,所以不需要再append
currentState = State.STRING;
break;
}
From 3758e3da40069a3fd878d534611b84079a39a94e Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 17:03:49 +0800
Subject: [PATCH 044/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20SyscallCom?=
=?UTF-8?q?mand=20=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 CommandFactory 中为 VMOpCode.SYSCALL 添加了 SyscallCommand 实现
- 解除了对 SYSCALL 命令的注释,使其可以被使用
---
src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java b/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
index 4054a11..dbdab0f 100644
--- a/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
+++ b/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.vm.factories;
+import org.jcnc.snow.vm.commands.system.control.SyscallCommand;
import org.jcnc.snow.vm.commands.type.control.byte8.*;
import org.jcnc.snow.vm.commands.type.control.double64.*;
import org.jcnc.snow.vm.commands.type.control.float32.*;
@@ -262,7 +263,7 @@ public class CommandFactory {
// region System Control (0x0400-0x04FF)
COMMANDS[VMOpCode.HALT] = new HaltCommand();
-// COMMANDS[VMOpCode.SYSCALL] = new SyscallCommand();
+ COMMANDS[VMOpCode.SYSCALL] = new SyscallCommand();
// COMMANDS[VMOpCode.DEBUG_TRAP] = new DebugTrapCommand();
// endregion
From bf9190dec658f9e503c83e9d356a455c0e653ab0 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 17:04:12 +0800
Subject: [PATCH 045/100] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E8=B0=83?=
=?UTF-8?q?=E8=AF=95=E7=94=A8=E6=8C=87=E4=BB=A4=20DEBUG=5FTRAP?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
移除了 OpHelper 类中 DEBUG_TRAP 指令的映射,以减少不必要的代码。这个修改对现有的功能没有影响,只是为了简化代码结构。
---
.../java/org/jcnc/snow/compiler/backend/utils/OpHelper.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java b/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java
index 42c29ff..d006802 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java
@@ -176,7 +176,7 @@ public final class OpHelper {
map.put("MOV", Integer.toString(VMOpCode.MOV));
map.put("HALT", Integer.toString(VMOpCode.HALT));
map.put("SYSCALL", Integer.toString(VMOpCode.SYSCALL));
- map.put("DEBUG_TRAP", Integer.toString(VMOpCode.DEBUG_TRAP));
+// map.put("DEBUG_TRAP", Integer.toString(VMOpCode.DEBUG_TRAP));
OPCODE_MAP = Collections.unmodifiableMap(map);
Map revmap = new HashMap<>(); // reverse map
From 23c6de3601a4039b8bd5700d20687ead9eae9a11 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 17:04:22 +0800
Subject: [PATCH 046/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20SyscallCom?=
=?UTF-8?q?mand=20=E7=B1=BB=E5=AE=9E=E7=8E=B0=E7=B3=BB=E7=BB=9F=E8=B0=83?=
=?UTF-8?q?=E7=94=A8=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 SyscallCommand 类,用于处理系统调用命令(opcode =0x0401)
---
.../system/control/SyscallCommand.java | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100644 src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
diff --git a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
new file mode 100644
index 0000000..017d561
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
@@ -0,0 +1,72 @@
+package org.jcnc.snow.vm.commands.system.control;
+
+import org.jcnc.snow.vm.interfaces.Command;
+import org.jcnc.snow.vm.module.CallStack;
+import org.jcnc.snow.vm.module.LocalVariableStore;
+import org.jcnc.snow.vm.module.OperandStack;
+
+import java.util.Arrays;
+
+/**
+ * SyscallCommand ―― 统一的系统调用入口(opcode = 0x0401)。
+ *
+ * 当前支持子命令:
+ *
+ * - PRINT —— 打印,不换行
+ * - PRINTLN —— 打印并换行
+ *
+ *
+ * 用法示例(VM 指令):
+ *
+ * 1025 PRINT "Hello, Snow!"
+ * I_PUSH 42
+ * 1025 PRINTLN
+ *
+ */
+public class SyscallCommand implements Command {
+
+ @Override
+ public int execute(String[] parts, int currentPC,
+ OperandStack operandStack,
+ LocalVariableStore localVariableStore,
+ CallStack callStack) {
+
+ if (parts.length < 2)
+ throw new IllegalArgumentException("SYSCALL requires a sub-command");
+
+ String subCmd = parts[1].toUpperCase();
+
+ switch (subCmd) {
+ case "PRINT":
+ case "PRINTLN": {
+ boolean newline = subCmd.equals("PRINTLN");
+ String output;
+
+ // 指令里直接带字符串常量
+ if (parts.length > 2) {
+ output = String.join(" ", Arrays.copyOfRange(parts, 2, parts.length));
+ if (output.length() >= 2 &&
+ output.startsWith("\"") &&
+ output.endsWith("\"")) {
+ output = output.substring(1, output.length() - 1); // 去掉首尾引号
+ }
+ }
+ // 没带常量,则弹栈打印
+ else {
+ Object value = operandStack.pop();
+ output = String.valueOf(value);
+ }
+
+ if (newline) System.out.println(output);
+ else System.out.print(output);
+ break;
+ }
+
+ default:
+ throw new UnsupportedOperationException("Unsupported SYSCALL: " + subCmd);
+ }
+
+ // 下一条指令
+ return currentPC + 1;
+ }
+}
From 59aef0c6616e8963e090444355c6393b62009213 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 17:05:48 +0800
Subject: [PATCH 047/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20SYSCALL=20?=
=?UTF-8?q?=E6=93=8D=E4=BD=9C=E7=A0=81=E7=9A=84=E8=AF=A6=E7=BB=86=E6=B3=A8?=
=?UTF-8?q?=E9=87=8A=E5=B9=B6=E7=A7=BB=E9=99=A4=E6=9C=AA=E4=BD=BF=E7=94=A8?=
=?UTF-8?q?=E7=9A=84=20DEBUG=5FTRAP=20=E6=93=8D=E4=BD=9C=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 为 SYSCALL 操作码添加了详细的注释,说明了其执行步骤和实现类- 注释掉了未使用的 DEBUG_TRAP 操作码
- 引入了 SyscallCommand 类以实现 SYSCALL 操作码的功能
---
src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java b/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
index 73d8ed5..8e1a880 100644
--- a/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
+++ b/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.vm.engine;
+import org.jcnc.snow.vm.commands.system.control.SyscallCommand;
import org.jcnc.snow.vm.commands.type.control.byte8.*;
import org.jcnc.snow.vm.commands.type.control.double64.*;
import org.jcnc.snow.vm.commands.type.control.float32.*;
@@ -2646,8 +2647,18 @@ public class VMOpCode {
*
*/
public static final int HALT = 0x0400;
+ /**
+ * SYSCALL Opcode: Represents a system call operation that invokes a system-level function or service.
+ * This opcode is implemented by the {@link SyscallCommand} class, which defines its specific execution logic.
+ *
+ * Execution Steps:
+ *
+ * - Parses the system call identifier from the instruction parameters.
+ * - Invokes the corresponding system-level function or service based on the system call identifier.
+ * - Returns the result of the system call operation.
+ */
public static final int SYSCALL = 0x0401;
- public static final int DEBUG_TRAP = 0x0402;
+// public static final int DEBUG_TRAP = 0x0402;
// endregion
/**
From 08cfc1ffb964d5563709e7c0f473f3a0602797d2 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 17 Jul 2025 17:06:39 +0800
Subject: [PATCH 048/100] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=20Bug1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/BugFarm/Bug1/Main.snow | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/playground/BugFarm/Bug1/Main.snow b/playground/BugFarm/Bug1/Main.snow
index f4fb369..3c4df88 100644
--- a/playground/BugFarm/Bug1/Main.snow
+++ b/playground/BugFarm/Bug1/Main.snow
@@ -2,8 +2,7 @@ module: Main
function: main
return_type: void
body:
- declare abc!:int =1
-
+ declare abc:string ="0"
end body
end function
end module
From f44fc18c52013dcb65f755f0e657bacb1d460a15 Mon Sep 17 00:00:00 2001
From: zhangxun <1958638841@qq.com>
Date: Fri, 18 Jul 2025 02:36:32 +0000
Subject: [PATCH 049/100] =?UTF-8?q?docs:=20Snow-Lang=20=E8=AF=AD=E6=B3=95?=
=?UTF-8?q?=E8=A7=84=E8=8C=83=E4=B8=8D=E8=83=BD=E8=B7=B3=E8=BD=AC=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index cd31809..da8a7f2 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
## 相关文档
[Snow-Lang 指南](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
-[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification)
+[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md)
[Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
From e2d4f97d75858d8fc09ce32042285b4079fe954c Mon Sep 17 00:00:00 2001
From: zhangxun <1958638841@qq.com>
Date: Fri, 18 Jul 2025 10:43:55 +0800
Subject: [PATCH 050/100] =?UTF-8?q?docs:=20=E7=A7=BB=E9=99=A4=E9=BB=98?=
=?UTF-8?q?=E8=AE=A4=E6=95=B4=E6=95=B0=E5=92=8C=E6=B5=AE=E7=82=B9=E6=95=B0?=
=?UTF-8?q?=E7=9A=84=E5=90=8E=E7=BC=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
index d8a816a..64d2af4 100644
--- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
+++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
@@ -321,10 +321,8 @@ Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体
|----|--------|----------|
| b | byte | 7b, -2B |
| s | short | 123s |
-| i | int | 100i |
| l | long | 5l, 123L |
| f | float | 3.14f |
-| d | double | 1.0d |
- 没有后缀的整数字面量自动为 `int`。
- 没有后缀的浮点字面量自动为 `double`。
From 901d2f842ae08acef547ba6536ace61e54ea1d11 Mon Sep 17 00:00:00 2001
From: zhangxun <1958638841@qq.com>
Date: Fri, 18 Jul 2025 11:03:21 +0800
Subject: [PATCH 051/100] =?UTF-8?q?fix:=20=E6=95=B0=E5=80=BC=E5=AD=97?=
=?UTF-8?q?=E9=9D=A2=E9=87=8F=E5=90=8E=E7=B4=A7=E6=8C=A8=E7=9D=80=E6=A0=87?=
=?UTF-8?q?=E8=AF=86=E7=AC=A6=E6=97=B6=EF=BC=8C=E6=8A=A5=E9=94=99=E4=BF=A1?=
=?UTF-8?q?=E6=81=AF=E8=BE=93=E5=87=BA=E5=AE=8C=E6=95=B4=E6=A0=87=E8=AF=86?=
=?UTF-8?q?=E7=AC=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
index c655595..b1adea1 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
@@ -177,8 +177,10 @@ public class NumberTokenScanner extends AbstractTokenScanner {
/* 2-B. **非法字母**(既不是后缀,也没有空白隔开) */
} else if (Character.isLetter(next)) {
+ var its = new IdentifierTokenScanner();
+ var token = its.scanToken(ctx, line, col);
throw new LexicalException(
- "数字后不能紧跟未知标识符 '" + next + "'", line, col);
+ "数字后不能紧跟未知标识符 '" + token.getLexeme() + "'", line, col);
/* 2-C. **非法下划线** */
} else if (next == '_') {
throw new LexicalException(
From 3dd06261e2cd554afb5a38c8190e9a50e55bcaf3 Mon Sep 17 00:00:00 2001
From: zhangxun <1958638841@qq.com>
Date: Fri, 18 Jul 2025 11:15:35 +0800
Subject: [PATCH 052/100] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=AF=B9?=
=?UTF-8?q?=E6=B5=AE=E7=82=B9=E6=95=B0=E5=AD=97=E9=9D=A2=E9=87=8F=E5=90=8E?=
=?UTF-8?q?=E7=BC=80=20D=20=E7=9A=84=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
index b1adea1..7cd0894 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/NumberTokenScanner.java
@@ -42,7 +42,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
* - 小数点后缺失数字(如 1.)—— 抛出 LexicalException
*
*
- * 支持的单字符类型后缀包括: b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set。
+ * 支持的单字符类型后缀包括: b, s, l, f 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set。
*/
public class NumberTokenScanner extends AbstractTokenScanner {
@@ -51,7 +51,7 @@ public class NumberTokenScanner extends AbstractTokenScanner {
* 包含: b, s, l, f, d 及其大写形式。
* 对于多字符后缀,可扩展为 Set 并在扫描尾部做贪婪匹配。
*/
- private static final String SUFFIX_CHARS = "bslfdBSLFD";
+ private static final String SUFFIX_CHARS = "bslfBSLF";
/**
* 判断是否由该扫描器处理。
From 6fb24f3f2f9b97d33264af03e8f5531e21bf5ce3 Mon Sep 17 00:00:00 2001
From: zhangxun <1958638841@qq.com>
Date: Fri, 18 Jul 2025 11:16:08 +0800
Subject: [PATCH 053/100] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=20Demo13=20?=
=?UTF-8?q?=E4=BB=A5=E6=94=AF=E6=8C=81=E6=96=B0=E7=89=88=E8=AF=AD=E6=B3=95?=
=?UTF-8?q?=EF=BC=88=E7=A7=BB=E9=99=A4=E5=AF=B9=E5=AD=97=E9=9D=A2=E9=87=8F?=
=?UTF-8?q?=20D=20=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/Demo/Demo13/Main.snow | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/playground/Demo/Demo13/Main.snow b/playground/Demo/Demo13/Main.snow
index dee7b5b..7b6479b 100644
--- a/playground/Demo/Demo13/Main.snow
+++ b/playground/Demo/Demo13/Main.snow
@@ -7,34 +7,34 @@ module: Main
5 == 7b
5 == 7l
5 == 7f
- 5 == 7d
+ 5 == 7.0
5b == 5b
5b == 5s
5b == 5l
5b == 5f
- 5b == 5d
+ 5b == 5.0
5s == 5s
5s == 5l
5s == 5f
- 5s == 5d
+ 5s == 5.0
5l == 5l
5l == 5f
- 5l == 5d
+ 5l == 5.0
5f == 5f
- 5f == 5d
+ 5f == 5.0
- 5d == 5d
+ 5.0 == 5.0
declare b: byte = 8b
declare s: short = 8s
declare i: int = 8
declare l: long = 8l
declare f: float = 8f
- declare d: double = 8d
+ declare d: double = 8
b == b
b == s
From dad69eabfba04b799a28e5d2dac6357cb3865af5 Mon Sep 17 00:00:00 2001
From: Luke
Date: Fri, 18 Jul 2025 18:06:19 +0800
Subject: [PATCH 054/100] =?UTF-8?q?feat(vm):=20=E5=AE=9E=E7=8E=B0=20UNIX?=
=?UTF-8?q?=E9=A3=8E=E6=A0=BC=E7=9A=84=E6=96=87=E4=BB=B6=E6=8F=8F=E8=BF=B0?=
=?UTF-8?q?=E7=AC=A6=20I/O=20=E6=93=8D=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 FDTable 类,用于管理文件描述符和 NIO Channel 的映射
- 重构 SyscallCommand 类,实现多个 I/O 相关的 syscall 子命令
- 支持文件操作(open、close、read、write、seek)、管道、网络套接字、I/O 多路复用等功能
- 优化异常处理机制,统一处理 syscall内部异常
---
.../system/control/SyscallCommand.java | 400 ++++++++++++++++--
.../java/org/jcnc/snow/vm/io/FDTable.java | 62 +++
2 files changed, 422 insertions(+), 40 deletions(-)
create mode 100644 src/main/java/org/jcnc/snow/vm/io/FDTable.java
diff --git a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
index 017d561..b45754e 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
@@ -1,72 +1,392 @@
package org.jcnc.snow.vm.commands.system.control;
import org.jcnc.snow.vm.interfaces.Command;
+import org.jcnc.snow.vm.io.FDTable;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
-import java.util.Arrays;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.nio.file.OpenOption;
+import java.nio.file.Paths;
+import java.util.*;
+
+import static java.nio.file.StandardOpenOption.*;
/**
- * SyscallCommand ―― 统一的系统调用入口(opcode = 0x0401)。
+ * {@code SyscallCommand} —— I/O syscall 子命令集合指令。
*
- * 当前支持子命令:
+ *
+ * 封装类 UNIX 文件描述符(File Descriptor, FD)操作、文件/网络 I/O、管道、fd 复制、多路复用(select)等系统调用能力,
+ * 基于 Java NIO 统一实现,供虚拟机指令集以 SYSCALL 形式扩展使用。
+ *
+ *
+ * 栈操作约定:
*
- * - PRINT —— 打印,不换行
- * - PRINTLN —— 打印并换行
+ * - 参数按“右值先入栈、左值后入栈”的顺序推入操作数栈,执行 {@code SYSCALL
} 后出栈。
+ * - 即:调用 SYSCALL OPEN path flags mode,入栈顺序为 path(先入)→ flags → mode(后入),出栈时 mode→flags→path 弹出。
*
*
- * 用法示例(VM 指令):
- *
- * 1025 PRINT "Hello, Snow!"
- * I_PUSH 42
- * 1025 PRINTLN
- *
+ * 返回值说明:
+ *
+ * - 成功:压入正值(如 FD、实际数据、字节数、0 表示成功)。
+ * - 失败:统一压入 -1,后续可扩展为 errno 机制。
+ *
+ *
+ * 支持的子命令(部分):
+ *
+ * - PRINT / PRINTLN —— 控制台输出(TODO: 代码未实现)
+ * - OPEN / CLOSE / READ / WRITE / SEEK —— 文件 I/O 操作
+ * - PIPE / DUP —— 管道和 FD 复制
+ * - SOCKET / CONNECT / BIND / LISTEN / ACCEPT —— 网络套接字
+ * - SELECT —— I/O 多路复用
+ *
*/
public class SyscallCommand implements Command {
+ /*------------------------------------ 工具方法 ------------------------------------*/
+
+ /**
+ * POSIX open 标志到 Java NIO OpenOption 的映射
+ *
+ * 将 Linux/UNIX 的 open 调用 flags 参数,转换为 Java NIO 的 OpenOption 集合。
+ * 目前仅支持 WRITE(0x1)、READ、CREATE(0x40)、TRUNCATE(0x200)、APPEND(0x400)等常用标志。
+ *
+ *
+ * @param flags POSIX 风格 open 标志(如 O_WRONLY=0x1, O_CREAT=0x40 等)
+ * @return 映射后的 OpenOption 集合
+ */
+ private static Set flagsToOptions(int flags) {
+ Set opts = new HashSet<>();
+ // 0x1 = WRITE,否则默认 READ
+ if ((flags & 0x1) != 0) opts.add(WRITE);
+ else opts.add(READ);
+ if ((flags & 0x40) != 0) opts.add(CREATE);
+ if ((flags & 0x200) != 0) opts.add(TRUNCATE_EXISTING);
+ if ((flags & 0x400) != 0) opts.add(APPEND);
+ return opts;
+ }
+
+ /**
+ * 统一异常处理:
+ *
+ * 捕获 syscall 内部所有异常,将 -1 压入操作数栈,表示系统调用失败(暂不区分错误类型)。
+ * 常见异常如文件不存在、权限不足、通道类型不符、网络故障等。
+ *
+ *
+ * @param stack 当前操作数栈
+ * @param e 捕获的异常对象
+ */
+ private static void pushErr(OperandStack stack, Exception e) {
+ stack.push(-1); // 目前统一用 -1,后续可按异常类型/errno 映射
+ }
+
+ /*--------------------------------------------------------------------------------*/
+
+ /**
+ * 执行 SYSCALL 子命令:
+ *
+ * 按照 parts[1] 指定的 SYSCALL 子命令,结合虚拟机栈与资源表完成对应的系统调用模拟。
+ * 支持基础文件、网络、管道等 I/O 操作,并对异常统一处理。
+ *
+ *
+ * @param parts 指令字符串数组,parts[1] 为子命令
+ * @param pc 当前指令计数器
+ * @param stack 操作数栈
+ * @param locals 局部变量表
+ * @param callStack 调用栈
+ * @return 下一条指令的 pc 值(默认 pc+1)
+ */
@Override
- public int execute(String[] parts, int currentPC,
- OperandStack operandStack,
- LocalVariableStore localVariableStore,
+ public int execute(String[] parts, int pc,
+ OperandStack stack,
+ LocalVariableStore locals,
CallStack callStack) {
if (parts.length < 2)
- throw new IllegalArgumentException("SYSCALL requires a sub-command");
+ throw new IllegalArgumentException("SYSCALL needs sub-command");
- String subCmd = parts[1].toUpperCase();
+ String cmd = parts[1].toUpperCase(Locale.ROOT);
- switch (subCmd) {
- case "PRINT":
- case "PRINTLN": {
- boolean newline = subCmd.equals("PRINTLN");
- String output;
+ try {
+ switch (cmd) {
- // 指令里直接带字符串常量
- if (parts.length > 2) {
- output = String.join(" ", Arrays.copyOfRange(parts, 2, parts.length));
- if (output.length() >= 2 &&
- output.startsWith("\"") &&
- output.endsWith("\"")) {
- output = output.substring(1, output.length() - 1); // 去掉首尾引号
+ /*==================== 文件 / 目录 ====================*/
+
+ /*
+ * OPEN —— 打开文件,返回文件描述符(File Descriptor, FD)。
+ * 入栈(push)顺序: path(文件路径, String), flags(int), mode(int,文件权限,暂未用)
+ * 出栈(pop)顺序: mode → flags → path
+ * 成功返回 fd,失败返回 -1。
+ */
+ case "OPEN" -> {
+ int mode = (Integer) stack.pop(); // 目前未用
+ int flags = (Integer) stack.pop();
+ String path = String.valueOf(stack.pop());
+ FileChannel fc = FileChannel.open(Paths.get(path), flagsToOptions(flags));
+ stack.push(FDTable.register(fc));
+ }
+ /*
+ * CLOSE —— 关闭文件描述符。
+ * 入栈顺序: fd(int)
+ * 出栈顺序: fd
+ * 返回 0 成功,-1 失败
+ */
+ case "CLOSE" -> {
+ int fd = (Integer) stack.pop();
+ FDTable.close(fd);
+ stack.push(0);
+ }
+ /*
+ * READ —— 从 fd 读取指定字节数。
+ * 入栈顺序: fd(int), count(int,字节数)
+ * 出栈顺序: count → fd
+ * 返回:byte[](实际读取的数据,EOF 时长度为 0)
+ */
+ case "READ" -> {
+ int count = (Integer) stack.pop();
+ int fd = (Integer) stack.pop();
+ Channel ch = FDTable.get(fd);
+ if (!(ch instanceof ReadableByteChannel rch)) {
+ stack.push(new byte[0]);
+ break;
}
+ ByteBuffer buf = ByteBuffer.allocate(count);
+ int n = rch.read(buf);
+ if (n < 0) n = 0;
+ buf.flip();
+ byte[] out = new byte[n];
+ buf.get(out);
+ stack.push(out);
}
- // 没带常量,则弹栈打印
- else {
- Object value = operandStack.pop();
- output = String.valueOf(value);
+ /*
+ * WRITE —— 向 fd 写数据。
+ * 入栈顺序: fd(int), data(byte[] 或 String)
+ * 出栈顺序: data → fd
+ * 返回写入字节数,失败 -1
+ */
+ case "WRITE" -> {
+ Object dataObj = stack.pop();
+ int fd = (Integer) stack.pop();
+ byte[] data = (dataObj instanceof byte[] b)
+ ? b
+ : String.valueOf(dataObj).getBytes();
+ Channel ch = FDTable.get(fd);
+ if (!(ch instanceof WritableByteChannel wch)) {
+ stack.push(-1);
+ break;
+ }
+ int written = wch.write(ByteBuffer.wrap(data));
+ stack.push(written);
+ }
+ /*
+ * SEEK —— 文件定位,移动文件读写指针。
+ * 入栈顺序: fd(int), offset(long/int), whence(int, 0=SET,1=CUR,2=END)
+ * 出栈顺序: whence → offset → fd
+ * 返回新位置(long),失败 -1
+ */
+ case "SEEK" -> {
+ int whence = (Integer) stack.pop();
+ long off = ((Number) stack.pop()).longValue();
+ int fd = (Integer) stack.pop();
+ Channel ch = FDTable.get(fd);
+ if (!(ch instanceof SeekableByteChannel sbc)) {
+ stack.push(-1);
+ break;
+ }
+ SeekableByteChannel newPos = switch (whence) {
+ case 0 -> sbc.position(off);
+ case 1 -> sbc.position(sbc.position() + off);
+ case 2 -> sbc.position(sbc.size() + off);
+ default -> throw new IllegalArgumentException("bad whence");
+ };
+ stack.push(newPos);
}
- if (newline) System.out.println(output);
- else System.out.print(output);
- break;
+ /*==================== 管道 / FD 相关 ====================*/
+
+ /*
+ * PIPE —— 创建匿名管道。
+ * 入栈顺序: (无)
+ * 出栈顺序: (无)
+ * 返回顺序: write fd(先压栈),read fd(后压栈)
+ */
+ case "PIPE" -> {
+ Pipe p = Pipe.open();
+ stack.push(FDTable.register(p.sink())); // write fd
+ stack.push(FDTable.register(p.source())); // read fd
+ }
+ /*
+ * DUP —— 复制一个已存在的 fd(dup)。
+ * 入栈顺序: oldfd(int)
+ * 出栈顺序: oldfd
+ * 返回新的 fd,失败 -1
+ */
+ case "DUP" -> {
+ int oldfd = (Integer) stack.pop();
+ stack.push(FDTable.dup(oldfd));
+ }
+
+ /*==================== 网络相关 ====================*/
+
+ /*
+ * SOCKET —— 创建套接字,支持 stream/dgram。
+ * 入栈顺序: domain(int, AF_INET=2等), type(int, 1=STREAM,2=DGRAM), protocol(int, 预留)
+ * 出栈顺序: protocol → type → domain
+ * 返回 fd
+ */
+ case "SOCKET" -> {
+ int proto = (Integer) stack.pop(); // 预留,暂不用
+ int type = (Integer) stack.pop(); // 1=STREAM,2=DGRAM
+ int domain = (Integer) stack.pop(); // AF_INET=2……
+ Channel ch = (type == 1)
+ ? SocketChannel.open()
+ : DatagramChannel.open();
+ stack.push(FDTable.register(ch));
+ }
+ /*
+ * CONNECT —— 发起 TCP 连接。
+ * 入栈顺序: fd(int), host(String), port(int)
+ * 出栈顺序: port → host → fd
+ * 返回 0 成功,-1 失败
+ */
+ case "CONNECT" -> {
+ int port = (Integer) stack.pop();
+ String host = String.valueOf(stack.pop());
+ int fd = (Integer) stack.pop();
+ Channel ch = FDTable.get(fd);
+ if (ch instanceof SocketChannel sc) {
+ sc.connect(new InetSocketAddress(host, port));
+ stack.push(0);
+ } else stack.push(-1);
+ }
+ /*
+ * BIND —— 绑定端口。
+ * 入栈顺序: fd(int), host(String), port(int)
+ * 出栈顺序: port → host → fd
+ * 返回 0 成功,-1 失败
+ */
+ case "BIND" -> {
+ int port = (Integer) stack.pop();
+ String host = String.valueOf(stack.pop());
+ int fd = (Integer) stack.pop();
+ Channel ch = FDTable.get(fd);
+ if (ch instanceof ServerSocketChannel ssc) {
+ ssc.bind(new InetSocketAddress(host, port));
+ stack.push(0);
+ } else stack.push(-1);
+ }
+ /*
+ * LISTEN —— 监听 socket,兼容 backlog。
+ * 入栈顺序: fd(int), backlog(int)
+ * 出栈顺序: backlog → fd
+ * 返回 0 成功,-1 失败
+ * 注意:Java NIO 打开 ServerSocketChannel 已自动监听,无 backlog 处理,行为和 UNIX 有区别。
+ */
+ case "LISTEN" -> {
+ int backlog = (Integer) stack.pop();
+ int fd = (Integer) stack.pop();
+ Channel ch = FDTable.get(fd);
+ if (ch instanceof ServerSocketChannel) stack.push(0);
+ else stack.push(-1);
+ }
+ /*
+ * ACCEPT —— 接收连接。
+ * 入栈顺序: fd(int)
+ * 出栈顺序: fd
+ * 返回新连接 fd,失败 -1
+ */
+ case "ACCEPT" -> {
+ int fd = (Integer) stack.pop();
+ Channel ch = FDTable.get(fd);
+ if (ch instanceof ServerSocketChannel ssc) {
+ SocketChannel cli = ssc.accept();
+ stack.push(FDTable.register(cli));
+ } else stack.push(-1);
+ }
+
+ /*==================== 多路复用 ====================*/
+
+ /*
+ * SELECT —— I/O 多路复用,监视多个 fd 是否可读写。
+ * 入栈顺序: fds(List), timeout_ms(long)
+ * 出栈顺序: timeout_ms → fds
+ * 返回: 就绪 fd 列表(List)
+ */
+ case "SELECT" -> {
+ long timeout = ((Number) stack.pop()).longValue();
+ @SuppressWarnings("unchecked")
+ List fds = (List) stack.pop();
+
+ Selector sel = Selector.open();
+ for (int fd : fds) {
+ Channel c = FDTable.get(fd);
+ if (c instanceof SelectableChannel sc) {
+ sc.configureBlocking(false);
+ int ops = (c instanceof ReadableByteChannel ? SelectionKey.OP_READ : 0)
+ | (c instanceof WritableByteChannel ? SelectionKey.OP_WRITE : 0);
+ sc.register(sel, ops, fd);
+ }
+ }
+ int ready = sel.select(timeout);
+ List readyFds = new ArrayList<>();
+ if (ready > 0) {
+ for (SelectionKey k : sel.selectedKeys())
+ readyFds.add((Integer) k.attachment());
+ }
+ stack.push(readyFds);
+ sel.close();
+ }
+
+
+ /*==================== 控制台输出 ====================*/
+
+ /*
+ * PRINT —— 控制台输出(无换行)。
+ * 入栈顺序: data(String 或 byte[])
+ * 出栈顺序: data
+ * 返回 0
+ */
+ case "PRINT" -> {
+ Object dataObj = stack.pop();
+ if (dataObj instanceof byte[] b) {
+ System.out.print(new String(b));
+ } else {
+ System.out.print(dataObj);
+ }
+ stack.push(0); // 表示成功
+ }
+ /*
+ * PRINTLN —— 控制台输出(自动换行)。
+ * 入栈顺序: data(String 或 byte[])
+ * 出栈顺序: data
+ * 返回 0
+ */
+ case "PRINTLN" -> {
+ Object dataObj = stack.pop();
+ if (dataObj instanceof byte[] b) {
+ System.out.println(new String(b));
+ } else {
+ System.out.println(dataObj);
+ }
+ stack.push(0); // 表示成功
+ }
+
+ /*==================== 其它未实现/扩展命令 ====================*/
+
+ /*
+ * TODO: PRINT / PRINTLN / 其它自定义 syscall 子命令未实现
+ */
+ default -> throw new UnsupportedOperationException("Unsupported SYSCALL: " + cmd);
}
-
- default:
- throw new UnsupportedOperationException("Unsupported SYSCALL: " + subCmd);
+ } catch (Exception e) {
+ // 统一异常处理,异常时压入 -1
+ pushErr(stack, e);
}
- // 下一条指令
- return currentPC + 1;
+ // 默认:下一条指令
+ return pc + 1;
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/io/FDTable.java b/src/main/java/org/jcnc/snow/vm/io/FDTable.java
new file mode 100644
index 0000000..98d6385
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/vm/io/FDTable.java
@@ -0,0 +1,62 @@
+package org.jcnc.snow.vm.io;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.nio.channels.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 维护 “虚拟 fd → Java NIO Channel” 的全局映射表。
+ *
+ *
+ * 0 → stdin (ReadableByteChannel)
+ * 1 → stdout (WritableByteChannel)
+ * 2 → stderr (WritableByteChannel)
+ * 3+ → 运行期动态分配
+ *
+ */
+public final class FDTable {
+
+ private FDTable() {}
+
+ /** 下一次可用 fd(0‒2 保留给标准流) */
+ private static final AtomicInteger NEXT_FD = new AtomicInteger(3);
+ /** 主映射表:fd → Channel */
+ private static final ConcurrentHashMap MAP = new ConcurrentHashMap<>();
+
+ static {
+ // JVM 标准流包装成 NIO Channel 后放入表中
+ MAP.put(0, Channels.newChannel(new BufferedInputStream(System.in)));
+ MAP.put(1, Channels.newChannel(new BufferedOutputStream(System.out)));
+ MAP.put(2, Channels.newChannel(new BufferedOutputStream(System.err)));
+ }
+
+ /** 注册新 Channel,返回分配到的虚拟 fd */
+ public static int register(Channel ch) {
+ int fd = NEXT_FD.getAndIncrement();
+ MAP.put(fd, ch);
+ return fd;
+ }
+
+ /** 取得 Channel;如果 fd 不存在则返回 null */
+ public static Channel get(int fd) {
+ return MAP.get(fd);
+ }
+
+ /** 关闭并移除 fd(0‒2 忽略) */
+ public static void close(int fd) throws IOException {
+ if (fd <= 2) return; // 标准流交由宿主 JVM 维护
+ Channel ch = MAP.remove(fd);
+ if (ch != null && ch.isOpen()) ch.close();
+ }
+
+ /** 类似 dup(oldfd) —— 返回指向同一 Channel 的新 fd */
+ public static int dup(int oldfd) {
+ Channel ch = MAP.get(oldfd);
+ if (ch == null)
+ throw new IllegalArgumentException("Bad fd: " + oldfd);
+ return register(ch); // 多个 fd 引用同一 Channel
+ }
+}
From 8ec5120e544cb6e1632000c7614fbbf6892bf953 Mon Sep 17 00:00:00 2001
From: Luke
Date: Fri, 18 Jul 2025 23:33:13 +0800
Subject: [PATCH 055/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E5=AD=90?=
=?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=94=AF=E6=8C=81=E7=8A=B6=E6=80=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除 PRINT / PRINTLN 命令的 TODO 注释
- 修正其它自定义 syscall 子命令的 TODO 注释
---
.../jcnc/snow/vm/commands/system/control/SyscallCommand.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
index b45754e..39e63e7 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
@@ -37,7 +37,7 @@ import static java.nio.file.StandardOpenOption.*;
*
* 支持的子命令(部分):
*
- * - PRINT / PRINTLN —— 控制台输出(TODO: 代码未实现)
+ * - PRINT / PRINTLN —— 控制台输出
* - OPEN / CLOSE / READ / WRITE / SEEK —— 文件 I/O 操作
* - PIPE / DUP —— 管道和 FD 复制
* - SOCKET / CONNECT / BIND / LISTEN / ACCEPT —— 网络套接字
@@ -377,7 +377,7 @@ public class SyscallCommand implements Command {
/*==================== 其它未实现/扩展命令 ====================*/
/*
- * TODO: PRINT / PRINTLN / 其它自定义 syscall 子命令未实现
+ * 其它自定义 syscall 子命令未实现
*/
default -> throw new UnsupportedOperationException("Unsupported SYSCALL: " + cmd);
}
From 4e3de185b83f795cbfe61f1d23bc3fc732081927 Mon Sep 17 00:00:00 2001
From: Luke
Date: Sat, 19 Jul 2025 00:09:17 +0800
Subject: [PATCH 056/100] =?UTF-8?q?refactor:=E9=87=8D=E6=9E=84=20PRINT=20?=
=?UTF-8?q?=E5=92=8C=20PRINTLN=20=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E8=BE=93=E5=87=BA=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 重构了 PRINT 和 PRINTLN 指令的实现,支持更多数据类型输出
- 新增通用的 output辅助方法,统一处理各种类型的输出
- 扩展了输出功能,支持基本类型、数组和任意对象的打印
- 优化了代码结构,提高了可读性和可维护性
---
.../system/control/SyscallCommand.java | 149 +++++++++++-------
1 file changed, 91 insertions(+), 58 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
index 39e63e7..eebcd28 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
@@ -46,42 +46,7 @@ import static java.nio.file.StandardOpenOption.*;
*/
public class SyscallCommand implements Command {
- /*------------------------------------ 工具方法 ------------------------------------*/
- /**
- * POSIX open 标志到 Java NIO OpenOption 的映射
- *
- * 将 Linux/UNIX 的 open 调用 flags 参数,转换为 Java NIO 的 OpenOption 集合。
- * 目前仅支持 WRITE(0x1)、READ、CREATE(0x40)、TRUNCATE(0x200)、APPEND(0x400)等常用标志。
- *
- *
- * @param flags POSIX 风格 open 标志(如 O_WRONLY=0x1, O_CREAT=0x40 等)
- * @return 映射后的 OpenOption 集合
- */
- private static Set flagsToOptions(int flags) {
- Set opts = new HashSet<>();
- // 0x1 = WRITE,否则默认 READ
- if ((flags & 0x1) != 0) opts.add(WRITE);
- else opts.add(READ);
- if ((flags & 0x40) != 0) opts.add(CREATE);
- if ((flags & 0x200) != 0) opts.add(TRUNCATE_EXISTING);
- if ((flags & 0x400) != 0) opts.add(APPEND);
- return opts;
- }
-
- /**
- * 统一异常处理:
- *
- * 捕获 syscall 内部所有异常,将 -1 压入操作数栈,表示系统调用失败(暂不区分错误类型)。
- * 常见异常如文件不存在、权限不足、通道类型不符、网络故障等。
- *
- *
- * @param stack 当前操作数栈
- * @param e 捕获的异常对象
- */
- private static void pushErr(OperandStack stack, Exception e) {
- stack.push(-1); // 目前统一用 -1,后续可按异常类型/errno 映射
- }
/*--------------------------------------------------------------------------------*/
@@ -92,10 +57,10 @@ public class SyscallCommand implements Command {
* 支持基础文件、网络、管道等 I/O 操作,并对异常统一处理。
*
*
- * @param parts 指令字符串数组,parts[1] 为子命令
- * @param pc 当前指令计数器
- * @param stack 操作数栈
- * @param locals 局部变量表
+ * @param parts 指令字符串数组,parts[1] 为子命令
+ * @param pc 当前指令计数器
+ * @param stack 操作数栈
+ * @param locals 局部变量表
* @param callStack 调用栈
* @return 下一条指令的 pc 值(默认 pc+1)
*/
@@ -345,35 +310,24 @@ public class SyscallCommand implements Command {
/*
* PRINT —— 控制台输出(无换行)。
- * 入栈顺序: data(String 或 byte[])
+ * 入栈顺序: data(任意基本类型或其包装类型、String、byte[] 等)
* 出栈顺序: data
* 返回 0
*/
case "PRINT" -> {
Object dataObj = stack.pop();
- if (dataObj instanceof byte[] b) {
- System.out.print(new String(b));
- } else {
- System.out.print(dataObj);
- }
- stack.push(0); // 表示成功
+ output(dataObj, false);
+ stack.push(0); // success
}
- /*
- * PRINTLN —— 控制台输出(自动换行)。
- * 入栈顺序: data(String 或 byte[])
- * 出栈顺序: data
- * 返回 0
- */
+
+ /* PRINTLN —— 控制台输出(自动换行)。*/
case "PRINTLN" -> {
Object dataObj = stack.pop();
- if (dataObj instanceof byte[] b) {
- System.out.println(new String(b));
- } else {
- System.out.println(dataObj);
- }
- stack.push(0); // 表示成功
+ output(dataObj, true);
+ stack.push(0); // success
}
+
/*==================== 其它未实现/扩展命令 ====================*/
/*
@@ -389,4 +343,83 @@ public class SyscallCommand implements Command {
// 默认:下一条指令
return pc + 1;
}
+
+ /*------------------------------------ 工具方法 ------------------------------------*/
+
+ /**
+ * POSIX open 标志到 Java NIO OpenOption 的映射
+ *
+ * 将 Linux/UNIX 的 open 调用 flags 参数,转换为 Java NIO 的 OpenOption 集合。
+ * 目前仅支持 WRITE(0x1)、READ、CREATE(0x40)、TRUNCATE(0x200)、APPEND(0x400)等常用标志。
+ *
+ *
+ * @param flags POSIX 风格 open 标志(如 O_WRONLY=0x1, O_CREAT=0x40 等)
+ * @return 映射后的 OpenOption 集合
+ */
+ private static Set flagsToOptions(int flags) {
+ Set opts = new HashSet<>();
+ // 0x1 = WRITE,否则默认 READ
+ if ((flags & 0x1) != 0) opts.add(WRITE);
+ else opts.add(READ);
+ if ((flags & 0x40) != 0) opts.add(CREATE);
+ if ((flags & 0x200) != 0) opts.add(TRUNCATE_EXISTING);
+ if ((flags & 0x400) != 0) opts.add(APPEND);
+ return opts;
+ }
+
+ /**
+ * 统一异常处理:
+ *
+ * 捕获 syscall 内部所有异常,将 -1 压入操作数栈,表示系统调用失败(暂不区分错误类型)。
+ * 常见异常如文件不存在、权限不足、通道类型不符、网络故障等。
+ *
+ *
+ * @param stack 当前操作数栈
+ * @param e 捕获的异常对象
+ */
+ private static void pushErr(OperandStack stack, Exception e) {
+ stack.push(-1); // 目前统一用 -1,后续可按异常类型/errno 映射
+ }
+
+ /**
+ * 统一的控制台输出辅助方法,支持:
+ *
+ * - 所有基本类型及其包装类(int、double、long、float…)
+ * - String、byte[]、char[] 以及其他原生数组
+ * - 任意 Object(调用 {@code toString})
+ *
+ *
+ * @param obj 要输出的对象
+ * @param newline 是否追加换行
+ */
+ private static void output(Object obj, boolean newline) {
+ String str;
+ if (obj == null) {
+ str = "null";
+ } else if (obj instanceof byte[] bytes) {
+ str = new String(bytes);
+ } else if (obj.getClass().isArray()) {
+ str = arrayToString(obj);
+ } else {
+ str = obj.toString();
+ }
+ if (newline) System.out.println(str);
+ else System.out.print(str);
+ }
+
+ /**
+ * 将各种原生数组转换成可读字符串。
+ */
+ private static String arrayToString(Object array) {
+ if (array instanceof int[] a) return Arrays.toString(a);
+ if (array instanceof long[] a) return Arrays.toString(a);
+ if (array instanceof double[] a) return Arrays.toString(a);
+ if (array instanceof float[] a) return Arrays.toString(a);
+ if (array instanceof short[] a) return Arrays.toString(a);
+ if (array instanceof char[] a) return Arrays.toString(a);
+ if (array instanceof byte[] a) return Arrays.toString(a);
+ if (array instanceof boolean[] a) return Arrays.toString(a);
+ if (array instanceof Object[] a) return Arrays.deepToString(a);
+ return "Unsupported array";
+ }
}
From 64cefebee542f7ae263ca1896363a6ae143f8a36 Mon Sep 17 00:00:00 2001
From: Luke
Date: Sat, 19 Jul 2025 17:04:49 +0800
Subject: [PATCH 057/100] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=20BuiltinUti?=
=?UTF-8?q?ls=20=E6=A0=87=E5=87=86=E5=BA=93=E5=B9=B6=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=9C=BA=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 重构 BuiltinTypeRegistry 类,扩展内置类型和模块的注册功能
- 新增 BuiltinUtils 标准库模块,提供 print 和 println 函数
- 实现 syscall 内核函数,供 BuiltinUtils 内部使用
- 更新测试用例,添加 Demo14 项目以验证新功能
---
.run/测试.run.xml | 1 -
playground/Demo/Demo14/BuiltinUtils.snow | 19 ++++
playground/Demo/Demo14/Main.snow | 11 +++
.../semantic/core/BuiltinTypeRegistry.java | 90 +++++++++++--------
4 files changed, 85 insertions(+), 36 deletions(-)
create mode 100644 playground/Demo/Demo14/BuiltinUtils.snow
create mode 100644 playground/Demo/Demo14/Main.snow
diff --git a/.run/测试.run.xml b/.run/测试.run.xml
index 5000363..c37e7f3 100644
--- a/.run/测试.run.xml
+++ b/.run/测试.run.xml
@@ -3,7 +3,6 @@
-
diff --git a/playground/Demo/Demo14/BuiltinUtils.snow b/playground/Demo/Demo14/BuiltinUtils.snow
new file mode 100644
index 0000000..d915ee8
--- /dev/null
+++ b/playground/Demo/Demo14/BuiltinUtils.snow
@@ -0,0 +1,19 @@
+module: BuiltinUtils
+ function: print
+ parameter:
+ declare msg: int
+ return_type: void
+ body:
+ syscall("PRINT",1)
+ end body
+ end function
+
+ function: println
+ parameter:
+ declare msg: int
+ return_type: void
+ body:
+ syscall("PRINTLN",1)
+ end body
+ end function
+end module
diff --git a/playground/Demo/Demo14/Main.snow b/playground/Demo/Demo14/Main.snow
new file mode 100644
index 0000000..baf23e4
--- /dev/null
+++ b/playground/Demo/Demo14/Main.snow
@@ -0,0 +1,11 @@
+module: Main
+ import: BuiltinUtils
+
+ function: main
+ return_type: void
+ body:
+ BuiltinUtils.print(1)
+ BuiltinUtils.println(2)
+ end body
+ end function
+end module
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
index d1566ab..3e69f38 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
@@ -1,54 +1,74 @@
package org.jcnc.snow.compiler.semantic.core;
-import org.jcnc.snow.compiler.semantic.type.*;
+import org.jcnc.snow.compiler.semantic.type.BuiltinType;
+import org.jcnc.snow.compiler.semantic.type.FunctionType;
+import org.jcnc.snow.compiler.semantic.type.Type;
-import java.util.Map;
+import java.util.*;
/**
- * {@code BuiltinTypeRegistry} 是内置类型和内置模块的集中注册中心。
- *
- * 本类主要负责:
+ * 语言全部内置类型 / 模块 / 函数的注册中心。
+ *
+ *
目前同时注册:
*
- * - 定义语言中所有可识别的基础类型(如 int、float、string 等);
- * - 在语义分析初始化时,将内置模块(如 {@code BuiltinUtils})注册到上下文中;
- * - 提供对内置类型的快速查找支持。
+ * - 所有基础类型(byte、short、int …)
+ * - 标准库模块 BuiltinUtils —— 仅声明函数签名,真正实现写在 Snow 源码中
+ * - 运行时内核函数 syscall —— 供标准库内部实现调用
*
- * 该类为纯工具类,所有成员均为静态,不可实例化。
*/
public final class BuiltinTypeRegistry {
- /**
- * 内置类型映射表: 将类型名称字符串映射到对应的 {@link Type} 实例。
- *
- * 用于类型解析过程(如解析变量声明或函数返回类型)中,
- * 将用户源码中的类型字符串转换为语义类型对象。
- */
- public static final Map BUILTIN_TYPES = Map.of(
- "int", BuiltinType.INT,
- "long", BuiltinType.LONG,
- "short", BuiltinType.SHORT,
- "byte", BuiltinType.BYTE,
- "float", BuiltinType.FLOAT,
- "double", BuiltinType.DOUBLE,
- "string", BuiltinType.STRING,
- "boolean", BuiltinType.BOOLEAN,
- "void", BuiltinType.VOID
- );
+ /** 基础类型表:名称 → Type */
+ public static final Map BUILTIN_TYPES;
+ static {
+ Map t = new HashMap<>();
+ t.put("byte", BuiltinType.BYTE);
+ t.put("short", BuiltinType.SHORT);
+ t.put("int", BuiltinType.INT);
+ t.put("long", BuiltinType.LONG);
+ t.put("float", BuiltinType.FLOAT);
+ t.put("double", BuiltinType.DOUBLE);
+ t.put("string", BuiltinType.STRING);
+ t.put("void", BuiltinType.VOID);
+ BUILTIN_TYPES = Collections.unmodifiableMap(t);
+ }
- /**
- * 私有构造函数,禁止实例化。
- */
private BuiltinTypeRegistry() { }
/**
- * 初始化语义上下文中与内置模块相关的内容。
- *
- * 当前实现将内置模块 {@code BuiltinUtils} 注册至上下文模块表中,
- * 使其在用户代码中可被访问(如 {@code BuiltinUtils.to_string(...)})。
- *
- * @param ctx 当前语义分析上下文
+ * 供语义分析阶段调用:向上下文注入所有内置模块 / 函数声明。
*/
public static void init(Context ctx) {
+ /* ---------- BuiltinUtils ---------- */
+ ModuleInfo utils = new ModuleInfo("BuiltinUtils");
+ // print(string): void
+ utils.getFunctions().put(
+ "print",
+ new FunctionType(
+ Collections.singletonList(BuiltinType.STRING),
+ BuiltinType.VOID
+ )
+ );
+
+ // println(string): void
+ utils.getFunctions().put(
+ "println",
+ new FunctionType(
+ Collections.singletonList(BuiltinType.STRING),
+ BuiltinType.VOID
+ )
+ );
+
+ // syscall(string, string): void —— 供 BuiltinUtils 内部使用
+ utils.getFunctions().put(
+ "syscall",
+ new FunctionType(
+ Arrays.asList(BuiltinType.STRING, BuiltinType.STRING),
+ BuiltinType.VOID
+ )
+ );
+
+ ctx.getModules().putIfAbsent("BuiltinUtils", utils);
}
}
From 72982c112751911cb9250257efe31d2d98ec254e Mon Sep 17 00:00:00 2001
From: Luke
Date: Sun, 20 Jul 2025 18:48:54 +0800
Subject: [PATCH 058/100] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=20Demo14?=
=?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.run/Demo14.run.xml | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 .run/Demo14.run.xml
diff --git a/.run/Demo14.run.xml b/.run/Demo14.run.xml
new file mode 100644
index 0000000..6071504
--- /dev/null
+++ b/.run/Demo14.run.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 983a287c422c9282d4d77fd8c4296759c06e5c7f Mon Sep 17 00:00:00 2001
From: Luke
Date: Sun, 20 Jul 2025 20:14:12 +0800
Subject: [PATCH 059/100] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20Builti?=
=?UTF-8?q?nUtils=20=E4=B8=AD=20syscall=20=E5=87=BD=E6=95=B0=E7=9A=84?=
=?UTF-8?q?=E5=8F=82=E6=95=B0=E7=B1=BB=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了 BuiltinUtils 中的 print 和 println函数
- 将 syscall 函数的第二个参数类型从 STRING 改为 INT
---
.../semantic/core/BuiltinTypeRegistry.java | 22 ++-----------------
1 file changed, 2 insertions(+), 20 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
index 3e69f38..e4bba8e 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
@@ -42,29 +42,11 @@ public final class BuiltinTypeRegistry {
/* ---------- BuiltinUtils ---------- */
ModuleInfo utils = new ModuleInfo("BuiltinUtils");
- // print(string): void
- utils.getFunctions().put(
- "print",
- new FunctionType(
- Collections.singletonList(BuiltinType.STRING),
- BuiltinType.VOID
- )
- );
-
- // println(string): void
- utils.getFunctions().put(
- "println",
- new FunctionType(
- Collections.singletonList(BuiltinType.STRING),
- BuiltinType.VOID
- )
- );
-
- // syscall(string, string): void —— 供 BuiltinUtils 内部使用
+ // syscall(string, int): void —— 供 BuiltinUtils 内部使用
utils.getFunctions().put(
"syscall",
new FunctionType(
- Arrays.asList(BuiltinType.STRING, BuiltinType.STRING),
+ Arrays.asList(BuiltinType.STRING, BuiltinType.INT),
BuiltinType.VOID
)
);
From b332c76ef88d8353569e776cdc5ed6d66d3893da Mon Sep 17 00:00:00 2001
From: Luke
Date: Sun, 20 Jul 2025 20:14:52 +0800
Subject: [PATCH 060/100] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=87=AA?=
=?UTF-8?q?=E5=8A=A8=E5=AF=BC=E5=85=A5=E6=A8=A1=E5=9D=97=E5=87=BD=E6=95=B0?=
=?UTF-8?q?=E8=B0=83=E7=94=A8=E6=94=AF=E6=8C=81=20-=20=E5=AE=9E=E7=8E=B0?=
=?UTF-8?q?=E4=BA=86=E5=9C=A8=E5=BD=93=E5=89=8D=E6=A8=A1=E5=9D=97=E6=9C=AA?=
=?UTF-8?q?=E6=89=BE=E5=88=B0=E7=9B=AE=E6=A0=87=E5=87=BD=E6=95=B0=E6=97=B6?=
=?UTF-8?q?=EF=BC=8C=E8=87=AA=E5=8A=A8=E9=81=8D=E5=8E=86=E6=89=80=E6=9C=89?=
=?UTF-8?q?=E5=B7=B2=E5=AF=BC=E5=85=A5=E6=A8=A1=E5=9D=97=E5=AF=BB=E6=89=BE?=
=?UTF-8?q?=E5=94=AF=E4=B8=80=E5=90=8C=E5=90=8D=E5=87=BD=E6=95=B0=E7=9A=84?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD=20-=20=E5=A6=82=E6=9E=9C=E5=A4=9A=E4=B8=AA?=
=?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=A8=A1=E5=9D=97=E5=90=AB=E6=9C=89=E5=90=8C?=
=?UTF-8?q?=E5=90=8D=E5=87=BD=E6=95=B0=EF=BC=8C=E4=BC=9A=E6=8A=A5=E9=94=99?=
=?UTF-8?q?=E6=8F=90=E7=A4=BA=E5=87=BD=E6=95=B0=E8=B0=83=E7=94=A8=E4=B8=8D?=
=?UTF-8?q?=E6=98=8E=E7=A1=AE=20-=20=E8=BF=99=E4=B8=AA=E6=94=B9=E5=8A=A8?=
=?UTF-8?q?=E6=89=A9=E5=B1=95=E4=BA=86=E5=87=BD=E6=95=B0=E8=B0=83=E7=94=A8?=
=?UTF-8?q?=E7=9A=84=E8=8C=83=E5=9B=B4=EF=BC=8C=E6=8F=90=E9=AB=98=E4=BA=86?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=9A=84=E7=81=B5=E6=B4=BB=E6=80=A7=E5=92=8C?=
=?UTF-8?q?=E5=8F=AF=E5=A4=8D=E7=94=A8=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/Demo/Demo14/BuiltinUtils.snow | 19 -----------
.../expression/CallExpressionAnalyzer.java | 34 +++++++++++++++++--
2 files changed, 32 insertions(+), 21 deletions(-)
delete mode 100644 playground/Demo/Demo14/BuiltinUtils.snow
diff --git a/playground/Demo/Demo14/BuiltinUtils.snow b/playground/Demo/Demo14/BuiltinUtils.snow
deleted file mode 100644
index d915ee8..0000000
--- a/playground/Demo/Demo14/BuiltinUtils.snow
+++ /dev/null
@@ -1,19 +0,0 @@
-module: BuiltinUtils
- function: print
- parameter:
- declare msg: int
- return_type: void
- body:
- syscall("PRINT",1)
- end body
- end function
-
- function: println
- parameter:
- declare msg: int
- return_type: void
- body:
- syscall("PRINTLN",1)
- end body
- end function
-end module
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java
index 8c2eddc..df0993c 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java
@@ -20,7 +20,7 @@ import java.util.List;
*
* 它负责处理类似 {@code callee(arg1, arg2, ...)} 形式的调用表达式,执行如下操作:
*
- * - 识别调用目标(支持模块成员函数调用和当前模块函数调用);
+ * - 识别调用目标(支持模块成员函数调用和当前模块函数调用,也支持自动在所有已导入模块中查找唯一同名函数);
* - 根据被调用函数的参数签名检查实参数量和类型的兼容性;
* - 支持数值参数的宽化转换(如 int → double);
* - 支持数值到字符串的隐式转换(自动视为调用 {@code to_string});
@@ -77,8 +77,38 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer
Date: Sun, 20 Jul 2025 20:15:07 +0800
Subject: [PATCH 061/100] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=E7=A4=BA?=
=?UTF-8?q?=E4=BE=8B=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/BugFarm/Bug1/Main.snow | 2 +-
playground/Demo/Demo14/Main.snow | 15 +++++++--------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/playground/BugFarm/Bug1/Main.snow b/playground/BugFarm/Bug1/Main.snow
index 3c4df88..3468433 100644
--- a/playground/BugFarm/Bug1/Main.snow
+++ b/playground/BugFarm/Bug1/Main.snow
@@ -2,7 +2,7 @@ module: Main
function: main
return_type: void
body:
- declare abc:string ="0"
+ declare abc:int =1
end body
end function
end module
diff --git a/playground/Demo/Demo14/Main.snow b/playground/Demo/Demo14/Main.snow
index baf23e4..42049ea 100644
--- a/playground/Demo/Demo14/Main.snow
+++ b/playground/Demo/Demo14/Main.snow
@@ -1,11 +1,10 @@
module: Main
- import: BuiltinUtils
+ import: BuiltinUtils
- function: main
- return_type: void
- body:
- BuiltinUtils.print(1)
- BuiltinUtils.println(2)
- end body
- end function
+ function: main
+ return_type: void
+ body:
+ syscall("PRINT",1)
+ end body
+ end function
end module
\ No newline at end of file
From 3aa38027c87334c0b2750e4cc9069d8fbab865da Mon Sep 17 00:00:00 2001
From: Luke
Date: Sun, 20 Jul 2025 20:45:17 +0800
Subject: [PATCH 062/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AF=B9?=
=?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=AD=97=E9=9D=A2=E9=87=8F=E7=9A=84?=
=?UTF-8?q?=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 ExpressionBuilder 类中增加了处理字符串字面量的逻辑
- 新增 buildStringLiteral 方法用于生成字符串常量寄存器
- 更新了 build 方法的 switch 语句,支持 StringLiteralNode 类型
- 优化了代码结构,提高了可读性和可维护性
---
.../ir/builder/ExpressionBuilder.java | 28 +++++++++++++++++--
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
index d56103a..31e2973 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
@@ -34,13 +34,14 @@ public record ExpressionBuilder(IRContext ctx) {
* 会根据节点的实际类型分别处理:
*
* - 数字字面量: 新建常量寄存器
+ * - 字符串字面量: 新建常量寄存器(字符串类型)
* - 布尔字面量: 生成值为 0 或 1 的常量寄存器
* - 标识符: 查找当前作用域中的寄存器
* - 二元表达式: 递归处理子表达式并进行相应运算
- * - 一元运算符:
+ *
- 一元运算符:
*
* -x(取负,生成 NEG_I32 指令)与
- * - code>!x(逻辑非,转换为
x == 0 比较指令)
+ * !x(逻辑非,转换为 x == 0 比较指令)
*
*
* - 函数调用: 生成对应的Call指令
@@ -51,11 +52,12 @@ public record ExpressionBuilder(IRContext ctx) {
* @return 该表达式的计算结果寄存器
* @throws IllegalStateException 如果遇到未定义的标识符或不支持的表达式类型
*/
-
public IRVirtualRegister build(ExpressionNode expr) {
return switch (expr) {
// 数字字面量
case NumberLiteralNode n -> buildNumberLiteral(n.value());
+ // 字符串字面量
+ case StringLiteralNode s -> buildStringLiteral(s.value());
// 布尔字面量
case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
// 标识符
@@ -69,6 +71,7 @@ public record ExpressionBuilder(IRContext ctx) {
case BinaryExpressionNode bin -> buildBinary(bin);
// 函数调用
case CallExpressionNode call -> buildCall(call);
+ // 一元表达式
case UnaryExpressionNode u -> buildUnary(u);
default -> throw new IllegalStateException(
"不支持的表达式类型: " + expr.getClass().getSimpleName());
@@ -111,6 +114,12 @@ public record ExpressionBuilder(IRContext ctx) {
// 数字字面量,直接加载到目标寄存器
case NumberLiteralNode n ->
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
+ // 字符串字面量,直接加载到目标寄存器
+ case StringLiteralNode s ->
+ InstructionFactory.loadConstInto(ctx, dest, new IRConstant(s.value()));
+ // 布尔字面量,直接加载到目标寄存器
+ case BoolLiteralNode b ->
+ InstructionFactory.loadConstInto(ctx, dest, new IRConstant(b.getValue() ? 1 : 0));
// 标识符,查找并move到目标寄存器
case IdentifierNode id -> {
IRVirtualRegister src = ctx.getScope().lookup(id.name());
@@ -223,6 +232,19 @@ public record ExpressionBuilder(IRContext ctx) {
return reg;
}
+ /**
+ * 处理字符串字面量,生成常量寄存器和加载指令。
+ *
+ * @param value 字符串内容
+ * @return 存放该字符串常量的寄存器
+ */
+ private IRVirtualRegister buildStringLiteral(String value) {
+ IRConstant constant = new IRConstant(value);
+ IRVirtualRegister reg = ctx.newRegister();
+ ctx.addInstruction(new LoadConstInstruction(reg, constant));
+ return reg;
+ }
+
/** 布尔字面量 → CONST (true=1,false=0)*/
private IRVirtualRegister buildBoolLiteral(boolean value) {
IRConstant constant = new IRConstant(value ? 1 : 0);
From c6067a875806f722721c1dac79e4dd3a4276d8d2 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 16:46:34 +0800
Subject: [PATCH 063/100] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=BC=95?=
=?UTF-8?q?=E7=94=A8=E7=B1=BB=E5=9E=8B=E5=B8=B8=E9=87=8F=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E5=8F=8D=E7=A0=81=E6=98=A0=E5=B0=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 OPCODE_MAP 中添加 R_PUSH、R_LOAD 和 R_STORE 指令- 优化反码映射逻辑,支持十六进制表示的指令码
- 在 getConstType 方法中增加对 String 类型的支持
---
.../snow/compiler/backend/utils/OpHelper.java | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java b/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java
index d006802..977c85e 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java
@@ -167,6 +167,9 @@ public final class OpHelper {
map.put("D2I", Integer.toString(VMOpCode.D2I));
map.put("D2L", Integer.toString(VMOpCode.D2L));
map.put("D2F", Integer.toString(VMOpCode.D2F));
+ map.put("R_PUSH", Integer.toString(VMOpCode.R_PUSH));
+ map.put("R_LOAD", Integer.toString(VMOpCode.R_LOAD));
+ map.put("R_STORE", Integer.toString(VMOpCode.R_STORE));
map.put("POP", Integer.toString(VMOpCode.POP));
map.put("DUP", Integer.toString(VMOpCode.DUP));
map.put("SWAP", Integer.toString(VMOpCode.SWAP));
@@ -180,7 +183,15 @@ public final class OpHelper {
OPCODE_MAP = Collections.unmodifiableMap(map);
Map revmap = new HashMap<>(); // reverse map
- OPCODE_MAP.forEach((key, value) -> revmap.put(Integer.parseInt(value), key));
+ OPCODE_MAP.forEach((key, value) -> {
+ int codeInt;
+ if (value.startsWith("0x") || value.startsWith("0X")) {
+ codeInt = Integer.parseInt(value.substring(2), 16);
+ } else {
+ codeInt = Integer.parseInt(value);
+ }
+ revmap.put(codeInt, key);
+ });
OPCODE_NAME_MAP = Collections.unmodifiableMap(revmap);
}
@@ -222,11 +233,13 @@ public final class OpHelper {
if (v instanceof Byte) return "B";
if (v instanceof Double) return "D";
if (v instanceof Float) return "F";
+ if (v instanceof String) return "R"; //引用类型
throw new IllegalStateException("Unknown const type: " + v.getClass());
}
/**
* 根据 opcode 数值的字符串形式获取指令名
+ *
* @param code 字符串形式的 opcode 数值
* @return opcode 对应的指令名
*/
@@ -236,6 +249,7 @@ public final class OpHelper {
/**
* 根据 opcode 获取指令名
+ *
* @param code opcode
* @return opcode 对应的指令名
*/
From 2cb428ed9ba992150f0761a92787a6bb3be3a007 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 16:48:50 +0800
Subject: [PATCH 064/100] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=BC=95?=
=?UTF-8?q?=E7=94=A8=E6=8E=A7=E5=88=B6=E5=91=BD=E4=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加 RPushCommand、RLoadCommand 和 RStoreCommand 三个引用控制命令类
- 在 CommandFactory 中注册这三个命令
---
.../org/jcnc/snow/vm/factories/CommandFactory.java | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java b/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
index dbdab0f..71479a3 100644
--- a/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
+++ b/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
@@ -6,6 +6,9 @@ import org.jcnc.snow.vm.commands.type.control.double64.*;
import org.jcnc.snow.vm.commands.type.control.float32.*;
import org.jcnc.snow.vm.commands.type.control.int32.*;
import org.jcnc.snow.vm.commands.type.control.long64.*;
+import org.jcnc.snow.vm.commands.type.control.ref.RLoadCommand;
+import org.jcnc.snow.vm.commands.type.control.ref.RPushCommand;
+import org.jcnc.snow.vm.commands.type.control.ref.RStoreCommand;
import org.jcnc.snow.vm.commands.type.control.short16.*;
import org.jcnc.snow.vm.commands.type.control.byte8.BAndCommand;
import org.jcnc.snow.vm.commands.type.control.byte8.BOrCommand;
@@ -62,6 +65,7 @@ public class CommandFactory {
static {
+
// region Type Control (0x0000-0x00BF)
// region Byte8 (0x0000-0x001F)
COMMANDS[VMOpCode.B_ADD] = new BAddCommand();
@@ -205,6 +209,7 @@ public class CommandFactory {
COMMANDS[VMOpCode.D_CL] = new DCLCommand();
COMMANDS[VMOpCode.D_CLE] = new DCLECommand();
// endregion
+
// endregion
// region Type Conversion (0x00C0-0x00DF)
@@ -245,6 +250,12 @@ public class CommandFactory {
COMMANDS[VMOpCode.D2F] = new D2FCommand();
// endregion
+ // region Reference Control (0x00E0-0x00EF)
+ COMMANDS[VMOpCode.R_PUSH] = new RPushCommand();
+ COMMANDS[VMOpCode.R_LOAD] = new RLoadCommand();
+ COMMANDS[VMOpCode.R_STORE] = new RStoreCommand();
+ // endregion
+
// region Stack Control (0x0100-0x01FF)
COMMANDS[VMOpCode.POP] = new PopCommand();
COMMANDS[VMOpCode.DUP] = new DupCommand();
From fec9fe3527ac8111b82182980a775e0035b4e386 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 16:51:30 +0800
Subject: [PATCH 065/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20Builti?=
=?UTF-8?q?nTypeRegistry=20=E7=B1=BB=E5=B9=B6=E4=BC=98=E5=8C=96=E6=96=87?=
=?UTF-8?q?=E6=A1=A3=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 重新整理基础类型表,添加 boolean 类型
- 优化文档注释,增加类和方法的详细描述
- 改进代码结构,提高可读性和可维护性
---
.../semantic/core/BuiltinTypeRegistry.java | 61 +++++++++++++------
1 file changed, 41 insertions(+), 20 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
index e4bba8e..9f266c9 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/BuiltinTypeRegistry.java
@@ -7,42 +7,62 @@ import org.jcnc.snow.compiler.semantic.type.Type;
import java.util.*;
/**
- * 语言全部内置类型 / 模块 / 函数的注册中心。
+ * BuiltinTypeRegistry - 语言全部内置类型/模块/函数注册中心
*
- * 目前同时注册:
+ *
+ * 该类统一注册编译器需要用到的所有基础类型、标准库模块与内核函数,供语义分析及类型检查阶段使用。
*
- * - 所有基础类型(byte、short、int …)
- * - 标准库模块 BuiltinUtils —— 仅声明函数签名,真正实现写在 Snow 源码中
- * - 运行时内核函数 syscall —— 供标准库内部实现调用
+ * - 所有基础类型(byte、short、int、long、float、double、string、boolean、void)
+ * - 标准库模块 BuiltinUtils(仅注册函数签名,具体实现由 Snow 语言源码实现)
+ * - 内核函数 syscall(供标准库内部实现调用)
*
+ *
*/
public final class BuiltinTypeRegistry {
- /** 基础类型表:名称 → Type */
+ /**
+ * 基础类型表:类型名称 → Type 实例
+ *
+ * 本 Map 静态初始化,注册所有 Snow 语言基础类型,供类型检查与类型推断使用。
+ *
+ */
public static final Map BUILTIN_TYPES;
static {
Map t = new HashMap<>();
- t.put("byte", BuiltinType.BYTE);
- t.put("short", BuiltinType.SHORT);
- t.put("int", BuiltinType.INT);
- t.put("long", BuiltinType.LONG);
- t.put("float", BuiltinType.FLOAT);
- t.put("double", BuiltinType.DOUBLE);
- t.put("string", BuiltinType.STRING);
- t.put("void", BuiltinType.VOID);
- BUILTIN_TYPES = Collections.unmodifiableMap(t);
+ t.put("byte", BuiltinType.BYTE); // 字节型
+ t.put("short", BuiltinType.SHORT); // 短整型
+ t.put("int", BuiltinType.INT); // 整型
+ t.put("long", BuiltinType.LONG); // 长整型
+ t.put("float", BuiltinType.FLOAT); // 单精度浮点
+ t.put("double", BuiltinType.DOUBLE); // 双精度浮点
+ t.put("string", BuiltinType.STRING); // 字符串
+ t.put("void", BuiltinType.VOID); // 无返回
+ t.put("boolean", BuiltinType.BOOLEAN); // 布尔类型
+
+ BUILTIN_TYPES = Collections.unmodifiableMap(t); // 不可变映射,防止被意外更改
}
+ /**
+ * 私有构造方法,禁止实例化
+ */
private BuiltinTypeRegistry() { }
/**
- * 供语义分析阶段调用:向上下文注入所有内置模块 / 函数声明。
+ * 初始化内置模块和函数声明
+ *
+ *
+ * 语义分析阶段调用,将所有基础模块与函数声明注册到语义上下文中。
+ * - 目前注册 BuiltinUtils 标准库模块(仅注册签名,不负责具体实现)。
+ * - syscall 函数注册到 BuiltinUtils 内,供标准库内部调用。
+ *
+ *
+ * @param ctx 全局语义分析上下文,持有模块表
*/
public static void init(Context ctx) {
- /* ---------- BuiltinUtils ---------- */
- ModuleInfo utils = new ModuleInfo("BuiltinUtils");
+ /* ---------- 注册标准库 os ---------- */
+ ModuleInfo utils = new ModuleInfo("os");
- // syscall(string, int): void —— 供 BuiltinUtils 内部使用
+ // syscall(string, int): void —— 供标准库内部使用的调用接口
utils.getFunctions().put(
"syscall",
new FunctionType(
@@ -51,6 +71,7 @@ public final class BuiltinTypeRegistry {
)
);
- ctx.getModules().putIfAbsent("BuiltinUtils", utils);
+ // 注册 BuiltinUtils 到上下文的模块表(若已存在则不重复添加)
+ ctx.getModules().putIfAbsent("os", utils);
}
}
From 7a52c7dd78f766114669d78e132a68d8acae06a9 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 16:56:18 +0800
Subject: [PATCH 066/100] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20syscall=20?=
=?UTF-8?q?=E8=B0=83=E7=94=A8=E7=9A=84=20VM=E6=8C=87=E4=BB=A4=E7=94=9F?=
=?UTF-8?q?=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增对 syscall 调用的特殊处理逻辑
- 支持 IRConstant 直接字面量和虚拟寄存器绑定的字符串常量作为 syscall 子命令
- 实现了 syscall 调用中参数压栈和 SYSCALL指令生成的逻辑
-优化了普通函数调用的指令生成流程
---
.../backend/generator/CallGenerator.java | 113 ++++++++++++++++--
1 file changed, 101 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java
index 84fe8cf..0f7c9c8 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java
@@ -4,53 +4,142 @@ import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.common.GlobalFunctionTable;
+import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
+import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
+import org.jcnc.snow.vm.engine.VMOpCode;
-import java.util.Map;
+import java.util.*;
/**
- * 将 IR CallInstruction 生成 VM 指令
+ * CallGenerator - 将 IR {@code CallInstruction} 生成 VM 指令
+ *
+ *
+ * 本类负责将中间表示(IR)中的函数调用指令 {@link CallInstruction} 转换为虚拟机(VM)指令。
+ * 支持普通函数调用和特殊的 syscall 指令转换。
+ *
+ *
+ *
+ * 能力说明:
+ *
+ * - 支持识别 {@code IRConstant} 直接字面量或已绑定到虚拟寄存器的字符串常量,直接降级为 {@code SYSCALL <SUBCMD>} 指令。
+ * - 对普通函数,完成参数加载、调用、返回值保存等指令生成。
+ *
+ *
*/
public class CallGenerator implements InstructionGenerator {
+ /**
+ * <虚拟寄存器 id, 对应的字符串常量>
+ * 用于记录虚拟寄存器与其绑定字符串常量的映射。由 {@link LoadConstGenerator} 在编译期间填充。
+ */
+ private static final Map STRING_CONST_POOL = new HashMap<>();
+
+ /**
+ * 注册字符串常量到虚拟寄存器
+ * 供 {@link LoadConstGenerator} 在加载字符串常量时调用。
+ *
+ * @param regId 虚拟寄存器 id
+ * @param value 字符串常量值
+ */
+ public static void registerStringConst(int regId, String value) {
+ STRING_CONST_POOL.put(regId, value);
+ }
+
+ /**
+ * 返回本生成器支持的 IR 指令类型(CallInstruction)
+ */
@Override
public Class supportedClass() {
return CallInstruction.class;
}
+ /**
+ * 生成 VM 指令的主逻辑
+ *
+ * @param ins 当前 IR 指令(函数调用)
+ * @param out 指令输出构建器
+ * @param slotMap IR 虚拟寄存器与物理槽位映射
+ * @param currentFn 当前函数名
+ */
@Override
public void generate(CallInstruction ins,
VMProgramBuilder out,
Map slotMap,
String currentFn) {
- /* 1. 推断返回值类型(用于非 void 情况下的 I/F/D/L_STORE) */
- char retType = 'I';
+ /* ========== 特殊处理 syscall 调用 ========== */
+ if ("syscall".equals(ins.getFunctionName()) ||
+ ins.getFunctionName().endsWith(".syscall")) {
+
+ List args = ins.getArguments();
+ if (args.isEmpty()) {
+ throw new IllegalStateException("syscall 需要子命令参数");
+ }
+
+ // ---------- 0. 解析 syscall 子命令 ----------
+ // 子命令支持 IRConstant(直接字面量)或虚拟寄存器(需已绑定字符串)
+ String subcmd;
+ IRValue first = args.getFirst();
+
+ if (first instanceof IRConstant(Object value)) { // 直接字面量
+ if (!(value instanceof String s))
+ throw new IllegalStateException("syscall 第一个参数必须是字符串常量");
+ subcmd = s.toUpperCase(Locale.ROOT);
+
+ } else if (first instanceof IRVirtualRegister vr) { // 虚拟寄存器
+ // 从常量池中查找是否已绑定字符串
+ subcmd = Optional.ofNullable(STRING_CONST_POOL.get(vr.id()))
+ .orElseThrow(() ->
+ new IllegalStateException("未找到 syscall 字符串常量绑定: " + vr));
+ subcmd = subcmd.toUpperCase(Locale.ROOT);
+
+ } else {
+ throw new IllegalStateException("syscall 第一个参数必须是字符串常量");
+ }
+
+ // ---------- 1. 压栈其余 syscall 参数(index 1 开始) ----------
+ for (int i = 1; i < args.size(); i++) {
+ IRVirtualRegister vr = (IRVirtualRegister) args.get(i);
+ int slotId = slotMap.get(vr);
+ char t = out.getSlotType(slotId);
+ if (t == '\0') t = 'I'; // 默认整型
+ out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
+ }
+
+ // ---------- 2. 生成 SYSCALL 指令 ----------
+ out.emit(VMOpCode.SYSCALL + " " + subcmd);
+ return; // syscall 无返回值,直接返回
+ }
+
+ /* ========== 普通函数调用 ========== */
+
+ // ---------- 1. 推断返回值类型(非 void 返回时用) ----------
+ char retType = 'I'; // 默认为整型
if (!ins.getArguments().isEmpty()) {
int firstSlot = slotMap.get((IRVirtualRegister) ins.getArguments().getFirst());
retType = out.getSlotType(firstSlot);
if (retType == '\0') retType = 'I';
}
- /* 2. 依次加载实参 */
+ // ---------- 2. 加载全部实参 ----------
for (var arg : ins.getArguments()) {
int slotId = slotMap.get((IRVirtualRegister) arg);
char t = out.getSlotType(slotId);
- if (t == '\0') t = 'I';
+ if (t == '\0') t = 'I'; // 默认整型
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
}
- /* 3. 发出 CALL 指令 */
+ // ---------- 3. 发出 CALL 指令 ----------
out.emitCall(ins.getFunctionName(), ins.getArguments().size());
- /* 3.5 若被调用函数返回 void,则无需保存返回值 */
- String rt = GlobalFunctionTable.getReturnType(ins.getFunctionName());
- if ("void".equals(rt)) {
- return; // 直接结束,无 _STORE
+ // ---------- 3.5 如果为 void 返回直接结束 ----------
+ if ("void".equals(GlobalFunctionTable.getReturnType(ins.getFunctionName()))) {
+ return;
}
- /* 4. 保存返回值到目标槽 */
+ // ---------- 4. 保存返回值 ----------
int destSlot = slotMap.get(ins.getDest());
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
out.setSlotType(destSlot, retType);
From 970976ecc5ad72e031b2167437056c5480182dc7 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 16:57:50 +0800
Subject: [PATCH 067/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20VM?=
=?UTF-8?q?=E9=80=80=E5=87=BA=E6=97=B6=E7=9A=84=E6=8F=90=E7=A4=BA=E4=BF=A1?=
=?UTF-8?q?=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 VMLauncher 启动后增加提示信息 "=== Launching VM ==="
- 在 VM 退出后增加提示信息 "=== VM exited ==="
---
src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
index f570bee..844c2fc 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
@@ -220,6 +220,7 @@ public final class CompileTask implements Task {
if (runAfterCompile) {
System.out.println("\n=== Launching VM ===");
VMLauncher.main(new String[]{outputFile.toString()});
+ System.out.println("\n=== VM exited ===");
}
return 0;
From 3aef7cd9065fdaf4123a4ff0e9cbe3baca029491 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:06:40 +0800
Subject: [PATCH 068/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20Expres?=
=?UTF-8?q?sionBuilder=20=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 优化了代码结构,提高了代码的可读性和可维护性
- 添加了详细的注释,解释了各个方法的功能和实现细节
- 改进了对不同表达式类型的处理逻辑,增强了表达式构建的能力
- 优化了寄存器的使用和管理,提高了 IR 指令生成的效率
---
.../ir/builder/ExpressionBuilder.java | 319 ++++++++++--------
1 file changed, 171 insertions(+), 148 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
index 31e2973..58eccfc 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java
@@ -5,130 +5,117 @@ import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;
import org.jcnc.snow.compiler.ir.utils.ComparisonUtils;
+import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
-import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
import org.jcnc.snow.compiler.parser.ast.*;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import java.util.*;
/**
- * 表达式构建器
+ * ExpressionBuilder - 表达式 → IR 构建器
+ *
*
- * 该类负责将抽象语法树(AST)的表达式节点转换为中间表示(IR)指令和虚拟寄存器,
- * 是编译器IR生成阶段的核心工具。
- *
- * 主要职责包括:
+ * 负责将 AST 表达式节点递归转换为 IR 虚拟寄存器操作,并生成对应的 IR 指令序列。
+ * 支持字面量、标识符、二元表达式、一元表达式、函数调用等多种类型表达式。
+ *
+ *
+ *
+ * 主要功能:
*
- * - 将数字字面量、标识符、二元表达式、函数调用等AST表达式节点,翻译为对应的IR指令序列
- * - 管理并分配虚拟寄存器,保证IR操作的数据流正确
+ * - 将表达式节点映射为虚拟寄存器
+ * - 为每种表达式类型生成对应 IR 指令
+ * - 支持表达式嵌套的递归构建
+ * - 支持写入指定目标寄存器,避免冗余的 move 指令
*
- *
+ *
*/
public record ExpressionBuilder(IRContext ctx) {
+ /* ───────────────── 顶层入口 ───────────────── */
+
/**
- * 构建并返回某个表达式节点对应的虚拟寄存器。
+ * 构建任意 AST 表达式节点,自动为其分配一个新的虚拟寄存器,并返回该寄存器。
*
- * 会根据节点的实际类型分别处理:
- *
- * - 数字字面量: 新建常量寄存器
- * - 字符串字面量: 新建常量寄存器(字符串类型)
- * - 布尔字面量: 生成值为 0 或 1 的常量寄存器
- * - 标识符: 查找当前作用域中的寄存器
- * - 二元表达式: 递归处理子表达式并进行相应运算
- * - 一元运算符:
- *
- * -x(取负,生成 NEG_I32 指令)与
- * !x(逻辑非,转换为 x == 0 比较指令)
- *
- *
- * - 函数调用: 生成对应的Call指令
- * - 其它类型不支持,抛出异常
- *
+ *
+ * 这是表达式 IR 生成的核心入口。它会根据不同的表达式类型进行分派,递归构建 IR 指令。
+ *
*
- * @param expr 要转换的表达式AST节点
- * @return 该表达式的计算结果寄存器
- * @throws IllegalStateException 如果遇到未定义的标识符或不支持的表达式类型
+ * @param expr 任意 AST 表达式节点
+ * @return 存储该表达式结果的虚拟寄存器
+ * @throws IllegalStateException 遇到不支持的表达式类型或未定义标识符
*/
public IRVirtualRegister build(ExpressionNode expr) {
return switch (expr) {
- // 数字字面量
+ // 数字字面量,例如 123、3.14
case NumberLiteralNode n -> buildNumberLiteral(n.value());
- // 字符串字面量
+ // 字符串字面量,例如 "abc"
case StringLiteralNode s -> buildStringLiteral(s.value());
- // 布尔字面量
+ // 布尔字面量,例如 true / false
case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
- // 标识符
+ // 标识符(变量名),如 a、b
case IdentifierNode id -> {
+ // 查找当前作用域中的变量寄存器
IRVirtualRegister reg = ctx.getScope().lookup(id.name());
if (reg == null)
throw new IllegalStateException("未定义标识符: " + id.name());
yield reg;
}
- // 二元表达式
+ // 二元表达式(如 a+b, x==y)
case BinaryExpressionNode bin -> buildBinary(bin);
- // 函数调用
- case CallExpressionNode call -> buildCall(call);
- // 一元表达式
- case UnaryExpressionNode u -> buildUnary(u);
+ // 函数/方法调用表达式
+ case CallExpressionNode call -> buildCall(call);
+ // 一元表达式(如 -a, !a)
+ case UnaryExpressionNode un -> buildUnary(un);
+
+ // 默认分支:遇到未知表达式类型则直接抛异常
default -> throw new IllegalStateException(
"不支持的表达式类型: " + expr.getClass().getSimpleName());
};
}
- /** 处理一元表达式 */
- private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
- String op = un.operator();
- IRVirtualRegister val = build(un.operand());
-
- // -x → NEG_*(根据类型自动选择位宽)
- if (op.equals("-")) {
- IRVirtualRegister dest = ctx.newRegister();
- IROpCode code = ExpressionUtils.negOp(un.operand());
- ctx.addInstruction(new UnaryOperationInstruction(code, dest, val));
- return dest;
- }
-
- // !x → (x == 0)
- if (op.equals("!")) {
- IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
- return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, val, zero);
- }
-
- throw new IllegalStateException("未知一元运算符: " + op);
- }
+ /* ───────────────── 写入指定寄存器 ───────────────── */
/**
- * 直接将表达式计算结果写入指定的目标寄存器(dest)。
- *
- * 与{@link #build(ExpressionNode)}类似,但支持目标寄存器复用(避免不必要的move)。
+ * 生成表达式,并将其结果直接写入目标寄存器,避免冗余的 move 操作。
*
- * @param node 表达式AST节点
- * @param dest 目标寄存器
- * @throws IllegalStateException 未定义标识符/不支持的表达式类型时报错
+ *
+ * 某些简单表达式(如字面量、变量名)可以直接写入目标寄存器;复杂表达式则会先 build 到新寄存器,再 move 到目标寄存器。
+ *
+ *
+ * @param node 要生成的表达式节点
+ * @param dest 目标虚拟寄存器(用于存储结果)
*/
public void buildInto(ExpressionNode node, IRVirtualRegister dest) {
switch (node) {
- // 数字字面量,直接加载到目标寄存器
+ // 数字字面量:生成 loadConst 指令写入目标寄存器
case NumberLiteralNode n ->
- InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
- // 字符串字面量,直接加载到目标寄存器
+ InstructionFactory.loadConstInto(
+ ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
+
+ // 字符串字面量:生成 loadConst 指令写入目标寄存器
case StringLiteralNode s ->
- InstructionFactory.loadConstInto(ctx, dest, new IRConstant(s.value()));
- // 布尔字面量,直接加载到目标寄存器
+ InstructionFactory.loadConstInto(
+ ctx, dest, new IRConstant(s.value()));
+
+ // 布尔字面量:转换为 int 1/0,生成 loadConst
case BoolLiteralNode b ->
- InstructionFactory.loadConstInto(ctx, dest, new IRConstant(b.getValue() ? 1 : 0));
- // 标识符,查找并move到目标寄存器
+ InstructionFactory.loadConstInto(
+ ctx, dest, new IRConstant(b.getValue() ? 1 : 0));
+
+ // 标识符:查表获取原寄存器,然后 move 到目标寄存器
case IdentifierNode id -> {
IRVirtualRegister src = ctx.getScope().lookup(id.name());
- if (src == null) throw new IllegalStateException("未定义标识符: " + id.name());
+ if (src == null)
+ throw new IllegalStateException("未定义标识符: " + id.name());
InstructionFactory.move(ctx, src, dest);
}
- // 二元表达式,直接写入目标寄存器
+
+ // 二元表达式:递归生成并写入目标寄存器
case BinaryExpressionNode bin -> buildBinaryInto(bin, dest);
- // 其他表达式,先递归生成寄存器,再move到目标寄存器
+
+ // 其它复杂情况:先 build 到新寄存器,再 move 到目标寄存器
default -> {
IRVirtualRegister tmp = build(node);
InstructionFactory.move(ctx, tmp, dest);
@@ -136,41 +123,100 @@ public record ExpressionBuilder(IRContext ctx) {
}
}
+ /* ───────────────── 具体表达式类型 ───────────────── */
+
/**
- * 构建二元表达式的IR,生成新寄存器存储结果。
- *
- * 先递归构建左右操作数,之后根据操作符类别(算术或比较)决定生成的IR操作码,
- * 并生成对应的二元运算指令。
+ * 一元表达式构建
*
- * @param bin 二元表达式节点
- * @return 存放结果的虚拟寄存器
+ *
+ * 支持算术取负(-a)、逻辑非(!a)等一元运算符。
+ *
+ *
+ * @param un 一元表达式节点
+ * @return 结果存储的新分配虚拟寄存器
*/
- private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
- String op = bin.operator();
- IRVirtualRegister left = build(bin.left());
- IRVirtualRegister right = build(bin.right());
+ private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
+ // 递归生成操作数的寄存器
+ IRVirtualRegister src = build(un.operand());
+ // 分配目标寄存器
+ IRVirtualRegister dest = ctx.newRegister();
- // 1. 比较运算
- if (ComparisonUtils.isComparisonOperator(op)) {
- return InstructionFactory.binOp(
- ctx,
- ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
- left, right);
+ switch (un.operator()) {
+ // 算术负号:生成取负指令
+ case "-" -> ctx.addInstruction(
+ new UnaryOperationInstruction(ExpressionUtils.negOp(un.operand()), dest, src));
+ // 逻辑非:等价于 a == 0,生成比较指令
+ case "!" -> {
+ IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
+ return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, src, zero);
+ }
+ // 其它一元运算符不支持,抛异常
+ default -> throw new IllegalStateException("未知一元运算符: " + un.operator());
}
-
- // 2. 其他算术 / 逻辑运算
- IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
- if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
- return InstructionFactory.binOp(ctx, code, left, right);
+ return dest;
}
/**
- * 将二元表达式的结果直接写入指定寄存器dest。
- *
- * 结构与{@link #buildBinary(BinaryExpressionNode)}类似,但不会新分配寄存器。
+ * 构建函数或方法调用表达式。
+ *
+ * @param call AST 调用表达式节点
+ * @return 存储调用结果的虚拟寄存器
+ */
+ private IRVirtualRegister buildCall(CallExpressionNode call) {
+ // 递归生成所有参数(实参)对应的寄存器
+ List argv = call.arguments().stream().map(this::build).toList();
+
+ // 解析被调用目标名,支持普通函数/成员方法
+ String callee = switch (call.callee()) {
+ // 成员方法调用,例如 obj.foo()
+ case MemberExpressionNode m when m.object() instanceof IdentifierNode id
+ -> id.name() + "." + m.member();
+ // 普通函数调用
+ case IdentifierNode id -> id.name();
+ // 其它情况暂不支持
+ default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName());
+ };
+
+ // 为返回值分配新寄存器,生成 Call 指令
+ IRVirtualRegister dest = ctx.newRegister();
+ ctx.addInstruction(new CallInstruction(dest, callee, new ArrayList<>(argv)));
+ return dest;
+ }
+
+ /**
+ * 二元表达式构建,结果存储到新寄存器。
+ *
+ * 支持算术、位运算与比较(==, !=, >, <, ...)。
*
* @param bin 二元表达式节点
- * @param dest 目标寄存器
+ * @return 存储表达式结果的虚拟寄存器
+ */
+ private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
+ // 递归生成左、右子表达式的寄存器
+ IRVirtualRegister a = build(bin.left());
+ IRVirtualRegister b = build(bin.right());
+ String op = bin.operator();
+
+ // 比较运算符(==、!=、>、< 等),需要生成条件跳转或布尔值寄存器
+ if (ComparisonUtils.isComparisonOperator(op)) {
+ return InstructionFactory.binOp(
+ ctx,
+ // 通过比较工具获得合适的 IR 操作码
+ ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
+ a, b);
+ }
+
+ // 其它算术/位运算
+ IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
+ if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
+ return InstructionFactory.binOp(ctx, code, a, b);
+ }
+
+ /**
+ * 二元表达式构建,结果直接写入目标寄存器(用于赋值左值等优化场景)。
+ *
+ * @param bin 二元表达式节点
+ * @param dest 目标虚拟寄存器
*/
private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) {
IRVirtualRegister a = build(bin.left());
@@ -189,67 +235,44 @@ public record ExpressionBuilder(IRContext ctx) {
}
}
- /**
- * 处理函数调用表达式,生成对应的Call指令和目标寄存器。
- *
- * 支持普通标识符调用和成员调用(如 mod.func),会为每个参数依次生成子表达式的寄存器。
- *
- * @param call 调用表达式AST节点
- * @return 返回结果存放的寄存器
- */
- private IRVirtualRegister buildCall(CallExpressionNode call) {
- // 递归构建所有参数的寄存器
- List argv = call.arguments().stream()
- .map(this::build)
- .toList();
- // 获取完整调用目标名称(支持成员/模块调用和普通调用)
- String fullName = switch (call.callee()) {
- case MemberExpressionNode member when member.object() instanceof IdentifierNode _ ->
- ((IdentifierNode)member.object()).name() + "." + member.member();
- case IdentifierNode id -> id.name();
- default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName());
- };
- // 申请目标寄存器
- IRVirtualRegister dest = ctx.newRegister();
- // 添加Call指令到IR上下文
- ctx.addInstruction(new CallInstruction(dest, fullName, new ArrayList<>(argv)));
- return dest;
- }
+ /* ───────────────── 字面量辅助方法 ───────────────── */
/**
- * 处理数字字面量,生成常量寄存器和加载指令。
- *
- * 会将字符串型字面量(如 "123", "1.0f")解析为具体的IRConstant,
- * 并分配一个新的虚拟寄存器来存放该常量。
+ * 构建数字字面量表达式(如 123),分配新寄存器并生成 LoadConst 指令。
*
- * @param value 字面量字符串
- * @return 存放该常量的寄存器
+ * @param value 字面量文本(字符串格式)
+ * @return 存储该字面量的寄存器
*/
private IRVirtualRegister buildNumberLiteral(String value) {
- IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value);
- IRVirtualRegister reg = ctx.newRegister();
- ctx.addInstruction(new LoadConstInstruction(reg, constant));
- return reg;
+ IRConstant c = ExpressionUtils.buildNumberConstant(ctx, value);
+ IRVirtualRegister r = ctx.newRegister();
+ ctx.addInstruction(new LoadConstInstruction(r, c));
+ return r;
}
/**
- * 处理字符串字面量,生成常量寄存器和加载指令。
+ * 构建字符串字面量表达式,分配新寄存器并生成 LoadConst 指令。
*
* @param value 字符串内容
- * @return 存放该字符串常量的寄存器
+ * @return 存储该字符串的寄存器
*/
private IRVirtualRegister buildStringLiteral(String value) {
- IRConstant constant = new IRConstant(value);
- IRVirtualRegister reg = ctx.newRegister();
- ctx.addInstruction(new LoadConstInstruction(reg, constant));
- return reg;
+ IRConstant c = new IRConstant(value);
+ IRVirtualRegister r = ctx.newRegister();
+ ctx.addInstruction(new LoadConstInstruction(r, c));
+ return r;
}
- /** 布尔字面量 → CONST (true=1,false=0)*/
- private IRVirtualRegister buildBoolLiteral(boolean value) {
- IRConstant constant = new IRConstant(value ? 1 : 0);
- IRVirtualRegister reg = ctx.newRegister();
- ctx.addInstruction(new LoadConstInstruction(reg, constant));
- return reg;
+ /**
+ * 构建布尔字面量表达式(true/false),分配新寄存器并生成 LoadConst 指令(1 表示 true,0 表示 false)。
+ *
+ * @param v 布尔值
+ * @return 存储 1/0 的寄存器
+ */
+ private IRVirtualRegister buildBoolLiteral(boolean v) {
+ IRConstant c = new IRConstant(v ? 1 : 0);
+ IRVirtualRegister r = ctx.newRegister();
+ ctx.addInstruction(new LoadConstInstruction(r, c));
+ return r;
}
}
From 6a339149f11f6584959cb7535b868a65c2eff744 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:09:26 +0800
Subject: [PATCH 069/100] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=20LoadConstG?=
=?UTF-8?q?enerator=20=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 优化类注释,明确类的功能和额外支持的特性
- 重构 generate 方法,提高代码可读性和维护性- 增加对字符串常量的处理,支持 syscall 降级场景
- 完善类型前缀处理,增加 'R' 前缀用于字符串常量
---
.../backend/generator/LoadConstGenerator.java | 70 ++++++++++---------
1 file changed, 36 insertions(+), 34 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/generator/LoadConstGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/generator/LoadConstGenerator.java
index 760422a..a24f6d9 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/generator/LoadConstGenerator.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/generator/LoadConstGenerator.java
@@ -10,16 +10,18 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map;
/**
- * 常量加载指令生成器
- * 该类用于生成将常量加载到虚拟机寄存器的指令,包括 PUSH 常量值和 STORE 到指定槽位,
- * 并为每个槽位设置正确的类型前缀(如 'I', 'L', 'F' 等)。
+ * LoadConstGenerator - 将 IR {@code LoadConstInstruction} 生成 VM 指令
+ *
+ *
+ * 本类负责将 IR 层的常量加载指令 {@link LoadConstInstruction} 转换为对应的虚拟机指令。
+ * 额外支持:如果常量类型为 {@code String},会同步登记到
+ * {@link CallGenerator} 的字符串常量池,方便 syscall 降级场景使用。
+ *
*/
public class LoadConstGenerator implements InstructionGenerator {
/**
- * 返回本生成器支持的指令类型,即 LoadConstInstruction。
- *
- * @return 支持的指令类型的 Class 对象
+ * 指定本生成器支持的 IR 指令类型(LoadConstInstruction)
*/
@Override
public Class supportedClass() {
@@ -27,49 +29,49 @@ public class LoadConstGenerator implements InstructionGenerator slotMap,
String currentFn) {
- // 1. 获取常量值(第一个操作数必为常量)
+
+ /* 1. 获取常量值 */
IRConstant constant = (IRConstant) ins.operands().getFirst();
Object value = constant.value();
- // 2. 生成 PUSH 指令,将常量值推入操作数栈
- // 通过 OpHelper 辅助方法获取合适的数据类型前缀
- String pushOp = OpHelper.pushOpcodeFor(value);
- out.emit(pushOp + " " + value);
+ /* 2. 生成 PUSH 指令,将常量值入栈 */
+ out.emit(OpHelper.pushOpcodeFor(value) + " " + value);
- // 3. 生成 STORE 指令,将栈顶的值存入对应槽位(寄存器)
- // 同样通过 OpHelper 获取对应类型的 STORE 指令
- String storeOp = OpHelper.storeOpcodeFor(value);
- // 获取目标虚拟寄存器对应的槽位编号
+ /* 3. STORE 到目标槽位 */
int slot = slotMap.get(ins.dest());
- out.emit(storeOp + " " + slot);
+ out.emit(OpHelper.storeOpcodeFor(value) + " " + slot);
- // 4. 根据常量的 Java 类型,为槽位设置正确的前缀字符
- // 这样在后续类型检查/运行时可用,常见前缀如 'I', 'L', 'F', 'D', 'S', 'B'
+ /* 4. 标记槽位数据类型(用于后续类型推断和 LOAD/STORE 指令选择) */
char prefix = switch (value) {
- case Integer _ -> 'I'; // 整型
- case Long _ -> 'L'; // 长整型
- case Short _ -> 'S'; // 短整型
- case Byte _ -> 'B'; // 字节型
- case Double _ -> 'D'; // 双精度浮点型
- case Float _ -> 'F'; // 单精度浮点型
- case Boolean _ -> 'I'; // 布尔(作为 0/1 整型存储)
- case null, default ->
- throw new IllegalStateException("Unknown const type: " + (value != null ? value.getClass() : null));
+ case Integer _ -> 'I'; // 整型
+ case Long _ -> 'L'; // 长整型
+ case Short _ -> 'S'; // 短整型
+ case Byte _ -> 'B'; // 字节型
+ case Double _ -> 'D'; // 双精度
+ case Float _ -> 'F'; // 单精度
+ case Boolean _ -> 'I'; // 布尔类型用 I 处理
+ case String _ -> 'R'; // 字符串常量
+ case null, default -> // 其它类型异常
+ throw new IllegalStateException("未知的常量类型: "
+ + (value != null ? value.getClass() : null));
};
-
- // 写入槽位类型映射表
out.setSlotType(slot, prefix);
+
+ /* 5. 如果是字符串常量,则登记到 CallGenerator 的常量池,便于 syscall 字符串降级使用 */
+ if (value instanceof String s) {
+ CallGenerator.registerStringConst(ins.dest().id(), s);
+ }
}
}
From 8eeed6f6b999c059c2159eb589ae9b17491e0f2f Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:10:20 +0800
Subject: [PATCH 070/100] =?UTF-8?q?refactor:=20=E8=B0=83=E6=95=B4=E6=93=8D?=
=?UTF-8?q?=E4=BD=9C=E6=95=B0=E6=A0=88=E6=89=93=E5=8D=B0=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在操作数栈状态打印时,增加空行以提高可读性
---
src/main/java/org/jcnc/snow/vm/module/OperandStack.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/vm/module/OperandStack.java b/src/main/java/org/jcnc/snow/vm/module/OperandStack.java
index 347387f..1e0d158 100644
--- a/src/main/java/org/jcnc/snow/vm/module/OperandStack.java
+++ b/src/main/java/org/jcnc/snow/vm/module/OperandStack.java
@@ -84,7 +84,7 @@ public class OperandStack {
*
*/
public void printOperandStack() {
- LoggingUtils.logInfo("Operand Stack state:", stack + "\n");
+ LoggingUtils.logInfo("\n\nOperand Stack state:", stack + "\n");
}
/**
From b4c933e3d4c310969a6ac265531e23d6b9d4c6fd Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:10:42 +0800
Subject: [PATCH 071/100] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=20Demo14=20?=
=?UTF-8?q?=E7=A4=BA=E4=BE=8B=E7=A8=8B=E5=BA=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修改导入模块,使用 os 模块替代 BuiltinUtils
- 更新 syscall 调用,增加表达式计算
---
playground/Demo/Demo14/Main.snow | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/playground/Demo/Demo14/Main.snow b/playground/Demo/Demo14/Main.snow
index 42049ea..8e5baff 100644
--- a/playground/Demo/Demo14/Main.snow
+++ b/playground/Demo/Demo14/Main.snow
@@ -1,10 +1,10 @@
module: Main
- import: BuiltinUtils
+ import: os
function: main
return_type: void
body:
- syscall("PRINT",1)
+ syscall("PRINT",2222+1)
end body
end function
end module
\ No newline at end of file
From e7c7451004d8b5d99ee68212771332bf02bfe385 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:16:54 +0800
Subject: [PATCH 072/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20CallCo?=
=?UTF-8?q?mmand=20=E7=B1=BB=E5=B9=B6=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?=
=?UTF-8?q?=E6=B3=A8=E9=87=8A=20-=20=E9=87=8D=E6=96=B0=E7=BB=84=E7=BB=87?=
=?UTF-8?q?=E7=B1=BB=E6=96=87=E6=A1=A3=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=AF=B9?=
=?UTF-8?q?=20CallCommand=20=E5=8A=9F=E8=83=BD=E5=92=8C=E8=A1=8C=E4=B8=BA?=
=?UTF-8?q?=E7=9A=84=E8=AF=A6=E7=BB=86=E6=8F=8F=E8=BF=B0=20-=20=E6=B7=BB?=
=?UTF-8?q?=E5=8A=A0=20execute=20=E6=96=B9=E6=B3=95=E7=9A=84=E8=AF=A6?=
=?UTF-8?q?=E7=BB=86=E6=B3=A8=E9=87=8A=EF=BC=8C=E6=98=8E=E7=A1=AE=E5=8F=82?=
=?UTF-8?q?=E6=95=B0=E5=92=8C=E8=BF=94=E5=9B=9E=E5=80=BC=E7=9A=84=E7=94=A8?=
=?UTF-8?q?=E9=80=94=20-=20=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93?=
=?UTF-8?q?=E6=9E=84=EF=BC=8C=E6=8F=90=E9=AB=98=E5=8F=AF=E8=AF=BB=E6=80=A7?=
=?UTF-8?q?=E5=92=8C=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../vm/commands/flow/control/CallCommand.java | 42 +++++++++++++++++--
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
index befbfea..1171885 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
@@ -5,12 +5,48 @@ import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.*;
/**
- * CALL addr nArgs — pushes a new stack-frame, transfers the specified
- * argument count from the operand stack into the callee’s local slots
- * 0‥n-1 (left-to-right), then jumps to {@code addr}.
+ * The CallCommand class implements the {@link Command} interface and represents a subroutine/function call
+ * instruction in the virtual machine.
+ *
+ * This command facilitates method invocation by creating a new stack frame, transferring arguments
+ * from the operand stack to the callee's local variable store, and jumping to the specified target address.
+ *
+ *
+ * Specific behavior:
+ *
+ * - Parses the target address and the number of arguments from the instruction parameters.
+ * - Validates the operands and checks for correct argument count.
+ * - Builds a new local variable store for the callee and transfers arguments from the operand stack
+ * (left-to-right order, where the top of the stack is the last argument).
+ * - Pushes a new stack frame onto the call stack, saving the return address and local variables.
+ * - Jumps to the specified target address to begin execution of the callee function.
+ * - If any error occurs (e.g., malformed operands, stack underflow), an exception is thrown.
+ *
*/
public class CallCommand implements Command {
+ /**
+ * Executes the CALL instruction, initiating a subroutine/function call within the virtual machine.
+ *
+ * This method handles the creation of a new stack frame for the callee, argument passing,
+ * and control transfer to the target function address.
+ *
+ *
+ * @param parts The instruction parameters. Must include:
+ *
+ * - {@code parts[0]}: The "CALL" operator.
+ * - {@code parts[1]}: The target address of the callee function.
+ * - {@code parts[2]}: The number of arguments to pass.
+ *
+ * @param currentPC The current program counter, used to record the return address for after the call.
+ * @param operandStack The operand stack manager. Arguments are popped from this stack.
+ * @param callerLVS The local variable store of the caller function (not directly modified here).
+ * @param callStack The virtual machine's call stack manager, used to push the new stack frame.
+ * @return The new program counter value, which is the address of the callee function (i.e., jump target).
+ * The VM should transfer control to this address after setting up the call frame.
+ * @throws IllegalArgumentException If the instruction parameters are malformed or missing.
+ * @throws IllegalStateException If the operand stack does not contain enough arguments.
+ */
@Override
public int execute(String[] parts,
int currentPC,
From 6098a290b1d67686df16098ac4dc6f88ea111378 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:18:30 +0800
Subject: [PATCH 073/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20R=5FLOAD?=
=?UTF-8?q?=E6=8C=87=E4=BB=A4=E7=9A=84=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 RLoadCommand 类,实现 Command接口
- 该指令用于从局部变量表中加载引用对象,并将其推入操作数栈- 指令格式:R_LOAD
- 其中 是局部变量表中的索引
- 执行过程包括解析索引、获取引用、推入栈顶和更新程序计数器
---
.../vm/commands/ref/control/RLoadCommand.java | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java
diff --git a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java
new file mode 100644
index 0000000..d7e314d
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java
@@ -0,0 +1,54 @@
+package org.jcnc.snow.vm.commands.ref.control;
+
+import org.jcnc.snow.vm.interfaces.Command;
+import org.jcnc.snow.vm.module.CallStack;
+import org.jcnc.snow.vm.module.LocalVariableStore;
+import org.jcnc.snow.vm.module.OperandStack;
+
+/**
+ * The {@code RLoadCommand} class implements the {@link Command} interface and represents the
+ * reference load instruction ({@code R_LOAD}) in the virtual machine.
+ *
+ *
+ * This instruction loads a reference object from the current stack frame’s local variable store
+ * at the specified slot and pushes it onto the operand stack.
+ *
+ *
+ * Instruction format: {@code R_LOAD }
+ *
+ * - {@code
}: The index in the local variable table to load the reference from.
+ *
+ *
+ * Behavior:
+ *
+ * - Parses the slot index from the instruction parameters.
+ * - Fetches the reference object stored at the specified slot in the current stack frame's local variable store.
+ * - Pushes the fetched reference onto the operand stack.
+ * - Increments the program counter to the next instruction.
+ *
+ */
+public final class RLoadCommand implements Command {
+
+ /**
+ * Executes the {@code R_LOAD} instruction, loading a reference from the local variable table and pushing it onto the operand stack.
+ *
+ * @param parts The instruction parameters. {@code parts[0]} is the operator ("R_LOAD"), {@code parts[1]} is the slot index.
+ * @param pc The current program counter value, indicating the instruction address being executed.
+ * @param stack The operand stack manager. The loaded reference will be pushed onto this stack.
+ * @param lvs The local variable store. (Not used directly, as this command uses the store from the current stack frame.)
+ * @param cs The call stack manager. The reference will be loaded from the local variable store of the top stack frame.
+ * @return The next program counter value ({@code pc + 1}), pointing to the next instruction.
+ * @throws NumberFormatException if the slot parameter cannot be parsed as an integer.
+ */
+ @Override
+ public int execute(String[] parts, int pc,
+ OperandStack stack,
+ LocalVariableStore lvs,
+ CallStack cs) {
+
+ int slot = Integer.parseInt(parts[1]);
+ Object v = cs.peekFrame().getLocalVariableStore().getVariable(slot);
+ stack.push(v);
+ return pc + 1;
+ }
+}
From a7117717bd76ef791fa565e9e990336c4e10e8fa Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:19:05 +0800
Subject: [PATCH 074/100] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E5=91=BD?=
=?UTF-8?q?=E4=BB=A4=E5=B7=A5=E5=8E=82=E4=B8=AD=E7=9A=84=E5=BC=95=E7=94=A8?=
=?UTF-8?q?=E5=91=BD=E4=BB=A4=E8=B7=AF=E5=BE=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将 RLoadCommand、RPushCommand 和 RStoreCommand 的导入路径从 type.control.ref 改为 ref.control
- 这个改动统一了引用类型命令的包结构,与其他类型命令保持一致
---
.../java/org/jcnc/snow/vm/factories/CommandFactory.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java b/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
index 71479a3..fc4a3ed 100644
--- a/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
+++ b/src/main/java/org/jcnc/snow/vm/factories/CommandFactory.java
@@ -6,9 +6,9 @@ import org.jcnc.snow.vm.commands.type.control.double64.*;
import org.jcnc.snow.vm.commands.type.control.float32.*;
import org.jcnc.snow.vm.commands.type.control.int32.*;
import org.jcnc.snow.vm.commands.type.control.long64.*;
-import org.jcnc.snow.vm.commands.type.control.ref.RLoadCommand;
-import org.jcnc.snow.vm.commands.type.control.ref.RPushCommand;
-import org.jcnc.snow.vm.commands.type.control.ref.RStoreCommand;
+import org.jcnc.snow.vm.commands.ref.control.RLoadCommand;
+import org.jcnc.snow.vm.commands.ref.control.RPushCommand;
+import org.jcnc.snow.vm.commands.ref.control.RStoreCommand;
import org.jcnc.snow.vm.commands.type.control.short16.*;
import org.jcnc.snow.vm.commands.type.control.byte8.BAndCommand;
import org.jcnc.snow.vm.commands.type.control.byte8.BOrCommand;
From 5ef36d57009702a38722c6af72fa94ae5ff0778b Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:23:43 +0800
Subject: [PATCH 075/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20R=5FPUSH?=
=?UTF-8?q?=E6=8C=87=E4=BB=A4=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 RPushCommand 类实现 Command 接口,用于处理引用类型推入操作
- 支持将字符串字面量等引用类型数据推入操作栈
---
.../vm/commands/ref/control/RPushCommand.java | 63 +++++++++++++++++++
1 file changed, 63 insertions(+)
create mode 100644 src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java
diff --git a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java
new file mode 100644
index 0000000..1386018
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java
@@ -0,0 +1,63 @@
+package org.jcnc.snow.vm.commands.ref.control;
+
+import org.jcnc.snow.vm.interfaces.Command;
+import org.jcnc.snow.vm.module.CallStack;
+import org.jcnc.snow.vm.module.LocalVariableStore;
+import org.jcnc.snow.vm.module.OperandStack;
+
+/**
+ * The {@code RPushCommand} class implements the {@link Command} interface and represents the
+ * reference push instruction ({@code R_PUSH}) in the virtual machine.
+ *
+ *
+ * This instruction pushes a reference object, such as a String literal, onto the operand stack.
+ *
+ *
+ * Instruction format: {@code R_PUSH }
+ *
+ * - {@code
}: The reference value (e.g., string) to be pushed onto the stack.
+ * If the literal contains spaces, all parts after {@code R_PUSH} are joined into a single string.
+ *
+ *
+ * Behavior:
+ *
+ * - Checks that the instruction has at least one parameter after the operator.
+ * - Concatenates all parameters after {@code R_PUSH} into a single string (separated by spaces).
+ * - Pushes the resulting string as a reference object onto the operand stack.
+ * - Increments the program counter to the next instruction.
+ * - Throws an {@code IllegalStateException} if the instruction is missing required parameters.
+ *
+ */
+public final class RPushCommand implements Command {
+
+ /**
+ * Executes the {@code R_PUSH} instruction, pushing a reference (such as a string literal)
+ * onto the operand stack.
+ *
+ * @param parts The instruction parameters. {@code parts[0]} is the operator ("R_PUSH"),
+ * {@code parts[1..]} are the parts of the literal to be concatenated and pushed.
+ * @param pc The current program counter value, indicating the instruction address being executed.
+ * @param stack The operand stack manager. The literal will be pushed onto this stack.
+ * @param lvs The local variable store. (Not used in this instruction.)
+ * @param cs The call stack manager. (Not used in this instruction.)
+ * @return The next program counter value ({@code pc + 1}), pointing to the next instruction.
+ * @throws IllegalStateException if the instruction is missing required parameters.
+ */
+ @Override
+ public int execute(String[] parts, int pc,
+ OperandStack stack,
+ LocalVariableStore lvs,
+ CallStack cs) {
+
+ if (parts.length < 2)
+ throw new IllegalStateException("R_PUSH missing parameter");
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i < parts.length; i++) {
+ if (i > 1) sb.append(' ');
+ sb.append(parts[i]);
+ }
+ stack.push(sb.toString());
+ return pc + 1;
+ }
+}
From 33d89e99083f8244896d2e752c8a1b094caf54cb Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:24:57 +0800
Subject: [PATCH 076/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20R=5FSTORE?=
=?UTF-8?q?=E6=8C=87=E4=BB=A4=E7=9A=84=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 RStoreCommand 类,实现 Command接口
- 添加 R_STORE指令的执行逻辑
- 更新虚拟机的指令集,支持 R_STORE 指令
---
.../commands/ref/control/RStoreCommand.java | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 src/main/java/org/jcnc/snow/vm/commands/ref/control/RStoreCommand.java
diff --git a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RStoreCommand.java b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RStoreCommand.java
new file mode 100644
index 0000000..0237908
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RStoreCommand.java
@@ -0,0 +1,58 @@
+package org.jcnc.snow.vm.commands.ref.control;
+
+import org.jcnc.snow.vm.interfaces.Command;
+import org.jcnc.snow.vm.module.CallStack;
+import org.jcnc.snow.vm.module.LocalVariableStore;
+import org.jcnc.snow.vm.module.OperandStack;
+
+/**
+ * The {@code RStoreCommand} class implements the {@link Command} interface and represents the
+ * reference store instruction ({@code R_STORE}) in the virtual machine.
+ *
+ *
+ * This instruction pops a reference object from the top of the operand stack
+ * and stores it in the local variable table at the specified slot index of the current stack frame.
+ *
+ *
+ * Instruction format: {@code R_STORE }
+ *
+ * - {@code
}: The index in the local variable table where the reference will be stored.
+ *
+ *
+ * Behavior:
+ *
+ * - Parses the slot index from the instruction parameters.
+ * - Pops a reference object from the operand stack.
+ * - Stores the popped reference object into the local variable table of the current stack frame at the specified slot.
+ * - Increments the program counter to the next instruction.
+ * - If the operand stack is empty, a {@code java.util.EmptyStackException} may be thrown.
+ *
+ */
+public final class RStoreCommand implements Command {
+
+ /**
+ * Executes the {@code R_STORE} instruction, storing a reference object from the top of the operand stack
+ * into the local variable table of the current stack frame.
+ *
+ * @param parts The instruction parameters. {@code parts[0]} is the operator ("R_STORE"),
+ * {@code parts[1]} is the slot index.
+ * @param pc The current program counter value, indicating the instruction address being executed.
+ * @param stack The operand stack manager. The reference object will be popped from this stack.
+ * @param lvs The local variable store. (Not used directly, as the store from the current stack frame is used.)
+ * @param cs The call stack manager. The reference will be stored in the local variable store of the top stack frame.
+ * @return The next program counter value ({@code pc + 1}), pointing to the next instruction.
+ * @throws NumberFormatException if the slot parameter cannot be parsed as an integer.
+ * @throws java.util.EmptyStackException if the operand stack is empty when popping.
+ */
+ @Override
+ public int execute(String[] parts, int pc,
+ OperandStack stack,
+ LocalVariableStore lvs,
+ CallStack cs) {
+
+ int slot = Integer.parseInt(parts[1]);
+ Object v = stack.pop();
+ cs.peekFrame().getLocalVariableStore().setVariable(slot, v);
+ return pc + 1;
+ }
+}
From b30b6aeaaa166414839063f2b26503c22dd44466 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 17:26:42 +0800
Subject: [PATCH 077/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=BC=95?=
=?UTF-8?q?=E7=94=A8=E7=B1=BB=E5=9E=8B=E6=8E=A7=E5=88=B6=E6=8C=87=E4=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 R_PUSH、R_LOAD 和 R_STORE 指令,用于处理对象引用类型
- 这些指令分别用于推送、加载和存储对象引用到操作栈或本地变量表
---
.../org/jcnc/snow/vm/engine/VMOpCode.java | 71 +++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java b/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
index 8e1a880..c333e34 100644
--- a/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
+++ b/src/main/java/org/jcnc/snow/vm/engine/VMOpCode.java
@@ -1,5 +1,8 @@
package org.jcnc.snow.vm.engine;
+import org.jcnc.snow.vm.commands.ref.control.RLoadCommand;
+import org.jcnc.snow.vm.commands.ref.control.RPushCommand;
+import org.jcnc.snow.vm.commands.ref.control.RStoreCommand;
import org.jcnc.snow.vm.commands.system.control.SyscallCommand;
import org.jcnc.snow.vm.commands.type.control.byte8.*;
import org.jcnc.snow.vm.commands.type.control.double64.*;
@@ -2483,6 +2486,74 @@ public class VMOpCode {
// endregion Double64
// endregion Conversion
+ // region Reference Control (0x00E0-0x00EF)
+ /**
+ * R_PUSH Opcode: Represents an operation that pushes an object reference (such as a String or any reference type)
+ * onto the operand stack.
+ * This opcode is implemented by the {@link RPushCommand} class, which defines its specific execution logic.
+ *
+ * Execution Steps:
+ *
+ * - Parses the object reference literal (e.g., a string) from the instruction parameters.
+ * - Creates or interprets the reference as an object instance if necessary.
+ * - Pushes the reference object onto the operand stack.
+ * - Increments the program counter (PC) to proceed with the next sequential instruction.
+ *
+ *
+ * This opcode is commonly used for:
+ *
+ * - Pushing string literals, objects, or other references needed for subsequent operations.
+ * - Supplying parameters for method calls that expect reference types.
+ * - Initializing the operand stack with reference values for computation or storage.
+ *
+ */
+ public static final int R_PUSH = 0x00E0;
+ /**
+ * R_LOAD Opcode: Represents an operation that loads an object reference from the local variable table
+ * and pushes it onto the operand stack.
+ * This opcode is implemented by the {@link RLoadCommand} class, which defines its specific execution logic.
+ *
+ * Execution Steps:
+ *
+ * - Parses the target slot index from the instruction parameters.
+ * - Retrieves the reference object stored at the specified slot in the local variable table
+ * of the current stack frame.
+ * - Pushes the retrieved reference onto the operand stack.
+ * - Increments the program counter (PC) to proceed with the next sequential instruction.
+ *
+ *
+ * This opcode is commonly used for:
+ *
+ * - Accessing local variables (such as function arguments or local object references) during method execution.
+ * - Preparing reference values for operations or method invocations.
+ * - Reusing objects previously stored in local variables.
+ *
+ */
+ public static final int R_LOAD = 0x00E1;
+ /**
+ * R_STORE Opcode: Represents an operation that pops an object reference from the top of the operand stack
+ * and stores it into the local variable table at the specified slot index.
+ * This opcode is implemented by the {@link RStoreCommand} class, which defines its specific execution logic.
+ *
+ * Execution Steps:
+ *
+ * - Parses the target slot index from the instruction parameters.
+ * - Pops the top reference object from the operand stack.
+ * - Stores the popped reference object into the specified slot in the local variable table
+ * of the current stack frame.
+ * - Increments the program counter (PC) to proceed with the next sequential instruction.
+ *
+ *
+ * This opcode is commonly used for:
+ *
+ * - Storing computation results or intermediate reference values for later use.
+ * - Passing object references to local variables in preparation for further operations or method calls.
+ * - Managing object lifetimes and ensuring correct referencing in scoped execution contexts.
+ *
+ */
+ public static final int R_STORE = 0x00E2;
+ // endregion
+
// region Stack Control (0x0100-0x01FF)
/**
* POP Opcode: Represents a stack operation that removes the top element from the operand stack.
From a454eed26fd825969862d431b4fa5f900350be5b Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 22:52:40 +0800
Subject: [PATCH 078/100] =?UTF-8?q?test:=20=E9=87=8D=E6=9E=84=20Demo14=20?=
=?UTF-8?q?=E6=BC=94=E7=A4=BA=E4=BB=A3=E7=A0=81=20-=20=E7=A7=BB=E9=99=A4?=
=?UTF-8?q?=E4=BA=86=20Main.snow=20=E6=96=87=E4=BB=B6=E4=B8=AD=E7=9A=84?=
=?UTF-8?q?=E7=9B=B4=E6=8E=A5=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8=20-=20?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=20OS.snow=20=E6=96=87=E4=BB=B6=EF=BC=8C?=
=?UTF-8?q?=E5=AE=9E=E7=8E=B0=20print=20=E5=87=BD=E6=95=B0=E5=B0=81?=
=?UTF-8?q?=E8=A3=85=20-=20=E4=BF=AE=E6=94=B9=20Main.snow=EF=BC=8C?=
=?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=96=B0=E7=9A=84=20print=20=E5=87=BD?=
=?UTF-8?q?=E6=95=B0=E6=9B=BF=E4=BB=A3=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/Demo/Demo14/Main.snow | 3 +--
playground/Demo/Demo14/OS.snow | 11 +++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
create mode 100644 playground/Demo/Demo14/OS.snow
diff --git a/playground/Demo/Demo14/Main.snow b/playground/Demo/Demo14/Main.snow
index 8e5baff..7ef2b05 100644
--- a/playground/Demo/Demo14/Main.snow
+++ b/playground/Demo/Demo14/Main.snow
@@ -1,10 +1,9 @@
module: Main
import: os
-
function: main
return_type: void
body:
- syscall("PRINT",2222+1)
+ print(222)
end body
end function
end module
\ No newline at end of file
diff --git a/playground/Demo/Demo14/OS.snow b/playground/Demo/Demo14/OS.snow
new file mode 100644
index 0000000..f985171
--- /dev/null
+++ b/playground/Demo/Demo14/OS.snow
@@ -0,0 +1,11 @@
+module: Main
+ import: os
+ function: print
+ parameter:
+ declare i1: int
+ return_type: void
+ body:
+ syscall("PRINT",i1)
+ end body
+ end function
+end module
\ No newline at end of file
From 074f0b6809bec76c0547f0c467ead58d0e86ba68 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 22:54:49 +0800
Subject: [PATCH 079/100] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E5=BA=93?=
=?UTF-8?q?=E5=87=BD=E6=95=B0=E5=AE=9E=E7=8E=B0=E6=89=93=E5=8D=B0=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/os/OS.snow | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 lib/os/OS.snow
diff --git a/lib/os/OS.snow b/lib/os/OS.snow
new file mode 100644
index 0000000..f985171
--- /dev/null
+++ b/lib/os/OS.snow
@@ -0,0 +1,11 @@
+module: Main
+ import: os
+ function: print
+ parameter:
+ declare i1: int
+ return_type: void
+ body:
+ syscall("PRINT",i1)
+ end body
+ end function
+end module
\ No newline at end of file
From e84aedc100f44de9646439e180ddae138f565470 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 23:13:50 +0800
Subject: [PATCH 080/100] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=E6=A8=A1?=
=?UTF-8?q?=E5=9D=97=E5=90=8D=E7=A7=B0=E4=B8=BA=E5=B0=8F=E5=86=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/os/OS.snow | 2 +-
playground/Demo/Demo14/OS.snow | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/os/OS.snow b/lib/os/OS.snow
index f985171..6026d43 100644
--- a/lib/os/OS.snow
+++ b/lib/os/OS.snow
@@ -1,4 +1,4 @@
-module: Main
+module: os
import: os
function: print
parameter:
diff --git a/playground/Demo/Demo14/OS.snow b/playground/Demo/Demo14/OS.snow
index f985171..6026d43 100644
--- a/playground/Demo/Demo14/OS.snow
+++ b/playground/Demo/Demo14/OS.snow
@@ -1,4 +1,4 @@
-module: Main
+module: os
import: os
function: print
parameter:
From 6d79e28c51c002ffe8f12ae64589829f4a26bf26 Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 21 Jul 2025 23:42:03 +0800
Subject: [PATCH 081/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20Syscal?=
=?UTF-8?q?lCommand=20=E7=B1=BB=E5=B9=B6=E4=BC=98=E5=8C=96=E6=96=87?=
=?UTF-8?q?=E6=A1=A3=E6=B3=A8=E9=87=8A-=20=E9=87=8D=E6=96=B0=E7=BB=84?=
=?UTF-8?q?=E7=BB=87=E7=B1=BB=E7=BB=93=E6=9E=84=EF=BC=8C=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=B8=83=E5=B1=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 更新文档注释,使其更加清晰和详细
- 优化部分方法实现,提高可读性和可维护性
---
.../system/control/SyscallCommand.java | 261 ++++++------------
1 file changed, 88 insertions(+), 173 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
index eebcd28..90caf8b 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/system/control/SyscallCommand.java
@@ -16,53 +16,47 @@ import java.util.*;
import static java.nio.file.StandardOpenOption.*;
/**
- * {@code SyscallCommand} —— I/O syscall 子命令集合指令。
+ * SyscallCommand —— 虚拟机系统调用(SYSCALL)指令实现。
*
*
- * 封装类 UNIX 文件描述符(File Descriptor, FD)操作、文件/网络 I/O、管道、fd 复制、多路复用(select)等系统调用能力,
- * 基于 Java NIO 统一实现,供虚拟机指令集以 SYSCALL 形式扩展使用。
+ * 本类负责将虚拟机指令集中的 SYSCALL 进行分派,模拟现实系统常见的文件、网络、管道、标准输出等操作,
+ * 通过操作数栈完成参数、返回值传递,并借助文件描述符表(FDTable)进行底层资源管理。
+ * 所有 I/O 相关功能均基于 Java NIO 实现,兼容多种 I/O 场景。
*
*
- * 栈操作约定:
+ * 参数与栈约定:
*
- * - 参数按“右值先入栈、左值后入栈”的顺序推入操作数栈,执行 {@code SYSCALL
} 后出栈。
- * - 即:调用 SYSCALL OPEN path flags mode,入栈顺序为 path(先入)→ flags → mode(后入),出栈时 mode→flags→path 弹出。
+ * - 所有调用参数,均按“右值先入、左值后入”顺序压入 {@link OperandStack}。
+ * - SYSCALL 指令自动弹出参数并处理结果;返回值(如描述符、读取长度、是否成功等)压回栈顶。
*
*
- * 返回值说明:
+ * 异常与失败处理:
*
- * - 成功:压入正值(如 FD、实际数据、字节数、0 表示成功)。
- * - 失败:统一压入 -1,后续可扩展为 errno 机制。
+ * - 系统调用失败或遇到异常时,均向操作数栈压入 {@code -1},以便调用者统一检测。
*
*
- * 支持的子命令(部分):
+ * 支持的子命令示例:
*
* - PRINT / PRINTLN —— 控制台输出
- * - OPEN / CLOSE / READ / WRITE / SEEK —— 文件 I/O 操作
- * - PIPE / DUP —— 管道和 FD 复制
- * - SOCKET / CONNECT / BIND / LISTEN / ACCEPT —— 网络套接字
- * - SELECT —— I/O 多路复用
+ * - OPEN / CLOSE / READ / WRITE / SEEK —— 文件相关操作
+ * - PIPE / DUP —— 管道与文件描述符复制
+ * - SOCKET / CONNECT / BIND / LISTEN / ACCEPT —— 网络通信
+ * - SELECT —— 多通道 I/O 就绪检测
*
*/
public class SyscallCommand implements Command {
-
-
- /*--------------------------------------------------------------------------------*/
-
/**
- * 执行 SYSCALL 子命令:
- *
- * 按照 parts[1] 指定的 SYSCALL 子命令,结合虚拟机栈与资源表完成对应的系统调用模拟。
- * 支持基础文件、网络、管道等 I/O 操作,并对异常统一处理。
- *
+ * 分发并执行 SYSCALL 子命令,根据子命令类型从操作数栈取出参数、操作底层资源,并将结果压回栈顶。
*
- * @param parts 指令字符串数组,parts[1] 为子命令
+ * @param parts 指令及子命令参数分割数组,parts[1]为子命令名
* @param pc 当前指令计数器
* @param stack 操作数栈
* @param locals 局部变量表
* @param callStack 调用栈
- * @return 下一条指令的 pc 值(默认 pc+1)
+ * @return 下一条指令的 pc 值(通常为 pc+1)
+ * @throws IllegalArgumentException 缺少子命令参数时抛出
+ * @throws UnsupportedOperationException 不支持的 SYSCALL 子命令时抛出
*/
@Override
public int execute(String[] parts, int pc,
@@ -70,46 +64,27 @@ public class SyscallCommand implements Command {
LocalVariableStore locals,
CallStack callStack) {
- if (parts.length < 2)
- throw new IllegalArgumentException("SYSCALL needs sub-command");
+ if (parts.length < 2) {
+ throw new IllegalArgumentException("SYSCALL missing subcommand");
+ }
String cmd = parts[1].toUpperCase(Locale.ROOT);
try {
switch (cmd) {
-
- /*==================== 文件 / 目录 ====================*/
-
- /*
- * OPEN —— 打开文件,返回文件描述符(File Descriptor, FD)。
- * 入栈(push)顺序: path(文件路径, String), flags(int), mode(int,文件权限,暂未用)
- * 出栈(pop)顺序: mode → flags → path
- * 成功返回 fd,失败返回 -1。
- */
+ // 文件相关操作
case "OPEN" -> {
- int mode = (Integer) stack.pop(); // 目前未用
+ int mode = (Integer) stack.pop();
int flags = (Integer) stack.pop();
String path = String.valueOf(stack.pop());
FileChannel fc = FileChannel.open(Paths.get(path), flagsToOptions(flags));
stack.push(FDTable.register(fc));
}
- /*
- * CLOSE —— 关闭文件描述符。
- * 入栈顺序: fd(int)
- * 出栈顺序: fd
- * 返回 0 成功,-1 失败
- */
case "CLOSE" -> {
int fd = (Integer) stack.pop();
FDTable.close(fd);
stack.push(0);
}
- /*
- * READ —— 从 fd 读取指定字节数。
- * 入栈顺序: fd(int), count(int,字节数)
- * 出栈顺序: count → fd
- * 返回:byte[](实际读取的数据,EOF 时长度为 0)
- */
case "READ" -> {
int count = (Integer) stack.pop();
int fd = (Integer) stack.pop();
@@ -126,12 +101,6 @@ public class SyscallCommand implements Command {
buf.get(out);
stack.push(out);
}
- /*
- * WRITE —— 向 fd 写数据。
- * 入栈顺序: fd(int), data(byte[] 或 String)
- * 出栈顺序: data → fd
- * 返回写入字节数,失败 -1
- */
case "WRITE" -> {
Object dataObj = stack.pop();
int fd = (Integer) stack.pop();
@@ -146,12 +115,6 @@ public class SyscallCommand implements Command {
int written = wch.write(ByteBuffer.wrap(data));
stack.push(written);
}
- /*
- * SEEK —— 文件定位,移动文件读写指针。
- * 入栈顺序: fd(int), offset(long/int), whence(int, 0=SET,1=CUR,2=END)
- * 出栈顺序: whence → offset → fd
- * 返回新位置(long),失败 -1
- */
case "SEEK" -> {
int whence = (Integer) stack.pop();
long off = ((Number) stack.pop()).longValue();
@@ -165,58 +128,32 @@ public class SyscallCommand implements Command {
case 0 -> sbc.position(off);
case 1 -> sbc.position(sbc.position() + off);
case 2 -> sbc.position(sbc.size() + off);
- default -> throw new IllegalArgumentException("bad whence");
+ default -> throw new IllegalArgumentException("Invalid offset type");
};
stack.push(newPos);
}
- /*==================== 管道 / FD 相关 ====================*/
-
- /*
- * PIPE —— 创建匿名管道。
- * 入栈顺序: (无)
- * 出栈顺序: (无)
- * 返回顺序: write fd(先压栈),read fd(后压栈)
- */
+ // 管道与描述符操作
case "PIPE" -> {
Pipe p = Pipe.open();
- stack.push(FDTable.register(p.sink())); // write fd
- stack.push(FDTable.register(p.source())); // read fd
+ stack.push(FDTable.register(p.sink()));
+ stack.push(FDTable.register(p.source()));
}
- /*
- * DUP —— 复制一个已存在的 fd(dup)。
- * 入栈顺序: oldfd(int)
- * 出栈顺序: oldfd
- * 返回新的 fd,失败 -1
- */
case "DUP" -> {
int oldfd = (Integer) stack.pop();
stack.push(FDTable.dup(oldfd));
}
- /*==================== 网络相关 ====================*/
-
- /*
- * SOCKET —— 创建套接字,支持 stream/dgram。
- * 入栈顺序: domain(int, AF_INET=2等), type(int, 1=STREAM,2=DGRAM), protocol(int, 预留)
- * 出栈顺序: protocol → type → domain
- * 返回 fd
- */
+ // 网络相关
case "SOCKET" -> {
- int proto = (Integer) stack.pop(); // 预留,暂不用
- int type = (Integer) stack.pop(); // 1=STREAM,2=DGRAM
- int domain = (Integer) stack.pop(); // AF_INET=2……
+ int proto = (Integer) stack.pop();
+ int type = (Integer) stack.pop();
+ int domain = (Integer) stack.pop();
Channel ch = (type == 1)
? SocketChannel.open()
: DatagramChannel.open();
stack.push(FDTable.register(ch));
}
- /*
- * CONNECT —— 发起 TCP 连接。
- * 入栈顺序: fd(int), host(String), port(int)
- * 出栈顺序: port → host → fd
- * 返回 0 成功,-1 失败
- */
case "CONNECT" -> {
int port = (Integer) stack.pop();
String host = String.valueOf(stack.pop());
@@ -225,14 +162,10 @@ public class SyscallCommand implements Command {
if (ch instanceof SocketChannel sc) {
sc.connect(new InetSocketAddress(host, port));
stack.push(0);
- } else stack.push(-1);
+ } else {
+ stack.push(-1);
+ }
}
- /*
- * BIND —— 绑定端口。
- * 入栈顺序: fd(int), host(String), port(int)
- * 出栈顺序: port → host → fd
- * 返回 0 成功,-1 失败
- */
case "BIND" -> {
int port = (Integer) stack.pop();
String host = String.valueOf(stack.pop());
@@ -241,45 +174,32 @@ public class SyscallCommand implements Command {
if (ch instanceof ServerSocketChannel ssc) {
ssc.bind(new InetSocketAddress(host, port));
stack.push(0);
- } else stack.push(-1);
+ } else {
+ stack.push(-1);
+ }
}
- /*
- * LISTEN —— 监听 socket,兼容 backlog。
- * 入栈顺序: fd(int), backlog(int)
- * 出栈顺序: backlog → fd
- * 返回 0 成功,-1 失败
- * 注意:Java NIO 打开 ServerSocketChannel 已自动监听,无 backlog 处理,行为和 UNIX 有区别。
- */
case "LISTEN" -> {
int backlog = (Integer) stack.pop();
int fd = (Integer) stack.pop();
Channel ch = FDTable.get(fd);
- if (ch instanceof ServerSocketChannel) stack.push(0);
- else stack.push(-1);
+ if (ch instanceof ServerSocketChannel) {
+ stack.push(0);
+ } else {
+ stack.push(-1);
+ }
}
- /*
- * ACCEPT —— 接收连接。
- * 入栈顺序: fd(int)
- * 出栈顺序: fd
- * 返回新连接 fd,失败 -1
- */
case "ACCEPT" -> {
int fd = (Integer) stack.pop();
Channel ch = FDTable.get(fd);
if (ch instanceof ServerSocketChannel ssc) {
SocketChannel cli = ssc.accept();
stack.push(FDTable.register(cli));
- } else stack.push(-1);
+ } else {
+ stack.push(-1);
+ }
}
- /*==================== 多路复用 ====================*/
-
- /*
- * SELECT —— I/O 多路复用,监视多个 fd 是否可读写。
- * 入栈顺序: fds(List), timeout_ms(long)
- * 出栈顺序: timeout_ms → fds
- * 返回: 就绪 fd 列表(List)
- */
+ // 多路复用
case "SELECT" -> {
long timeout = ((Number) stack.pop()).longValue();
@SuppressWarnings("unchecked")
@@ -298,107 +218,94 @@ public class SyscallCommand implements Command {
int ready = sel.select(timeout);
List readyFds = new ArrayList<>();
if (ready > 0) {
- for (SelectionKey k : sel.selectedKeys())
+ for (SelectionKey k : sel.selectedKeys()) {
readyFds.add((Integer) k.attachment());
+ }
}
stack.push(readyFds);
sel.close();
}
-
- /*==================== 控制台输出 ====================*/
-
- /*
- * PRINT —— 控制台输出(无换行)。
- * 入栈顺序: data(任意基本类型或其包装类型、String、byte[] 等)
- * 出栈顺序: data
- * 返回 0
- */
+ // 控制台输出
case "PRINT" -> {
Object dataObj = stack.pop();
output(dataObj, false);
- stack.push(0); // success
+ stack.push(0);
}
-
- /* PRINTLN —— 控制台输出(自动换行)。*/
case "PRINTLN" -> {
Object dataObj = stack.pop();
output(dataObj, true);
- stack.push(0); // success
+ stack.push(0);
}
-
- /*==================== 其它未实现/扩展命令 ====================*/
-
- /*
- * 其它自定义 syscall 子命令未实现
- */
- default -> throw new UnsupportedOperationException("Unsupported SYSCALL: " + cmd);
+ default -> throw new UnsupportedOperationException("Unsupported SYSCALL subcommand: " + cmd);
}
} catch (Exception e) {
- // 统一异常处理,异常时压入 -1
pushErr(stack, e);
}
- // 默认:下一条指令
return pc + 1;
}
- /*------------------------------------ 工具方法 ------------------------------------*/
-
/**
- * POSIX open 标志到 Java NIO OpenOption 的映射
+ * 根据传入的文件打开标志,构造 NIO {@link OpenOption} 集合。
*
- * 将 Linux/UNIX 的 open 调用 flags 参数,转换为 Java NIO 的 OpenOption 集合。
- * 目前仅支持 WRITE(0x1)、READ、CREATE(0x40)、TRUNCATE(0x200)、APPEND(0x400)等常用标志。
+ * 本方法负责将底层虚拟机传递的 flags 整数型位域,转换为 Java NIO 标准的文件打开选项集合,
+ * 以支持文件读、写、创建、截断、追加等多种访问场景。
+ * 常用于 SYSCALL 的 OPEN 子命令。
*
*
- * @param flags POSIX 风格 open 标志(如 O_WRONLY=0x1, O_CREAT=0x40 等)
- * @return 映射后的 OpenOption 集合
+ * @param flags 文件打开模式标志。各标志可组合使用,具体含义请参见虚拟机文档。
+ * @return 转换后的 OpenOption 集合,可直接用于 FileChannel.open 等 NIO 方法
*/
private static Set flagsToOptions(int flags) {
Set opts = new HashSet<>();
- // 0x1 = WRITE,否则默认 READ
+ // 如果有写入标志,则添加WRITE,否则默认为READ。
if ((flags & 0x1) != 0) opts.add(WRITE);
else opts.add(READ);
+ // 如果包含创建标志,允许创建文件。
if ((flags & 0x40) != 0) opts.add(CREATE);
+ // 包含截断标志,打开时清空内容。
if ((flags & 0x200) != 0) opts.add(TRUNCATE_EXISTING);
+ // 包含追加标志,文件写入时追加到末尾。
if ((flags & 0x400) != 0) opts.add(APPEND);
return opts;
}
/**
- * 统一异常处理:
+ * 捕获所有异常并统一处理,操作数栈压入 -1 代表本次系统调用失败。
*
- * 捕获 syscall 内部所有异常,将 -1 压入操作数栈,表示系统调用失败(暂不区分错误类型)。
- * 常见异常如文件不存在、权限不足、通道类型不符、网络故障等。
+ * 本方法是全局错误屏障,任何命令异常都会转换为虚拟机通用的失败信号,
+ * 保证上层调用逻辑不会被异常打断。实际应用中可拓展错误码机制。
*
*
- * @param stack 当前操作数栈
- * @param e 捕获的异常对象
+ * @param stack 操作数栈,将失败信号写入此栈
+ * @param e 抛出的异常对象,可在调试时输出日志
*/
private static void pushErr(OperandStack stack, Exception e) {
- stack.push(-1); // 目前统一用 -1,后续可按异常类型/errno 映射
+ stack.push(-1);
+ System.err.println("Syscall exception: " + e);
}
/**
- * 统一的控制台输出辅助方法,支持:
- *
- * - 所有基本类型及其包装类(int、double、long、float…)
- * - String、byte[]、char[] 以及其他原生数组
- * - 任意 Object(调用 {@code toString})
- *
+ * 控制台输出通用方法,支持基本类型、字节数组、任意数组、对象等。
+ *
+ * 该方法用于 SYSCALL PRINT/PRINTLN,将任意类型对象转为易读字符串输出到标准输出流。
+ * 字节数组自动按 UTF-8 解码,其它原生数组按格式化字符串输出。
+ *
*
- * @param obj 要输出的对象
- * @param newline 是否追加换行
+ * @param obj 待输出的内容,可以为任何类型(如基本类型、byte[]、数组、对象等)
+ * @param newline 是否自动换行。如果为 true,则在输出后换行;否则直接输出。
*/
private static void output(Object obj, boolean newline) {
String str;
if (obj == null) {
str = "null";
} else if (obj instanceof byte[] bytes) {
+ // 字节数组作为文本输出
str = new String(bytes);
} else if (obj.getClass().isArray()) {
+ // 其它数组格式化输出
str = arrayToString(obj);
} else {
str = obj.toString();
@@ -408,7 +315,15 @@ public class SyscallCommand implements Command {
}
/**
- * 将各种原生数组转换成可读字符串。
+ * 将各种原生数组和对象数组转换为可读字符串,便于控制台输出和调试。
+ *
+ * 本方法针对 int、long、double、float、short、char、byte、boolean 等所有原生数组类型
+ * 以及对象数组都能正确格式化,统一输出格式风格,避免显示为类型 hashCode。
+ * 若为不支持的类型,返回通用提示字符串。
+ *
+ *
+ * @param array 任意原生数组或对象数组
+ * @return 该数组的可读字符串表示
*/
private static String arrayToString(Object array) {
if (array instanceof int[] a) return Arrays.toString(a);
From 07b7d5c40e6f548ea60fb6afb865d4fb3de2c258 Mon Sep 17 00:00:00 2001
From: Luke
Date: Tue, 22 Jul 2025 16:35:43 +0800
Subject: [PATCH 082/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E7=A8=8B?=
=?UTF-8?q?=E5=BA=8F=E7=BB=88=E6=AD=A2=E5=92=8C=E5=87=BD=E6=95=B0=E8=B0=83?=
=?UTF-8?q?=E7=94=A8=E7=9A=84=E8=BE=93=E5=87=BA=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 CallCommand 中添加换行符,改善函数调用的输出可读性
- 修改 HaltCommand 中的终止消息格式,提高信息的清晰度
---
.../org/jcnc/snow/vm/commands/flow/control/CallCommand.java | 2 +-
.../org/jcnc/snow/vm/commands/system/control/HaltCommand.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
index 1171885..26dda90 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
@@ -80,7 +80,7 @@ public class CallCommand implements Command {
new MethodContext("subroutine@" + targetAddr, null));
callStack.pushFrame(newFrame);
- System.out.println("Calling function at address: " + targetAddr);
+ System.out.println("\nCalling function at address: " + targetAddr);
return targetAddr; // jump
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/commands/system/control/HaltCommand.java b/src/main/java/org/jcnc/snow/vm/commands/system/control/HaltCommand.java
index 06a5da4..71e208c 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/system/control/HaltCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/system/control/HaltCommand.java
@@ -59,7 +59,7 @@ public class HaltCommand implements Command {
@Override
public int execute(String[] parts, int currentPC, OperandStack operandStack, LocalVariableStore localVariableStore, CallStack callStack) {
// Output the termination message
- LoggingUtils.logInfo("Process has ended", "\n");
+ LoggingUtils.logInfo("\nProcess has ended", "");
// Return -1 to indicate the program termination, and the virtual machine will not continue executing subsequent instructions
return -1;
From 70feb1fe5e94a771d591ad477f6b528562d6fadc Mon Sep 17 00:00:00 2001
From: Luke
Date: Tue, 22 Jul 2025 16:36:23 +0800
Subject: [PATCH 083/100] =?UTF-8?q?style:=20=E4=BC=98=E5=8C=96=20RetComman?=
=?UTF-8?q?d=20=E7=B1=BB=E7=9A=84=E8=BE=93=E5=87=BA=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
index 1e4ebd5..505f378 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
@@ -44,7 +44,7 @@ public class RetCommand implements Command {
finished.getLocalVariableStore().clearVariables();
int returnAddr = finished.getReturnAddress();
- System.out.println("Return " + returnAddr);
+ System.out.println("\nReturn " + returnAddr);
return returnAddr;
}
}
From 1605390f0863655d6b72781597bd020b8faf2f62 Mon Sep 17 00:00:00 2001
From: Luke
Date: Tue, 22 Jul 2025 16:37:53 +0800
Subject: [PATCH 084/100] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=87=BD?=
=?UTF-8?q?=E6=95=B0=E6=9C=AB=E5=B0=BE=20CALL=20=E6=8C=87=E4=BB=A4?=
=?UTF-8?q?=E7=9A=84=E6=9C=AA=E8=A7=A3=E6=9E=90=E7=AC=A6=E5=8F=B7=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在函数开始时登记函数入口地址
- 在函数末尾强制添加 RET 或 HALT 指令
- 优化了代码注释和格式
---
.../backend/builder/VMCodeGenerator.java | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java
index 8370e90..2458b9e 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java
@@ -1,6 +1,7 @@
package org.jcnc.snow.compiler.backend.builder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
+import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
@@ -16,7 +17,7 @@ import java.util.stream.Collectors;
* 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。
*
*
- * 工作流程简述:
+ * 工作流程简述:
*
* - 接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。
* - 遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。
@@ -74,18 +75,26 @@ public final class VMCodeGenerator {
*/
public void generate(IRFunction fn) {
this.currentFn = fn.name();
- out.beginFunction(currentFn); // 输出函数起始
+
+ /* 登记函数入口地址 —— 解决 CALL 未解析符号问题 */
+ out.beginFunction(currentFn);
+
+ /* 逐条分发 IR 指令给对应的生成器 */
for (IRInstruction ins : fn.body()) {
@SuppressWarnings("unchecked")
- // 取得与当前 IR 指令类型匹配的生成器(泛型强转消除类型警告)
InstructionGenerator gen =
(InstructionGenerator) registry.get(ins.getClass());
if (gen == null) {
throw new IllegalStateException("Unsupported IR: " + ins);
}
- // 通过多态分发到实际生成器
gen.generate(ins, out, slotMap, currentFn);
}
- out.endFunction(); // 输出函数结束
+
+ /* 强制补上函数结尾的返回/终止指令 */
+ String retOpcode = "main".equals(currentFn) ? "HALT" : "RET";
+ out.emit(OpHelper.opcode(retOpcode));
+
+ /* 结束函数 */
+ out.endFunction();
}
}
From 0dbe39eff3e4f21a9129802dedc54e04acd10532 Mon Sep 17 00:00:00 2001
From: Luke
Date: Tue, 22 Jul 2025 22:33:41 +0800
Subject: [PATCH 085/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=9E=9A?=
=?UTF-8?q?=E4=B8=BE=E7=B1=BB=E5=B9=B6=E7=BB=9F=E4=B8=80=E6=A8=A1=E5=BC=8F?=
=?UTF-8?q?=E5=AE=9A=E4=B9=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 Mode 枚举类,用于统一定义程序的运行和调试模式- 删除 VMMode 枚举类,使用新的 Mode 枚举替代
- 通过重构简化代码结构,提高代码可维护性
---
src/main/java/org/jcnc/snow/common/Mode.java | 20 +++++++++++++++++++
.../java/org/jcnc/snow/vm/engine/VMMode.java | 19 ------------------
2 files changed, 20 insertions(+), 19 deletions(-)
create mode 100644 src/main/java/org/jcnc/snow/common/Mode.java
delete mode 100644 src/main/java/org/jcnc/snow/vm/engine/VMMode.java
diff --git a/src/main/java/org/jcnc/snow/common/Mode.java b/src/main/java/org/jcnc/snow/common/Mode.java
new file mode 100644
index 0000000..f8ee663
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/common/Mode.java
@@ -0,0 +1,20 @@
+package org.jcnc.snow.common;
+
+/**
+ * 程序的运行/调试模式枚举。
+ *
+ * - RUN:运行模式
+ * - DEBUG:调试模式
+ *
+ */
+public enum Mode {
+ /**
+ * 运行模式。
+ */
+ RUN,
+
+ /**
+ * 调试模式。
+ */
+ DEBUG
+}
diff --git a/src/main/java/org/jcnc/snow/vm/engine/VMMode.java b/src/main/java/org/jcnc/snow/vm/engine/VMMode.java
deleted file mode 100644
index a378ef7..0000000
--- a/src/main/java/org/jcnc/snow/vm/engine/VMMode.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.jcnc.snow.vm.engine;
-
-/**
- * The VMMode enum defines the different operational modes of the virtual machine.
- * This class is used to distinguish the behavior of the virtual machine in different states, with each mode corresponding to a different operational logic.
- */
-public enum VMMode {
- /**
- * Run Mode: The virtual machine executes instructions in the normal execution flow.
- * In this mode, the virtual machine processes instructions and performs related calculations.
- */
- RUN,
-
- /**
- * Debug Mode: The virtual machine outputs debug information during execution.
- * This mode is used for debugging the virtual machine, allowing developers to view detailed information such as the execution state, local variables, and more.
- */
- DEBUG,
-}
From da7fc0b046b218a04f14fb5946babefd865e5424 Mon Sep 17 00:00:00 2001
From: Luke
Date: Tue, 22 Jul 2025 22:33:50 +0800
Subject: [PATCH 086/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=85=A8?=
=?UTF-8?q?=E5=B1=80=E9=85=8D=E7=BD=AE=E5=92=8C=E8=B0=83=E8=AF=95=E8=BE=93?=
=?UTF-8?q?=E5=87=BA=E5=B7=A5=E5=85=B7=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 SnowConfig 类,用于统一设置程序运行模式
- 提供调试模式下的日志输出方法
- 支持判断当前运行模式
---
.../java/org/jcnc/snow/common/SnowConfig.java | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 src/main/java/org/jcnc/snow/common/SnowConfig.java
diff --git a/src/main/java/org/jcnc/snow/common/SnowConfig.java b/src/main/java/org/jcnc/snow/common/SnowConfig.java
new file mode 100644
index 0000000..e48108e
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/common/SnowConfig.java
@@ -0,0 +1,58 @@
+package org.jcnc.snow.common;
+
+/**
+ * 全局编译/运行配置和调试输出工具类。
+ *
+ * 用于统一设置程序的运行模式,并在调试模式下输出日志信息。
+ *
+ */
+public final class SnowConfig {
+
+ /**
+ * 当前运行模式,默认为 {@link Mode#RUN}。
+ */
+ public static Mode MODE = Mode.RUN;
+
+ /**
+ * 私有构造方法,防止实例化。
+ */
+ private SnowConfig() {
+ }
+
+ /**
+ * 仅在 {@link Mode#DEBUG} 模式下打印一行信息。
+ *
+ * @param msg 要输出的信息
+ */
+ public static void print(String msg) {
+ if (MODE == Mode.DEBUG) System.out.println(msg);
+ }
+
+ /**
+ * 仅在 {@link Mode#DEBUG} 模式下按格式输出信息。
+ *
+ * @param fmt 格式化字符串
+ * @param args 格式化参数
+ */
+ public static void print(String fmt, Object... args) {
+ if (MODE == Mode.DEBUG) System.out.printf(fmt, args);
+ }
+
+ /**
+ * 判断当前是否为 {@link Mode#DEBUG} 模式。
+ *
+ * @return 当且仅当当前为调试模式时返回 true
+ */
+ public static boolean isDebug() {
+ return MODE == Mode.DEBUG;
+ }
+
+ /**
+ * 判断当前是否为 {@link Mode#RUN} 模式。
+ *
+ * @return 当且仅当当前为运行模式时返回 true
+ */
+ public static boolean isRun() {
+ return MODE == Mode.RUN;
+ }
+}
From 6f81feab3fc35df34c778c82afeffe73dedba6b7 Mon Sep 17 00:00:00 2001
From: Luke
Date: Tue, 22 Jul 2025 22:34:15 +0800
Subject: [PATCH 087/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E8=99=9A?=
=?UTF-8?q?=E6=8B=9F=E6=9C=BA=E5=92=8C=E7=BC=96=E8=AF=91=E5=99=A8=E7=9A=84?=
=?UTF-8?q?=E8=B0=83=E8=AF=95=E8=BE=93=E5=87=BA=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../snow/compiler/lexer/core/LexerEngine.java | 10 +-
.../utils/SemanticAnalysisReporter.java | 4 +-
.../org/jcnc/snow/pkg/tasks/CompileTask.java | 155 ++++++++++--------
.../java/org/jcnc/snow/vm/VMInitializer.java | 6 +-
.../java/org/jcnc/snow/vm/VMLauncher.java | 7 +-
.../vm/commands/flow/control/CallCommand.java | 32 ++--
.../vm/commands/flow/control/RetCommand.java | 4 +-
.../snow/vm/engine/VirtualMachineEngine.java | 5 +-
.../snow/vm/module/LocalVariableStore.java | 50 ++++--
.../org/jcnc/snow/vm/utils/LoggingUtils.java | 4 +-
10 files changed, 160 insertions(+), 117 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index 1ac0792..672116f 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.compiler.lexer.core;
+import org.jcnc.snow.common.SnowConfig;
import org.jcnc.snow.compiler.lexer.base.TokenScanner;
import org.jcnc.snow.compiler.lexer.scanners.*;
import org.jcnc.snow.compiler.lexer.token.Token;
@@ -10,6 +11,8 @@ import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import static org.jcnc.snow.common.SnowConfig.print;
+
/**
* Snow 语言词法分析器核心实现。
* 采用“先扫描 → 后批量校验 → 统一报告”策略:
@@ -53,14 +56,17 @@ public class LexerEngine {
/* 2. 后置整体校验 */
validateTokens();
/* 3. 打印 token */
- TokenPrinter.print(tokens);
+ if (SnowConfig.isDebug()) {
+ TokenPrinter.print(tokens);
+ }
+
/* 4. 统一报告错误 */
report(errors);
}
public static void report(List errors) {
if (errors == null || errors.isEmpty()) {
- System.out.println("\n## 词法分析通过,没有发现错误\n");
+ print("\n## 词法分析通过,没有发现错误\n");
return;
}
System.err.println("\n词法分析发现 " + errors.size() + " 个错误: ");
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
index edeb9a5..eb332b8 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
@@ -4,6 +4,8 @@ import org.jcnc.snow.compiler.semantic.error.SemanticError;
import java.util.List;
+import static org.jcnc.snow.common.SnowConfig.print;
+
/**
* {@code SemanticAnalysisReporter} 用于在语义分析结束后汇总并打印所有收集到的
* {@link SemanticError}。为了同时满足“完整错误收集”与“按需快速失败”两种使用场景,
@@ -28,7 +30,7 @@ public final class SemanticAnalysisReporter {
System.err.println("语义分析发现 " + errors.size() + " 个错误: ");
errors.forEach(err -> System.err.println(" " + err));
} else {
- System.out.println("\n## 语义分析通过,没有发现错误\n");
+ print("\n## 语义分析通过,没有发现错误\n");
}
}
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
index 844c2fc..c908125 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
@@ -1,12 +1,14 @@
package org.jcnc.snow.pkg.tasks;
import org.jcnc.snow.cli.commands.CompileCommand;
-import org.jcnc.snow.compiler.backend.utils.OpHelper;
+import org.jcnc.snow.common.Mode;
+import org.jcnc.snow.common.SnowConfig;
import org.jcnc.snow.compiler.backend.alloc.RegisterAllocator;
import org.jcnc.snow.compiler.backend.builder.VMCodeGenerator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.generator.InstructionGeneratorProvider;
+import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.builder.IRProgramBuilder;
import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRInstruction;
@@ -26,6 +28,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
+import static org.jcnc.snow.common.SnowConfig.print;
+
/**
* CLI 任务: 编译 .snow 源文件为 VM 字节码(.water 文件)。
*
@@ -39,16 +43,20 @@ import java.util.*;
*
*/
public final class CompileTask implements Task {
- /** 项目信息 */
+ /**
+ * 项目信息
+ */
private final Project project;
- /** 原始命令行参数 */
+ /**
+ * 原始命令行参数
+ */
private final String[] args;
/**
* 创建一个编译任务。
*
- * @param project 项目信息对象
- * @param args 命令行参数数组
+ * @param project 项目信息对象
+ * @param args 命令行参数数组
*/
public CompileTask(Project project, String[] args) {
this.project = project;
@@ -64,6 +72,56 @@ public final class CompileTask implements Task {
this(project, new String[0]);
}
+ /* ---------------------- 调试输出工具 ---------------------- */
+
+ /**
+ * 推断 .water 输出文件名。
+ *
+ * - 如果指定 -o,直接使用该名称。
+ * - 目录编译时,取目录名。
+ * - 单文件编译时,取文件名去掉 .snow 后缀。
+ * - 否则默认 "program"。
+ *
+ *
+ * @param sources 源文件路径列表
+ * @param outName 输出文件名(如有指定,否则为 null)
+ * @param dir 源码目录(如有指定,否则为 null)
+ * @return 推断出的输出文件路径(.water 文件)
+ */
+ private static Path deriveOutputPath(List sources, String outName, Path dir) {
+ String base;
+ if (outName != null) {
+ base = outName;
+ } else if (dir != null) {
+ base = dir.getFileName().toString();
+ } else if (sources.size() == 1) {
+ base = sources.getFirst().getFileName().toString()
+ .replaceFirst("\\.snow$", "");
+ } else {
+ base = "program";
+ }
+ return Path.of(base + ".water");
+ }
+
+ /**
+ * 将 main 函数调整至函数列表首位,确保程序入口为 PC=0。
+ *
+ * @param in 原始 IRProgram
+ * @return 调整入口后的 IRProgram
+ */
+ private static IRProgram reorderForEntry(IRProgram in) {
+ List ordered = new ArrayList<>(in.functions());
+ for (int i = 0; i < ordered.size(); i++) {
+ if ("main".equals(ordered.get(i).name())) {
+ Collections.swap(ordered, 0, i);
+ break;
+ }
+ }
+ IRProgram out = new IRProgram();
+ ordered.forEach(out::add);
+ return out;
+ }
+
/**
* 执行编译任务。该方法会解析参数并调用 {@link #execute(String[])} 进行实际编译流程。
*
@@ -96,6 +154,7 @@ public final class CompileTask implements Task {
String arg = args[i];
switch (arg) {
case "run" -> runAfterCompile = true;
+ case "-debug" -> SnowConfig.MODE = Mode.DEBUG;
case "-o" -> {
if (i + 1 < args.length) outputName = args[++i];
else {
@@ -151,8 +210,8 @@ public final class CompileTask implements Task {
// ---------------- 1. 词法/语法分析,并打印源代码 ----------------
List allAst = new ArrayList<>();
- System.out.println("## 编译器输出");
- System.out.println("### Snow 源代码");
+ print("## 编译器输出");
+ print("### Snow 源代码");
for (Path p : sources) {
if (!Files.exists(p)) {
@@ -163,8 +222,8 @@ public final class CompileTask implements Task {
String code = Files.readString(p, StandardCharsets.UTF_8);
// 打印源码
- System.out.println("#### " + p.getFileName());
- System.out.println(code);
+ print("#### " + p.getFileName());
+ print(code);
// 词法、语法分析
LexerEngine lexer = new LexerEngine(code, p.toString());
@@ -185,11 +244,11 @@ public final class CompileTask implements Task {
program = reorderForEntry(program);
// 打印 AST 和 IR
- System.out.println("### AST");
- ASTPrinter.printJson(allAst);
+ print("### AST");
+ if (SnowConfig.isDebug()) ASTPrinter.printJson(allAst);
- System.out.println("### IR");
- System.out.println(program);
+ print("### IR");
+ print(program.toString());
// ---------------- 4. IR → VM 指令 ----------------
VMProgramBuilder builder = new VMProgramBuilder();
@@ -203,74 +262,28 @@ public final class CompileTask implements Task {
}
List finalCode = builder.build();
- System.out.println("### VM code");
- for (int i = 0; i < finalCode.size(); i++) {
- String[] parts = finalCode.get(i).split(" ");
- String name = OpHelper.opcodeName(parts[0]);
- parts = Arrays.copyOfRange(parts, 1, parts.length);
- System.out.printf("%04d: %-10s %s\n", i, name, String.join(" ", parts));
+ print("### VM code");
+ if (SnowConfig.isDebug()) {
+ for (int i = 0; i < finalCode.size(); i++) {
+ String[] parts = finalCode.get(i).split(" ");
+ String name = OpHelper.opcodeName(parts[0]);
+ parts = Arrays.copyOfRange(parts, 1, parts.length);
+ print("%04d: %-10s %s%n", i, name, String.join(" ", parts));
+ }
}
// ---------------- 5. 写出 .water 文件 ----------------
Path outputFile = deriveOutputPath(sources, outputName, dir);
Files.write(outputFile, finalCode, StandardCharsets.UTF_8);
- System.out.println("Written to " + outputFile.toAbsolutePath());
+ print("Written to " + outputFile.toAbsolutePath());
- // ---------------- 6. 可选: 立即运行 VM ----------------
+ // ---------------- 6. 立即运行 VM ----------------
if (runAfterCompile) {
- System.out.println("\n=== Launching VM ===");
+ print("\n=== Launching VM ===");
VMLauncher.main(new String[]{outputFile.toString()});
- System.out.println("\n=== VM exited ===");
+ print("\n=== VM exited ===");
}
return 0;
}
-
- /**
- * 推断 .water 输出文件名。
- *
- * - 如果指定 -o,直接使用该名称。
- * - 目录编译时,取目录名。
- * - 单文件编译时,取文件名去掉 .snow 后缀。
- * - 否则默认 "program"。
- *
- *
- * @param sources 源文件路径列表
- * @param outName 输出文件名(如有指定,否则为 null)
- * @param dir 源码目录(如有指定,否则为 null)
- * @return 推断出的输出文件路径(.water 文件)
- */
- private static Path deriveOutputPath(List sources, String outName, Path dir) {
- String base;
- if (outName != null) {
- base = outName;
- } else if (dir != null) {
- base = dir.getFileName().toString();
- } else if (sources.size() == 1) {
- base = sources.getFirst().getFileName().toString()
- .replaceFirst("\\.snow$", "");
- } else {
- base = "program";
- }
- return Path.of(base + ".water");
- }
-
- /**
- * 将 main 函数调整至函数列表首位,确保程序入口为 PC=0。
- *
- * @param in 原始 IRProgram
- * @return 调整入口后的 IRProgram
- */
- private static IRProgram reorderForEntry(IRProgram in) {
- List ordered = new ArrayList<>(in.functions());
- for (int i = 0; i < ordered.size(); i++) {
- if ("main".equals(ordered.get(i).name())) {
- Collections.swap(ordered, 0, i);
- break;
- }
- }
- IRProgram out = new IRProgram();
- ordered.forEach(out::add);
- return out;
- }
}
diff --git a/src/main/java/org/jcnc/snow/vm/VMInitializer.java b/src/main/java/org/jcnc/snow/vm/VMInitializer.java
index fc1ce08..ca11e3b 100644
--- a/src/main/java/org/jcnc/snow/vm/VMInitializer.java
+++ b/src/main/java/org/jcnc/snow/vm/VMInitializer.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.vm;
+import org.jcnc.snow.common.Mode;
import org.jcnc.snow.vm.execution.CommandLoader;
import org.jcnc.snow.vm.engine.VMCommandExecutor;
-import org.jcnc.snow.vm.engine.VMMode;
import org.jcnc.snow.vm.engine.VirtualMachineEngine;
import org.jcnc.snow.vm.io.FilePathResolver;
import org.jcnc.snow.vm.utils.VMStateLogger;
@@ -45,7 +45,7 @@ public class VMInitializer {
* @param vmMode The mode in which the virtual machine should operate.
* This can be used to specify different operational modes (e.g., debug mode, normal mode).
*/
- public static void initializeAndRunVM(String[] args, VMMode vmMode) {
+ public static void initializeAndRunVM(String[] args, Mode vmMode) {
// Retrieve and validate file path
String filePath = FilePathResolver.getFilePath(args);
if (filePath == null) return;
@@ -55,7 +55,7 @@ public class VMInitializer {
if (commands.isEmpty()) return;
// Execute the commands using the virtual machine engine
- VirtualMachineEngine virtualMachineEngine = new VirtualMachineEngine(vmMode);
+ VirtualMachineEngine virtualMachineEngine = new VirtualMachineEngine();
VMCommandExecutor.executeInstructions(virtualMachineEngine, commands);
// Print the virtual machine's state
diff --git a/src/main/java/org/jcnc/snow/vm/VMLauncher.java b/src/main/java/org/jcnc/snow/vm/VMLauncher.java
index 345d9d1..ecda6cb 100644
--- a/src/main/java/org/jcnc/snow/vm/VMLauncher.java
+++ b/src/main/java/org/jcnc/snow/vm/VMLauncher.java
@@ -1,6 +1,7 @@
package org.jcnc.snow.vm;
-import org.jcnc.snow.vm.engine.VMMode;
+
+import org.jcnc.snow.common.Mode;
import static org.jcnc.snow.vm.VMInitializer.initializeAndRunVM;
@@ -12,7 +13,7 @@ import static org.jcnc.snow.vm.VMInitializer.initializeAndRunVM;
*
* This class provides the entry point to launch the virtual machine. The main method retrieves the file path
* of the VM instructions from the command-line arguments, initializes the VM engine, and runs the VM in the
- * specified mode (e.g., {@link VMMode#DEBUG}).
+ * specified mode (e.g., {@link Mode#DEBUG}).
*/
public class VMLauncher {
@@ -44,6 +45,6 @@ public class VMLauncher {
*/
public static void main(String[] args) {
// Call the method that initializes and runs the VM in DEBUG mode
- initializeAndRunVM(args, VMMode.RUN);
+ initializeAndRunVM(args, Mode.RUN);
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
index 26dda90..90741be 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
@@ -1,9 +1,11 @@
package org.jcnc.snow.vm.commands.flow.control;
-import org.jcnc.snow.vm.engine.VMMode;
+import org.jcnc.snow.common.Mode;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.*;
+import static org.jcnc.snow.common.SnowConfig.print;
+
/**
* The CallCommand class implements the {@link Command} interface and represents a subroutine/function call
* instruction in the virtual machine.
@@ -32,18 +34,18 @@ public class CallCommand implements Command {
* and control transfer to the target function address.
*
*
- * @param parts The instruction parameters. Must include:
- *
- * - {@code parts[0]}: The "CALL" operator.
- * - {@code parts[1]}: The target address of the callee function.
- * - {@code parts[2]}: The number of arguments to pass.
- *
- * @param currentPC The current program counter, used to record the return address for after the call.
- * @param operandStack The operand stack manager. Arguments are popped from this stack.
- * @param callerLVS The local variable store of the caller function (not directly modified here).
- * @param callStack The virtual machine's call stack manager, used to push the new stack frame.
+ * @param parts The instruction parameters. Must include:
+ *
+ * - {@code parts[0]}: The "CALL" operator.
+ * - {@code parts[1]}: The target address of the callee function.
+ * - {@code parts[2]}: The number of arguments to pass.
+ *
+ * @param currentPC The current program counter, used to record the return address for after the call.
+ * @param operandStack The operand stack manager. Arguments are popped from this stack.
+ * @param callerLVS The local variable store of the caller function (not directly modified here).
+ * @param callStack The virtual machine's call stack manager, used to push the new stack frame.
* @return The new program counter value, which is the address of the callee function (i.e., jump target).
- * The VM should transfer control to this address after setting up the call frame.
+ * The VM should transfer control to this address after setting up the call frame.
* @throws IllegalArgumentException If the instruction parameters are malformed or missing.
* @throws IllegalStateException If the operand stack does not contain enough arguments.
*/
@@ -61,13 +63,13 @@ public class CallCommand implements Command {
int nArgs;
try {
targetAddr = Integer.parseInt(parts[1]);
- nArgs = Integer.parseInt(parts[2]);
+ nArgs = Integer.parseInt(parts[2]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("CALL: malformed operands", e);
}
/* build new frame & local table for callee */
- LocalVariableStore calleeLVS = new LocalVariableStore(VMMode.RUN);
+ LocalVariableStore calleeLVS = new LocalVariableStore();
/* transfer arguments: operand stack top is last arg */
for (int slot = nArgs - 1; slot >= 0; slot--) {
@@ -80,7 +82,7 @@ public class CallCommand implements Command {
new MethodContext("subroutine@" + targetAddr, null));
callStack.pushFrame(newFrame);
- System.out.println("\nCalling function at address: " + targetAddr);
+ print("\nCalling function at address: " + targetAddr);
return targetAddr; // jump
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
index 505f378..c31ec96 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
@@ -3,6 +3,8 @@ package org.jcnc.snow.vm.commands.flow.control;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.*;
+import static org.jcnc.snow.common.SnowConfig.print;
+
/**
* Implements the {@code RET} instruction (method return).
*
@@ -44,7 +46,7 @@ public class RetCommand implements Command {
finished.getLocalVariableStore().clearVariables();
int returnAddr = finished.getReturnAddress();
- System.out.println("\nReturn " + returnAddr);
+ print("\nReturn " + returnAddr);
return returnAddr;
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java b/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java
index 0f188ab..704822b 100644
--- a/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java
+++ b/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.vm.engine;
+import org.jcnc.snow.common.Mode;
import org.jcnc.snow.vm.execution.CommandExecutionHandler;
import org.jcnc.snow.vm.module.*;
@@ -53,10 +54,10 @@ public class VirtualMachineEngine {
*
* @param vmMode execution mode (DEBUG / RUN)
*/
- public VirtualMachineEngine(VMMode vmMode) {
+ public VirtualMachineEngine() {
this.operandStack = new OperandStack();
this.callStack = new CallStack();
- this.localVariableStore = new LocalVariableStore(vmMode); // shared with root frame
+ this.localVariableStore = new LocalVariableStore(); // shared with root frame
this.commandExecutionHandler =
new CommandExecutionHandler(operandStack, localVariableStore, callStack);
this.programCounter = 0;
diff --git a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
index 8c64ff9..e1b3bd1 100644
--- a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
+++ b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
@@ -1,11 +1,10 @@
package org.jcnc.snow.vm.module;
+import org.jcnc.snow.common.SnowConfig;
import org.jcnc.snow.vm.gui.LocalVariableStoreSwing;
import org.jcnc.snow.vm.utils.LoggingUtils;
-import org.jcnc.snow.vm.engine.VMMode;
import java.util.ArrayList;
-import java.util.Objects;
/**
* The {@code LocalVariableStore} represents a simple dynamically-sized
@@ -18,25 +17,23 @@ import java.util.Objects;
public class LocalVariableStore {
private final ArrayList localVariables;
- private final VMMode vmMode;
-
/* ---------- construction ---------- */
- public LocalVariableStore(VMMode vmMode, int initialCapacity) {
+ public LocalVariableStore(int initialCapacity) {
this.localVariables = new ArrayList<>(initialCapacity);
- this.vmMode = vmMode;
handleMode();
}
- public LocalVariableStore(VMMode vmMode) {
+ public LocalVariableStore() {
this.localVariables = new ArrayList<>();
- this.vmMode = vmMode;
handleMode();
}
/* ---------- public API ---------- */
- /** Sets the value at {@code index}, expanding the list if necessary. */
+ /**
+ * Sets the value at {@code index}, expanding the list if necessary.
+ */
public void setVariable(int index, Object value) {
ensureCapacity(index + 1);
localVariables.set(index, value);
@@ -46,10 +43,17 @@ public class LocalVariableStore {
* 兼容早期实现: VM 指令译码器可直接调用 store / load
* 而无需关心内部命名差异。
* ------------------------------------------------------------ */
- public void store(int index, Object value) { setVariable(index, value); }
- public Object load(int index) { return getVariable(index); }
+ public void store(int index, Object value) {
+ setVariable(index, value);
+ }
- /** Returns the value at {@code index}. */
+ public Object load(int index) {
+ return getVariable(index);
+ }
+
+ /**
+ * Returns the value at {@code index}.
+ */
public Object getVariable(int index) {
/* 修改点 #1 —— 自动扩容以避免 LOAD 越界异常 */
if (index < 0)
@@ -58,12 +62,16 @@ public class LocalVariableStore {
return localVariables.get(index); // 可能为 null,符合 JVM 语义
}
- /** Exposes the backing list (read-only preferred). */
+ /**
+ * Exposes the backing list (read-only preferred).
+ */
public ArrayList getLocalVariables() {
return localVariables;
}
- /** Prints every slot to the logger. */
+ /**
+ * Prints every slot to the logger.
+ */
public void printLv() {
if (localVariables.isEmpty()) {
LoggingUtils.logInfo("Local variable table is empty", "");
@@ -76,7 +84,9 @@ public class LocalVariableStore {
}
}
- /** Clears all variables (used when a stack frame is popped). */
+ /**
+ * Clears all variables (used when a stack frame is popped).
+ */
public void clearVariables() {
localVariables.clear();
}
@@ -99,7 +109,9 @@ public class LocalVariableStore {
/* ---------- internal helpers ---------- */
- /** Ensures backing list can hold {@code minCapacity} slots. */
+ /**
+ * Ensures backing list can hold {@code minCapacity} slots.
+ */
private void ensureCapacity(int minCapacity) {
/* 修改点 #3 —— 使用 while 循环填充 null,确保 slot 可随机写入 */
while (localVariables.size() < minCapacity) {
@@ -107,10 +119,12 @@ public class LocalVariableStore {
}
}
- /** Mode-specific UI hook (unchanged). */
+ /**
+ * Mode-specific UI hook (unchanged).
+ */
private void handleMode() {
/* no-op */
- if (Objects.requireNonNull(vmMode) == VMMode.DEBUG) {
+ if (SnowConfig.isDebug()) {
LocalVariableStoreSwing.display(this, "Local Variable Table");
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java b/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java
index 2367cb7..3cc4eeb 100644
--- a/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java
+++ b/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java
@@ -3,6 +3,8 @@ package org.jcnc.snow.vm.utils;
import java.util.logging.Level;
import java.util.logging.Logger;
+import static org.jcnc.snow.common.SnowConfig.print;
+
/**
* The LoggingUtils class provides logging functionality, supporting different log levels for output.
* This class uses Java's built-in logging system for logging, supporting both console output and log file recording.
@@ -51,6 +53,6 @@ public class LoggingUtils {
*/
public static void logInfo(String title, String message) {
// Output the informational message to the console
- System.out.println(title + message);
+ print(title + message);
}
}
From ebb9524db0f33ed8d21807c62d3f0b0aa687bb4f Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 23 Jul 2025 10:24:49 +0800
Subject: [PATCH 088/100] =?UTF-8?q?refactor:=20=E4=BF=9D=E7=95=99=20cloud?=
=?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=9A=84=20"run"=20=E5=92=8C=20"-de?=
=?UTF-8?q?bug"=20=E6=A0=87=E5=BF=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/jcnc/snow/cli/commands/CompileCommand.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java b/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
index 277c8b5..361413b 100644
--- a/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
+++ b/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
@@ -60,10 +60,10 @@ public final class CompileCommand implements CLICommand {
List argList = new ArrayList<>();
- // 保留用户在 cloud 模式下传入的 “run” 标志
+ // 保留用户在 cloud 模式下传入的 “run” / “-debug” 标志
for (String a : args) {
- if ("run".equals(a)) {
- argList.add("run");
+ if ("run".equals(a) || "-debug".equals(a)) {
+ argList.add(a);
}
}
From 80deaa9c4f60e6e9a0f3e8f4f5836df14f5f8e57 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 23 Jul 2025 10:42:38 +0800
Subject: [PATCH 089/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AF=B9=20G?=
=?UTF-8?q?raalVM=20native-image=20=E7=9A=84=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 LocalVariableStore 中添加对 native-image环境的检测
- 在 VMUtils 中实现 isNativeImage 方法
- 更新 module-info.java,添加对 org.graalvm.nativeimage 的依赖
- 优化调试模式下的 UI 显示逻辑,避免在 native-image 环境中显示 Swing 窗口
---
src/main/java/module-info.java | 1 +
.../snow/vm/module/LocalVariableStore.java | 18 +++++++++++++-----
.../java/org/jcnc/snow/vm/utils/VMUtils.java | 18 ++++++++++++++++++
3 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 3f8a7b3..3597cae 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -4,6 +4,7 @@ module org.jcnc.snow.compiler {
uses CLICommand;
requires java.desktop;
requires java.logging;
+ requires org.graalvm.nativeimage;
exports org.jcnc.snow.compiler.ir.core;
exports org.jcnc.snow.compiler.ir.instruction;
}
diff --git a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
index e1b3bd1..7207882 100644
--- a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
+++ b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
@@ -6,6 +6,8 @@ import org.jcnc.snow.vm.utils.LoggingUtils;
import java.util.ArrayList;
+import static org.jcnc.snow.vm.utils.VMUtils.isNativeImage;
+
/**
* The {@code LocalVariableStore} represents a simple dynamically-sized
* local-variable table (frame locals) of the VM.
@@ -84,6 +86,9 @@ public class LocalVariableStore {
}
}
+
+ /* ---------- internal helpers ---------- */
+
/**
* Clears all variables (used when a stack frame is popped).
*/
@@ -106,9 +111,6 @@ public class LocalVariableStore {
}
}
-
- /* ---------- internal helpers ---------- */
-
/**
* Ensures backing list can hold {@code minCapacity} slots.
*/
@@ -120,12 +122,18 @@ public class LocalVariableStore {
}
/**
- * Mode-specific UI hook (unchanged).
+ * Mode-specific UI hook for debugging.
+ *
+ * If debug mode is enabled and not running inside a GraalVM native-image,
+ * this method will open the Swing-based variable inspector window.
+ * In native-image environments (where AWT/Swing is unavailable),
+ * the window will not be displayed.
*/
private void handleMode() {
- /* no-op */
if (SnowConfig.isDebug()) {
+ if (isNativeImage()) return;
LocalVariableStoreSwing.display(this, "Local Variable Table");
}
}
+
}
diff --git a/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java b/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java
index 21b526d..ca8d25a 100644
--- a/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java
+++ b/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.vm.utils;
+import org.graalvm.nativeimage.ImageInfo;
import org.jcnc.snow.vm.engine.VirtualMachineEngine;
/**
@@ -39,4 +40,21 @@ public class VMUtils {
vm.printStack();
vm.printLocalVariables();
}
+
+ /**
+ * Detects if the current runtime environment is a GraalVM native-image.
+ *
+ * Uses GraalVM's {@code org.graalvm.nativeimage.ImageInfo.inImageCode()} API to determine
+ * if the application is running as a native executable. If the class is not present
+ * (for example, in a standard JVM), returns {@code false}.
+ *
+ * @return {@code true} if running inside a GraalVM native-image, otherwise {@code false}
+ */
+ public static boolean isNativeImage() {
+ try {
+ return ImageInfo.inImageCode();
+ } catch (Throwable t) {
+ return false;
+ }
+ }
}
From 1486a1e3a553e51dc0c19846b0aaae4981a2392b Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 23 Jul 2025 10:49:34 +0800
Subject: [PATCH 090/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20LocalVaria?=
=?UTF-8?q?bleStore=20=E7=B1=BB=E7=9A=84=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
index 7207882..2904d04 100644
--- a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
+++ b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
@@ -42,8 +42,8 @@ public class LocalVariableStore {
}
/* ------------------------------------------------------------
- * 兼容早期实现: VM 指令译码器可直接调用 store / load
- * 而无需关心内部命名差异。
+ * Backward compatibility: VM instruction decoder can directly call
+ * store / load methods without caring about internal naming differences.
* ------------------------------------------------------------ */
public void store(int index, Object value) {
setVariable(index, value);
From f77784193759fc2cfe6d556e28e2462d1de1eeb8 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 24 Jul 2025 11:13:41 +0800
Subject: [PATCH 091/100] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E8=BF=90?=
=?UTF-8?q?=E8=A1=8C=E9=85=8D=E7=BD=AE=E5=B9=B6=E7=A7=BB=E9=99=A4=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E8=A6=86=E7=9B=96=E7=8E=87=E8=AE=BE=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在所有 Demo 运行配置中添加 -debug 参数
- 移除所有 Demo 运行配置中的代码覆盖率设置
---
.run/Demo1.run.xml | 8 +-------
.run/Demo10.run.xml | 8 +-------
.run/Demo11.run.xml | 8 +-------
.run/Demo12.run.xml | 8 +-------
.run/Demo13.run.xml | 2 +-
.run/Demo14.run.xml | 2 +-
.run/Demo2.run.xml | 8 +-------
.run/Demo3.run.xml | 8 +-------
.run/Demo4.run.xml | 8 +-------
.run/Demo5.run.xml | 8 +-------
.run/Demo6.run.xml | 8 +-------
.run/Demo7.run.xml | 8 +-------
.run/Demo8.run.xml | 8 +-------
.run/Demo9.run.xml | 8 +-------
14 files changed, 14 insertions(+), 86 deletions(-)
diff --git a/.run/Demo1.run.xml b/.run/Demo1.run.xml
index 055866b..aa50447 100644
--- a/.run/Demo1.run.xml
+++ b/.run/Demo1.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo10.run.xml b/.run/Demo10.run.xml
index 3f6bf8b..74bb0ba 100644
--- a/.run/Demo10.run.xml
+++ b/.run/Demo10.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo11.run.xml b/.run/Demo11.run.xml
index ea7c1fc..d61b202 100644
--- a/.run/Demo11.run.xml
+++ b/.run/Demo11.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo12.run.xml b/.run/Demo12.run.xml
index 5d75b19..bce1584 100644
--- a/.run/Demo12.run.xml
+++ b/.run/Demo12.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo13.run.xml b/.run/Demo13.run.xml
index 2544ad6..c722dcf 100644
--- a/.run/Demo13.run.xml
+++ b/.run/Demo13.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/Demo14.run.xml b/.run/Demo14.run.xml
index 6071504..a3c55c6 100644
--- a/.run/Demo14.run.xml
+++ b/.run/Demo14.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/Demo2.run.xml b/.run/Demo2.run.xml
index 3b10a4e..9a1b95d 100644
--- a/.run/Demo2.run.xml
+++ b/.run/Demo2.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo3.run.xml b/.run/Demo3.run.xml
index 9d0224e..0b86b8b 100644
--- a/.run/Demo3.run.xml
+++ b/.run/Demo3.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo4.run.xml b/.run/Demo4.run.xml
index a84cbe3..8c44d89 100644
--- a/.run/Demo4.run.xml
+++ b/.run/Demo4.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo5.run.xml b/.run/Demo5.run.xml
index e392f42..90ef70e 100644
--- a/.run/Demo5.run.xml
+++ b/.run/Demo5.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo6.run.xml b/.run/Demo6.run.xml
index a55fc8e..e58b6dc 100644
--- a/.run/Demo6.run.xml
+++ b/.run/Demo6.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo7.run.xml b/.run/Demo7.run.xml
index e8479ec..aeab6e2 100644
--- a/.run/Demo7.run.xml
+++ b/.run/Demo7.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo8.run.xml b/.run/Demo8.run.xml
index d4554e1..6f6d2d3 100644
--- a/.run/Demo8.run.xml
+++ b/.run/Demo8.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
diff --git a/.run/Demo9.run.xml b/.run/Demo9.run.xml
index 1002732..23d6f53 100644
--- a/.run/Demo9.run.xml
+++ b/.run/Demo9.run.xml
@@ -3,13 +3,7 @@
-
-
-
-
-
-
-
+
From b826fc43aa80f68bec29e3c5f08f9479225a5b5b Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 24 Jul 2025 11:23:55 +0800
Subject: [PATCH 092/100] =?UTF-8?q?chore:=E4=BC=98=E5=8C=96=20Native=20Ima?=
=?UTF-8?q?ge=20=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除 module-info.java 中对 org.graalvm.nativeimage 的直接引用
- 修改 VMUtils 中的 isNativeImage 方法,使用反射调用 ImageInfo
---
src/main/java/module-info.java | 1 -
src/main/java/org/jcnc/snow/vm/utils/VMUtils.java | 5 +++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 3597cae..3f8a7b3 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -4,7 +4,6 @@ module org.jcnc.snow.compiler {
uses CLICommand;
requires java.desktop;
requires java.logging;
- requires org.graalvm.nativeimage;
exports org.jcnc.snow.compiler.ir.core;
exports org.jcnc.snow.compiler.ir.instruction;
}
diff --git a/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java b/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java
index ca8d25a..8298df8 100644
--- a/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java
+++ b/src/main/java/org/jcnc/snow/vm/utils/VMUtils.java
@@ -1,6 +1,5 @@
package org.jcnc.snow.vm.utils;
-import org.graalvm.nativeimage.ImageInfo;
import org.jcnc.snow.vm.engine.VirtualMachineEngine;
/**
@@ -52,9 +51,11 @@ public class VMUtils {
*/
public static boolean isNativeImage() {
try {
- return ImageInfo.inImageCode();
+ Class> imageInfo = Class.forName("org.graalvm.nativeimage.ImageInfo");
+ return (Boolean) imageInfo.getMethod("inImageCode").invoke(null);
} catch (Throwable t) {
return false;
}
}
+
}
From 4860aba07fe39765dec2ad89bf4dfb21ec0bb7d3 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 24 Jul 2025 11:32:51 +0800
Subject: [PATCH 093/100] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E9=A1=B9?=
=?UTF-8?q?=E7=9B=AE=E7=89=88=E6=9C=AC=E8=87=B3=20v0.5.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修改 pom.xml 中的版本号为 0.5.0
- 更新 README.md 中的版本徽章为 v0.5.0
- 在 issue 模板中更新软件版本选项,将 v0.4.2 替换为 v0.5.0
---
.gitee/ISSUE_TEMPLATE/bug.yml | 2 +-
README.md | 4 ++--
pom.xml | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.gitee/ISSUE_TEMPLATE/bug.yml b/.gitee/ISSUE_TEMPLATE/bug.yml
index 8c52224..8f2368e 100644
--- a/.gitee/ISSUE_TEMPLATE/bug.yml
+++ b/.gitee/ISSUE_TEMPLATE/bug.yml
@@ -69,7 +69,7 @@ body:
attributes:
label: 软件版本/分支
options:
- - v0.4.2
+ - v0.5.0
- main
- dev
- 其他
diff --git a/README.md b/README.md
index da8a7f2..8a58d7b 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/pom.xml b/pom.xml
index 53b5d38..ec86d77 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
org.jcnc.snow
Snow
- 0.4.2
+ 0.5.0
UTF-8
From ebc322668e6baaf393387c0ee31b77856c6f3336 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 24 Jul 2025 12:36:28 +0800
Subject: [PATCH 094/100] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E8=BF=90?=
=?UTF-8?q?=E8=A1=8C=E9=85=8D=E7=BD=AE=E5=B9=B6=E6=B7=BB=E5=8A=A0=E6=96=B0?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.run/Bug1.run.xml | 6 ------
.run/Demo14.run.xml | 2 +-
.run/Help.run.xml | 6 ------
.run/Snow.run.xml | 15 +++++++++++++++
.run/Version.run.xml | 6 ------
5 files changed, 16 insertions(+), 19 deletions(-)
create mode 100644 .run/Snow.run.xml
diff --git a/.run/Bug1.run.xml b/.run/Bug1.run.xml
index f9c6da7..3c8e9ce 100644
--- a/.run/Bug1.run.xml
+++ b/.run/Bug1.run.xml
@@ -4,12 +4,6 @@
-
-
-
-
-
-
diff --git a/.run/Demo14.run.xml b/.run/Demo14.run.xml
index a3c55c6..6071504 100644
--- a/.run/Demo14.run.xml
+++ b/.run/Demo14.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/Help.run.xml b/.run/Help.run.xml
index 849a3b4..89a7af9 100644
--- a/.run/Help.run.xml
+++ b/.run/Help.run.xml
@@ -3,12 +3,6 @@
-
-
-
-
-
-
diff --git a/.run/Snow.run.xml b/.run/Snow.run.xml
new file mode 100644
index 0000000..30b2c4f
--- /dev/null
+++ b/.run/Snow.run.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/Version.run.xml b/.run/Version.run.xml
index 5816f30..954c579 100644
--- a/.run/Version.run.xml
+++ b/.run/Version.run.xml
@@ -3,12 +3,6 @@
-
-
-
-
-
-
From 210fdb62f03e3cd96ed5cbeec15764761e16a243 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 24 Jul 2025 12:36:56 +0800
Subject: [PATCH 095/100] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=85=A8?=
=?UTF-8?q?=E5=B1=80=E8=B0=83=E8=AF=95=E9=80=89=E9=A1=B9=E5=B9=B6=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 CLIUtils 中添加了全局调试标志集合,支持 "-debug" 和 "--debug" 选项
- 在 CompileTask 中更新了调试选项的处理逻辑,支持新的 "--debug" 标志
- 在 SnowCLI 中引入了 Mode 和 SnowConfig 类,以支持调试模式的配置
---
src/main/java/org/jcnc/snow/cli/SnowCLI.java | 2 ++
src/main/java/org/jcnc/snow/cli/utils/CLIUtils.java | 11 ++++++++++-
.../java/org/jcnc/snow/pkg/tasks/CompileTask.java | 2 +-
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/cli/SnowCLI.java b/src/main/java/org/jcnc/snow/cli/SnowCLI.java
index 0ce6ba0..d05b0bf 100644
--- a/src/main/java/org/jcnc/snow/cli/SnowCLI.java
+++ b/src/main/java/org/jcnc/snow/cli/SnowCLI.java
@@ -4,6 +4,8 @@ import org.jcnc.snow.cli.api.CLICommand;
import org.jcnc.snow.cli.commands.*;
import org.jcnc.snow.cli.utils.CLIUtils;
import org.jcnc.snow.cli.utils.VersionUtils;
+import org.jcnc.snow.common.Mode;
+import org.jcnc.snow.common.SnowConfig;
import java.util.Arrays;
import java.util.Map;
diff --git a/src/main/java/org/jcnc/snow/cli/utils/CLIUtils.java b/src/main/java/org/jcnc/snow/cli/utils/CLIUtils.java
index ca36951..efa44b3 100644
--- a/src/main/java/org/jcnc/snow/cli/utils/CLIUtils.java
+++ b/src/main/java/org/jcnc/snow/cli/utils/CLIUtils.java
@@ -26,12 +26,21 @@ public class CLIUtils {
"-v", "--version"
);
+ /**
+ * 全局调试标志集合,支持 "-debug"、"--debug"。
+ */
+ public static final Set GLOBAL_DEBUG_FLAGS = Set.of(
+ "--debug"
+ );
+
/**
* 全局选项列表,包括帮助和版本选项的描述。
*/
public static final List