From f820b9e9c0ee0030144a9035e4ef3b27881ff569 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 16:42:09 +0800 Subject: [PATCH 001/100] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=20Snow-Lang?= =?UTF-8?q?=20=E8=AF=AD=E6=B3=95=E8=A7=84=E8=8C=83=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 Snow-Lang 语法规范文档,详细定义了语言的词汇结构、语句、类型系统等 - 在 README.md 中添加了新文档的链接 - 重命名了原有的 Snow-Lang 语法文档为 Snow-Lang 指南 --- README.md | 5 +- .../Snow-Lang-Grammar-Specification.md.md | 585 ++++++++++++++++++ 2 files changed, 589 insertions(+), 1 deletion(-) create mode 100644 docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md diff --git a/README.md b/README.md index 9df5b5f..7ce97c4 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,10 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的 [https://gitee.com/jcnc-org/snow/releases](https://gitee.com/jcnc-org/snow/releases) ## 相关文档 -[Snow-Lang 语法](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md) +[Snow-Lang 指南](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md) + +[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md) + [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.md new file mode 100644 index 0000000..495d43b --- /dev/null +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md @@ -0,0 +1,585 @@ +# Snow‑Lang 语法规范 + +--- + +## 0 · 符号约定 + +* ⟦ … ⟧:可选项(0 或 1 次) +* { … }\*:可重复项(0 次或多次) + +--- + +## 1 · 词汇结构 + +### 1.1 编码与字符集 + +源文件采用 UTF‑8 编码。除注释外,标识符只允许英文大小写字母 (A‑Z a‑z)、数字 (0‑9) 与下划线 _;首字符不能为数字。 + +```ebnf +identifier ::= [A-Za-z_][A-Za-z0-9_]* ; +``` + +* **区分大小写**:Foo 与 foo 为不同标识符。 +* 保留字 (见 §1.3) **禁止** 用作标识符。 + +### 1.2 分隔符与强制空白 + +相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例: + +```snow +module: Foo // 推荐 +module:Foo // 不推荐 +``` + +### 1.3 保留关键字 + +``` +module import end module globals struct end struct +function end function params returns body end body +declare if then else end if loop init cond step +end loop break continue self +``` + +以上列表 **均为关键词**,大小写固定,不能作为标识符。 + +### 1.4 文字量 (Literal) + +* **整型**:123 0 -42 +* **浮点**:3.14 0.0 +* **布尔**:true false +* **字符串**:未来版本保留;当前规范未定义。 + +### 1.5 注释 + +* **单行注释**:以 // 起,至当行行尾。 +* **多行注释**:/* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。 + +--- + +### 1.6 换行与缩进 + +* **只有换行有语义**:以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。 +* **缩进没有语义**:缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。 +* 块体通过显式关闭关键字(如 end module、end function 等)结束。 +* 若关闭关键字与开始关键字之间的缩进不一致,不会报错,仍以关闭关键字为准。 + +> 块体结构完全由行分隔和显式关闭关键字决定,缩进仅为美观,不影响代码执行。 + +--- + +## 2 · 模块与导入 + +### 2.1 模块声明 + +```snow +module: + … +end module +``` + +* 一个源文件只能出现 **一次** module: 声明,且文件名与模块名无必然关系。 +* 模块名可使用点号(.)分隔表示包层级,例如 util.math。 +* **允许** 不同文件夹下声明同名模块,但模块全名(含包路径,用点分隔)在全项目中必须唯一。 +* 若项目中出现重复的模块全名,编译阶段将报重定义错误。 + +例如: +> src/util/math.snow // module: util.math +> src/core/math.snow // module: core.math +> +> 两者都声明了 module: math,但由于包路径不同(util.math 与 core.math),互不冲突。 + +### 2.2 导入 + +```snow +import: ⟦ as ⟧, ⟦ as ⟧, … +``` + +* **别名 (Alias)** 可为任何合法标识符,放在 as 关键字之后。 +* **重复导入**:对同一模块多次导入(无论是否带 alias)只解析一次,其余忽略告警。 +* **循环依赖**:当前规范未定义,若出现编译器可拒绝或延迟解析。 +* **子模块**(诸如 A.B)暂不支持。 + +### 2.3 全路径引用 + +* 跨模块引用必须使用 _Prefix_._Name_,其中 *Prefix* 是模块名或导入时的别名。 + 例如:Math.Point 或 M.sin。 +* **解析顺序**:未加前缀的标识符只在本模块查找;找不到则视为编译错误,不会隐式搜索导入模块。 + +--- + +## 3 · 命名与作用域 + +### 3.1 作用域层级 + +1. **模块顶层**:全局变量、结构体、模块级函数。 +2. **结构体内部**:字段、方法、构造函数。 +3. **函数/方法**:形参与局部变量。 +4. **局部嵌套块** (if / loop 等) 的局部变量。 + +### 3.2 唯一性规则 + +* **模块顶层唯一**:同一模块的 *结构体名*、*模块级函数名*、*全局变量名* **不得重名**。 +* **结构体内部**:字段名与方法名不得相同;**允许有多个与结构体名同名的函数(即构造函数重载),但其参数签名必须互不相同。** +* **构造函数重载**:结构体内部可以声明多个与结构体名同名的函数作为构造函数,参数类型与数量必须不同,否则属于 DuplicateName 错误。 +* **跨层级遮蔽**:内层可定义与外层同名标识符(除关键字限制外),遵循最近作用域原则。 + +### 3.3 访问控制约定 + +* **私有成员与方法**:以单个下划线 `_` 开头的变量名、字段名或方法名,**仅在其所属结构体或模块内部可见**。外部不可访问,编译器应报错 `AccessDenied`。 + - 例如 `_foo`, `_barMethod`。 +* **公有成员与方法**:非下划线开头的变量、字段、方法,默认为公有。可在模块外部通过模块名/别名前缀访问。 + +#### 影响范围 +- **模块级变量与函数**:`globals` 和 `function` 语句声明的以 `_` 开头者,仅限本模块访问。 +- **结构体字段与方法**:声明为 `_name`、`_doSomething` 的,仅结构体本身或其方法体可访问。 +--- + +#### 访问示例 + +```snow +// module: foo +globals: + declare _secret: int = 42 // 仅 foo 模块内部可见 + declare visible: int = 1 // 公有 + +function: _hidden // 仅 foo 模块内部可见 + returns: int + body: + return 100 + end body +end function + +function: publicFunc + returns: int + body: + return _secret + 1 // 合法 + end body +end function + +// module: bar +import: foo + +declare x: int = foo.visible // 合法 +declare y: int = foo._secret // 编译错误 AccessDenied +declare z: int = foo._hidden() // 编译错误 AccessDenied +``` + +## 4 · 声明语法 + +### 4.1 全局变量 + +```snow +globals: + declare VarName: Type ⟦= Expr⟧ +``` + +* 后续对该变量赋值时 **不得** 使用 declare。 + +### 4.2 结构体 + +```snow +struct: StructName + declare field1: Type1 + declare field2: Type2 + … + + // ──────────── 构造函数(可以不存在, 可重载) ────────────── + function: StructName + params: + declare p1: Type1 + … + body: + self.field1 = p1 + … + end body + end function + + function: StructName + params: + declare q1: TypeQ + declare q2: TypeQ + body: + // ... + end body + end function + // ...可继续声明更多参数签名各异的构造函数... + // ───────────────────────────────────────────── + + // ────────── 结构体内函数 (可以不存在) ────────── + function: method1 + ⟦params: + declare x: TypeX + …⟧ + returns: ReturnType + body: + … + end body + end function + // ───────────────────────────────────────────── + +end struct +``` + +**实例化**: + +* declare p: Point = Point(1, 2) +* declare p2: Point = Point(3) + +- 实参顺序 = 构造函数 params: 声明顺序;与字段声明顺序无关。 +- **构造函数重载时**,调用 Point(...) 时根据参数数量和类型匹配唯一的构造函数。若无匹配或多重匹配,则为编译错误。 +- 不支持命名实参、缺省实参或字段名字面量初始化。 + +### 4.3 函数 + +```snow +function: FuncName + returns: Type // 无返回值的时候写 void + ⟦params: + declare x: TypeX // 无参数的时候不写 params + …⟧ + body: + … + end body +end function +``` + +* **返回检查**:若 returns: 指定类型非 void,所有控制流路径必须显式 return 该类型值。 +* 在 loop 内或经 break 跳出后能到达的路径亦计入检查;若缺失,编译错误。 + +--- + +## 5 · 语句 + +### 5.1 变量声明与赋值 + +```snow +declare x: int = 0 +x = 1 +``` + +* 同一作用域中 declare 仅能出现一次。 + +### 5.2 条件语句 + +```snow +if Condition then + … +else + … +end if +``` + +* Condition 类型必须为 bool。 + +### 5.3 循环语句 + +```snow +loop: + init: + declare i: int = 0 + cond: + i < 10 + step: + i = i + 1 + body: + … + end body +end loop +``` + +* **作用域**:init 块声明的变量仅在本 loop 的 init/cond/step/body 有效。 +* break 立即终止当前循环;continue 跳过剩余 body,执行 step → cond。 + +--- + +## 6 · 类型系统 + +### 6.1 数值类型 + +Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等: + +| 类型名 | 关键字 | 位数 | 描述 | +|-------------|----------|-------|-----------------------------| +| byte8 | byte | 8 | 8 位有符号整数 | +| short16 | short | 16 | 16 位有符号整数 | +| int32 | int | 32 | 32 位有符号整数(默认整数类型)| +| long64 | long | 64 | 64 位有符号整数 | +| float32 | float | 32 | 32 位 IEEE-754 浮点数 | +| double64 | double | 64 | 64 位 IEEE-754 浮点数(默认浮点类型)| + +**说明** +* 没有无符号整型,所有整型均为有符号。 +* `int` 为整数常量与变量的默认类型。 +* `double` 为浮点常量与变量的默认类型。 +* `bool` 类型只表示真/假,不允许与数值类型直接互转。 + +#### 数值字面量后缀 + +为指定具体类型,可在数值字面量后加后缀字母(大小写均可): + +| 后缀 | 类型 | 例子 | +|------|-----------|-----------| +| b | byte | 7b, -2B | +| s | short | 123s | +| i | int | 100i | +| l | long | 5l, 123L | +| f | float | 3.14f | +| d | double | 1.0d | + +- 没有后缀的整数字面量自动为 `int`。 +- 没有后缀的浮点字面量自动为 `double`。 + +**示例:** +```snow +declare a: int = 7 // int (默认) +declare b: long = 9l // long +declare c: float = 2.5f // float +declare d: double = 2.5 // double (默认) +declare e: byte = 127b // byte +declare f: short = 100s // short +```` + +--- + +### 6.2 布尔类型 + +* 关键字为 `bool` +* 字面量为 `true` 或 `false` +* 仅用于逻辑判断、条件分支,不与整型互转 + +--- + +### 6.3 数组类型 + +支持一维和多维数组。数组类型以 `T[]` 表示元素类型为 T 的一维数组,多维数组以 `T[][]`、`T[][][]` 依次类推。 + +#### 声明与初始化 + +````snow +declare arr: int[] = [1, 2, 3] +declare matrix: double[][] = [ + [1.1, 2.2], + [3.3, 4.4] +] +declare cube: bool[][][] = [ + [[true, false], [false, true]], + [[false, false], [true, true]] +] +```` + +#### 访问与赋值 + +````snow +arr[0] = 10 +matrix[1][1] = 5.6 +declare x: int = arr[2] +declare y: double = matrix[0][1] +```` + +--- + +### 6.4 结构体类型 + +* 使用 `struct` 关键字声明 +* 结构体类型为用户自定义类型,**值类型**(赋值、传参时会拷贝整个结构体) +* 字段类型可以为任何合法类型(包括数组、其它结构体) + +````snow +struct: Point + declare x: int + declare y: int +end struct + +declare a: Point = Point(1, 2) +```` + +--- + +### 6.5 传值说明 + +* **所有变量、参数、返回值**均为**值传递**(按值拷贝) +* 结构体、数组在赋值与传参时,均会复制整个值;后续修改不会影响原对象 + + +--- + +## 7 · 名字解析算法(概览) + +1. **输入**:未限定前缀的标识符 N,当前作用域 S。 +2. 自内向外遍历作用域链查找 N;首次匹配即确定绑定。 +3. 若遍历至模块顶层仍未匹配,编译错误 *UnresolvedIdentifier*。 +4. 限定名 Prefix.N:直接在模块表中查 Prefix(包括别名),成功后在该模块顶层查找 N;找不到即 *UnresolvedQualifiedIdentifier*。 + +--- + +## 8 · 编译单位与入口 + +* **单一入口**:编译器需指定某模块某函数作为启动入口。 +* **模块初始化**:globals 块中的带初值变量在程序启动时自顶向下按出现顺序初始化;不同模块按依赖拓扑顺序初始化(循环依赖未定义)。 + +--- + +## 9 · 错误分类 + +| 编译期错误代码 | 产生条件 | +| ---------------------- | -------------------------- | +| DuplicateName | 违反唯一性规则;结构体内有参数签名完全相同的构造函数 | +| UnresolvedIdentifier | 名字无法解析 | +| ReturnMissing | 非 void 函数缺少 return | +| TypeMismatch | 赋值或返回类型不兼容 | +| ImportCycle | (可选)检测到循环依赖 | +| CtorAmbiguous | 构造函数重载时参数匹配不唯一 | +| CtorNotFound | 构造函数重载时无匹配参数签名 | +|AccessDenied | 访问了以 `_` 开头的私有变量或方法但不在允许范围| + +--- + + +## 10 · 完整示例 + +````snow +module: RectExample + import: Geometry + + struct: Point + declare x: int + declare y: int + + // 构造函数1:两个参数 + function: Point + params: + declare x: int + declare y: int + body: + self.x = x + self.y = y + end body + end function + + // 构造函数2:一个参数 + function: Point + params: + declare xy: int + body: + self.x = xy + self.y = xy + end body + end function + end struct + + struct: Rectangle + declare left_top: Point + declare right_bottom: Point + + function: Rectangle + params: + declare x1: int + declare y1: int + declare x2: int + declare y2: int + body: + self.left_top = Point(x1, y1) + self.right_bottom = Point(x2, y2) + end body + end function + + function: Rectangle + params: + declare width: int + declare height: int + body: + self.left_top = Point(0, 0) + self.right_bottom = Point(width, height) + end body + end function + + function: width + returns: int + body: + return self.right_bottom.x - self.left_top.x + end body + end function + + function: height + returns: int + body: + return self.right_bottom.y - self.left_top.y + end body + end function + + function: area + returns: int + body: + return self.width() * self.height() + end body + end function + end struct + + function: main + returns: int + declare rect1: Rectangle = Rectangle(0, 0, 10, 10) + declare rect2: Rectangle = Rectangle(5, 6) + declare result: int = 0 + body: + if rect1.area() > 50 then + loop: + init: + declare i: int = 1 + cond: + i <= rect1.width() + step: + i = i + 1 + body: + if i == 3 then + continue + end if + if i == 8 then + break + end if + result = result + i + end body + end loop + else + result = rect1.area() + end if + return result + end body + end function + +end module +```` + +--- + +## 11 · 构造函数重载示例 + +**示例:** + +````snow +struct: Point + declare x: int + declare y: int + + function: Point + params: + declare x: int + declare y: int + body: + self.x = x + self.y = y + end body + end function + + function: Point + params: + declare xy: int + body: + self.x = xy + self.y = xy + end body + end function +end struct + +declare a: Point = Point(1, 2) // 匹配第一个构造函数 +declare b: Point = Point(5) // 匹配第二个构造函数 +```` \ No newline at end of file From d2a6bde8cd54f5fbc613f96d8d0421e7ade03e08 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:03:09 +0800 Subject: [PATCH 002/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E8=AF=AD?= =?UTF-8?q?=E6=B3=95=E8=A7=84=E8=8C=83=E5=B9=B6=E6=B7=BB=E5=8A=A0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E8=A7=84=E5=88=99=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 Snow 语言语法规范,调整错误分类表格格式和示例代码结构 --- .lingma/rules/project_rule.md | 2 ++ .../Snow-Lang-Grammar-Specification.md.md | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 .lingma/rules/project_rule.md diff --git a/.lingma/rules/project_rule.md b/.lingma/rules/project_rule.md new file mode 100644 index 0000000..aea8af4 --- /dev/null +++ b/.lingma/rules/project_rule.md @@ -0,0 +1,2 @@ +**添加规则文件可帮助模型精准理解你的编码偏好,如框架、代码风格等** +**规则文件只对当前工程生效,单文件限制10000字符。如果无需将该文件提交到远程 Git 仓库,请将其添加到 .gitignore** \ No newline at end of file diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md index 495d43b..a60b3fd 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md @@ -421,8 +421,8 @@ declare a: Point = Point(1, 2) ## 9 · 错误分类 -| 编译期错误代码 | 产生条件 | -| ---------------------- | -------------------------- | +| 编译期错误代码 | 产生条件 | +|----------------------|----------------------------| | DuplicateName | 违反唯一性规则;结构体内有参数签名完全相同的构造函数 | | UnresolvedIdentifier | 名字无法解析 | | ReturnMissing | 非 void 函数缺少 return | @@ -430,7 +430,7 @@ declare a: Point = Point(1, 2) | ImportCycle | (可选)检测到循环依赖 | | CtorAmbiguous | 构造函数重载时参数匹配不唯一 | | CtorNotFound | 构造函数重载时无匹配参数签名 | -|AccessDenied | 访问了以 `_` 开头的私有变量或方法但不在允许范围| +| AccessDenied | 访问了以 `_` 开头的私有变量或方法但不在允许范围 | --- @@ -517,10 +517,10 @@ module: RectExample function: main returns: int - declare rect1: Rectangle = Rectangle(0, 0, 10, 10) - declare rect2: Rectangle = Rectangle(5, 6) - declare result: int = 0 body: + declare rect1: Rectangle = Rectangle(0, 0, 10, 10) + declare rect2: Rectangle = Rectangle(5, 6) + declare result: int = 0 if rect1.area() > 50 then loop: init: From c1d0e03b6cec232bbe89c71de2f58f4bd244502b Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:03:09 +0800 Subject: [PATCH 003/100] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E8=AF=AD?= =?UTF-8?q?=E6=B3=95=E8=A7=84=E8=8C=83=E5=B9=B6=E6=B7=BB=E5=8A=A0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E8=A7=84=E5=88=99=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 Snow 语言语法规范,调整错误分类表格格式和示例代码结构 --- .lingma/rules/project_rule.md | 2 ++ .../Snow-Lang-Grammar-Specification.md.md | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 .lingma/rules/project_rule.md diff --git a/.lingma/rules/project_rule.md b/.lingma/rules/project_rule.md new file mode 100644 index 0000000..aea8af4 --- /dev/null +++ b/.lingma/rules/project_rule.md @@ -0,0 +1,2 @@ +**添加规则文件可帮助模型精准理解你的编码偏好,如框架、代码风格等** +**规则文件只对当前工程生效,单文件限制10000字符。如果无需将该文件提交到远程 Git 仓库,请将其添加到 .gitignore** \ No newline at end of file diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md index 495d43b..a60b3fd 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md @@ -421,8 +421,8 @@ declare a: Point = Point(1, 2) ## 9 · 错误分类 -| 编译期错误代码 | 产生条件 | -| ---------------------- | -------------------------- | +| 编译期错误代码 | 产生条件 | +|----------------------|----------------------------| | DuplicateName | 违反唯一性规则;结构体内有参数签名完全相同的构造函数 | | UnresolvedIdentifier | 名字无法解析 | | ReturnMissing | 非 void 函数缺少 return | @@ -430,7 +430,7 @@ declare a: Point = Point(1, 2) | ImportCycle | (可选)检测到循环依赖 | | CtorAmbiguous | 构造函数重载时参数匹配不唯一 | | CtorNotFound | 构造函数重载时无匹配参数签名 | -|AccessDenied | 访问了以 `_` 开头的私有变量或方法但不在允许范围| +| AccessDenied | 访问了以 `_` 开头的私有变量或方法但不在允许范围 | --- @@ -517,10 +517,10 @@ module: RectExample function: main returns: int - declare rect1: Rectangle = Rectangle(0, 0, 10, 10) - declare rect2: Rectangle = Rectangle(5, 6) - declare result: int = 0 body: + declare rect1: Rectangle = Rectangle(0, 0, 10, 10) + declare rect2: Rectangle = Rectangle(5, 6) + declare result: int = 0 if rect1.area() > 50 then loop: init: From e18d7426bc1e6f5611b7c87ac88af28f3b455ac7 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:45:01 +0800 Subject: [PATCH 004/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=AD=BB?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 initializer 改为 init - 将 condition 改为 cond - 将 update 改为 step --- lib/math/factorial/factorial.snow | 6 +++--- lib/test/Dead_loop.snow | 6 +++--- playground/Demo/Demo5/Main.snow | 6 +++--- playground/Demo/Demo9/Main.snow | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/math/factorial/factorial.snow b/lib/math/factorial/factorial.snow index 46749dd..82a6dbf 100644 --- a/lib/math/factorial/factorial.snow +++ b/lib/math/factorial/factorial.snow @@ -15,11 +15,11 @@ module: Math body: declare num1:int = 1 loop: - initializer: + init: declare counter:int = 1 - condition: + cond: counter <= n - update: + step: counter = counter + 1 body: num1 = num1 * counter diff --git a/lib/test/Dead_loop.snow b/lib/test/Dead_loop.snow index 5f73bfb..f2a1a98 100644 --- a/lib/test/Dead_loop.snow +++ b/lib/test/Dead_loop.snow @@ -3,11 +3,11 @@ function: main return_type: int body: loop: - initializer: + init: declare i:int = 0 - condition: + cond: 1 == 1 - update: + step: i = i + 1 body: diff --git a/playground/Demo/Demo5/Main.snow b/playground/Demo/Demo5/Main.snow index 75ae75f..c475980 100644 --- a/playground/Demo/Demo5/Main.snow +++ b/playground/Demo/Demo5/Main.snow @@ -5,11 +5,11 @@ module: Main body: declare b1: boolean = true loop: - initializer: + init: declare i:int = 0 - condition: + cond: b1 - update: + step: i = i + 1 body: diff --git a/playground/Demo/Demo9/Main.snow b/playground/Demo/Demo9/Main.snow index 46749dd..82a6dbf 100644 --- a/playground/Demo/Demo9/Main.snow +++ b/playground/Demo/Demo9/Main.snow @@ -15,11 +15,11 @@ module: Math body: declare num1:int = 1 loop: - initializer: + init: declare counter:int = 1 - condition: + cond: counter <= n - update: + step: counter = counter + 1 body: num1 = num1 * counter From e2896eb37da6d67159f652e39ea7d7b515fe631d Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:45:22 +0800 Subject: [PATCH 005/100] =?UTF-8?q?docs:=20=E9=87=8D=E6=9E=84=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E5=92=8C=E6=9D=A1=E4=BB=B6=E8=AF=AD=E5=8F=A5=E7=9A=84?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 loop 语句中的 initializer 改为 init - 将 condition 改为 cond - 将 update 改为 step - 更新了相关文档和示例代码 --- README.md | 6 +++--- docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7ce97c4..8593611 100644 --- a/README.md +++ b/README.md @@ -391,11 +391,11 @@ module: Math body: declare num1:int = 1 loop: - initializer: + init: declare counter:int = 1 - condition: + cond: counter <= n - update: + step: counter = counter + 1 body: num1 = num1 * counter diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md b/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md index 265b4b1..2ac5fdd 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md @@ -102,14 +102,14 @@ x = y + 1 if 语句的形式如下,else 是可选的: ```snow -if condition then +if cond then // 条件成立执行的代码 else // 以上条件不成立执行的代码 end if ``` -condition 可以是表达式(结果为 bool 类型)或者 bool 字面量 +cond 可以是表达式(结果为 bool 类型)或者 bool 字面量 例: @@ -134,14 +134,14 @@ end module loop 语句的形式如下: ```snow loop: - initializer: + init: // 循环开始前可声明循环变量,有且只能声明一个 declare i: int = 1 - condition: + cond: // 循环条件,成立则执行 body 的代码, // 不成立则退出循环,有且只能写一条 i <= 100 - update: + step: // 循环体执行完后执行的代码,有且只能写一条 i = i + 1 body: @@ -158,11 +158,11 @@ module: Main body: declare sum: int = 0 loop: - initializer: + init: declare i: int = 1 - condition: + cond: i <= 100 - update: + step: i = i + 1 body: sum = sum + i From 1141abf231abfea375f50fc79231879b7a194514 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:45:55 +0800 Subject: [PATCH 006/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E8=AF=AD=E5=8F=A5=E8=8A=82=E7=82=B9=E7=9A=84=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 Declaration 节点中的 initializer 字段名称为 init - 修改 If 节点中的 condition 字段名称为 cond - 修改 Loop 节点中 initializer、condition 和 update 字段名称分别为 init、cond 和 step --- .../snow/compiler/parser/utils/ASTJsonSerializer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 278a42c..51ba838 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 @@ -121,7 +121,7 @@ public class ASTJsonSerializer { Map map = newNodeMap("Declaration"); map.put("name", d.getName()); map.put("varType", d.getType()); - map.put("initializer", d.getInitializer().map(ASTJsonSerializer::exprToMap).orElse(null)); + map.put("init", d.getInitializer().map(ASTJsonSerializer::exprToMap).orElse(null)); yield map; } // 赋值语句节点 @@ -132,7 +132,7 @@ public class ASTJsonSerializer { // 条件语句节点 case IfNode i -> { Map map = newNodeMap("If"); - map.put("condition", exprToMap(i.condition())); + map.put("cond", exprToMap(i.condition())); List thenList = new ArrayList<>(i.thenBranch().size()); for (Node stmt : i.thenBranch()) thenList.add(nodeToMap(stmt)); map.put("then", thenList); @@ -146,9 +146,9 @@ public class ASTJsonSerializer { // 循环语句节点 case LoopNode l -> { Map map = newNodeMap("Loop"); - map.put("initializer", l.initializer() != null ? nodeToMap(l.initializer()) : null); - map.put("condition", l.condition() != null ? exprToMap(l.condition()) : null); - map.put("update", l.update() != null ? nodeToMap(l.update()) : null); + map.put("init", l.init() != null ? nodeToMap(l.init()) : null); + map.put("cond", l.cond() != null ? exprToMap(l.cond()) : null); + map.put("step", l.step() != null ? nodeToMap(l.step()) : null); List body = new ArrayList<>(l.body().size()); for (Node stmt : l.body()) body.add(nodeToMap(stmt)); map.put("body", body); From bc309dfa97e9aae631c2a6870c32d48dc2154360 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:46:11 +0800 Subject: [PATCH 007/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20ASTPri?= =?UTF-8?q?nter=20=E7=B1=BB=E4=B8=AD=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改了 IfNode 和 LoopNode 的打印逻辑 - 优化了变量命名,提高了代码可读性 - 调整了缩进和格式,保持代码风格一致性 --- .../snow/compiler/parser/function/ASTPrinter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java index c12edb3..95b9708 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java @@ -86,9 +86,9 @@ public class ASTPrinter { case AssignmentNode(String variable, ExpressionNode value, NodeContext _) -> System.out.println(pad + variable + " = " + value); case IfNode( - ExpressionNode condition, List thenBranch, List elseBranch, NodeContext _ + ExpressionNode cond, List thenBranch, List elseBranch, NodeContext _ ) -> { - System.out.println(pad + "if " + condition); + System.out.println(pad + "if " + cond); for (StatementNode stmt : thenBranch) { print(stmt, indent + 1); } @@ -100,13 +100,13 @@ public class ASTPrinter { } } case LoopNode( - StatementNode initializer, ExpressionNode condition, StatementNode update, List body, + StatementNode init, ExpressionNode cond, StatementNode step, List body, NodeContext _ ) -> { System.out.println(pad + "loop {"); - print(initializer, indent + 1); - System.out.println(pad + " condition: " + condition); - System.out.println(pad + " update: " + update); + print(init, indent + 1); + System.out.println(pad + " cond: " + cond); + System.out.println(pad + " step: " + step); System.out.println(pad + " body {"); for (StatementNode stmt : body) { print(stmt, indent + 2); From d92e3d0e17dd00e22f8eaee657647d55a4db6961 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:48:08 +0800 Subject: [PATCH 008/100] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20matchH?= =?UTF-8?q?eader=20=E5=87=BD=E6=95=B0=E5=8F=82=E6=95=B0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将关键字参数注释中的 "initializer" 改为 "init",以匹配实际代码中的使用 --- .../java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f20b7c6..3677caf 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 @@ -25,7 +25,7 @@ public class ParserUtils { * 若格式不匹配,将抛出语法异常。 * * @param ts 当前的 token 流 - * @param keyword 结构起始关键字(如 "loop", "function", "initializer" 等) + * @param keyword 结构起始关键字(如 "loop", "function", "init" 等) */ public static void matchHeader(TokenStream ts, String keyword) { ts.expect(keyword); // 匹配关键字 From b135a4b37b32af3d5db0d8fae55b2cfc29479f11 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:48:50 +0800 Subject: [PATCH 009/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E8=AF=AD=E5=8F=A5=E5=88=86=E6=9E=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改初始化语句、条件表达式和更新语句的分析方法 - 优化代码结构,提高可读性和可维护性 - 适应新的语法树节点命名 --- .../analyzers/statement/LoopAnalyzer.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 a00d993..064d059 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 @@ -44,24 +44,24 @@ public class LoopAnalyzer implements StatementAnalyzer { // 新建 loopScope,以支持循环内部变量声明与外部隔离 SymbolTable loopScope = new SymbolTable(locals); - // 2. 分析初始化语句(如 for(i=0)),使用 loopScope 作为作用域 - var initAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.initializer()); + // 2. 分析初始化语句 + var initAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.init()); if (initAnalyzer != null) { - initAnalyzer.analyze(ctx, mi, fn, loopScope, ln.initializer()); + initAnalyzer.analyze(ctx, mi, fn, loopScope, ln.init()); } - // 3. 分析条件表达式(如 for(...; cond; ...) 或 while(cond)) - var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.condition()); - Type condType = condAnalyzer.analyze(ctx, mi, fn, loopScope, ln.condition()); + // 3. 分析条件表达式 + var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.cond()); + Type condType = condAnalyzer.analyze(ctx, mi, fn, loopScope, ln.cond()); // 条件类型必须为 boolean,否则记录错误 if (TypeUtils.isLogic(condType)) { ctx.getErrors().add(new SemanticError(ln, "loop 条件必须为 boolean")); } - // 4. 分析更新语句(如 for(...; ...; update)) - var updateAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.update()); + // 4. 分析更新语句 + var updateAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.step()); if (updateAnalyzer != null) { - updateAnalyzer.analyze(ctx, mi, fn, loopScope, ln.update()); + updateAnalyzer.analyze(ctx, mi, fn, loopScope, ln.step()); } // 5. 分析循环体内的每一条语句 From 2c4850cc8ff7683dfe1195c13de5b11cc06fd6aa Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:49:10 +0800 Subject: [PATCH 010/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20LoopNo?= =?UTF-8?q?de=20=E7=B1=BB=E7=9A=84=E5=8F=82=E6=95=B0=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 initializer 参数重命名为 init - 将 condition 参数重命名为 cond- 将 update 参数重命名为 step --- .../org/jcnc/snow/compiler/parser/ast/LoopNode.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java index 2ba283e..6beb716 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java @@ -14,16 +14,16 @@ import java.util.List; * 每一部分均对应为 AST 中的子节点,便于进一步语义分析与代码生成。 *

* - * @param initializer 在循环开始前执行的初始化语句 - * @param condition 每次迭代前评估的条件表达式,控制循环是否继续 - * @param update 每轮迭代完成后执行的更新语句 + * @param init 在循环开始前执行的初始化语句 + * @param cond 每次迭代前评估的条件表达式,控制循环是否继续 + * @param step 每轮迭代完成后执行的更新语句 * @param body 循环体语句列表,表示循环主体执行逻辑 * @param context 节点的上下文信息(包含行号、列号、文件名等) */ public record LoopNode( - StatementNode initializer, - ExpressionNode condition, - StatementNode update, + StatementNode init, + ExpressionNode cond, + StatementNode step, List body, NodeContext context ) implements StatementNode { From fb1c54998b1b4b8b34554ff941ec45a3f58c5f7a Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:49:44 +0800 Subject: [PATCH 011/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E8=AF=AD=E5=8F=A5=E8=A7=A3=E6=9E=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 简化了循环语句各区块的名称,提高代码可读性 - 更新了代码注释,使其与新的区块名称保持一致- 修改了变量命名,以更好地反映其对应的循环语句部分- 优化了代码结构,提高了维护性和可扩展性 --- .../parser/statement/LoopStatementParser.java | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) 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 c1a9c66..7ffeb74 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 @@ -24,23 +24,23 @@ import java.util.Map; * 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块: *
{@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
  * }
* * 各区块说明: *
    - *
  • {@code initializer}:初始化语句,通常为变量声明。
  • - *
  • {@code condition}:循环判断条件,必须为布尔或数值表达式。
  • - *
  • {@code update}:每轮执行后更新逻辑,通常为赋值语句。
  • + *
  • {@code init}:初始化语句,通常为变量声明。
  • + *
  • {@code cond}:循环判断条件,必须为布尔或数值表达式。
  • + *
  • {@code step}:每轮执行后更新逻辑,通常为赋值语句。
  • *
  • {@code body}:主执行语句块,支持任意多条语句。
  • *
* 本类依赖 {@link FlexibleSectionParser} 实现各区块的统一处理,确保结构明确、可扩展。 @@ -75,49 +75,49 @@ public class LoopStatementParser implements StatementParser { ParserUtils.matchHeader(ts, "loop"); // 使用数组模拟引用以便在 lambda 中写入(Java 不支持闭包内修改局部变量) - final StatementNode[] initializer = new StatementNode[1]; - final ExpressionNode[] condition = new ExpressionNode[1]; - final AssignmentNode[] update = new AssignmentNode[1]; + final StatementNode[] init = new StatementNode[1]; + final ExpressionNode[] cond = new ExpressionNode[1]; + final AssignmentNode[] step = new AssignmentNode[1]; final List body = new ArrayList<>(); // 定义各命名区块的识别与处理逻辑 Map sections = new HashMap<>(); - // initializer 区块:仅支持一条语句,通常为 declare - sections.put("initializer", new FlexibleSectionParser.SectionDefinition( - ts1 -> ts1.peek().getLexeme().equals("initializer"), + // init 区块:仅支持一条语句,通常为 declare + sections.put("init", new FlexibleSectionParser.SectionDefinition( + ts1 -> ts1.peek().getLexeme().equals("init"), (ctx1, ts1) -> { - ParserUtils.matchHeader(ts1, "initializer"); - initializer[0] = StatementParserFactory.get(ts1.peek().getLexeme()).parse(ctx1); + ParserUtils.matchHeader(ts1, "init"); + init[0] = StatementParserFactory.get(ts1.peek().getLexeme()).parse(ctx1); ParserUtils.skipNewlines(ts1); } )); - // condition 区块:支持任意可解析为布尔的表达式 - sections.put("condition", new FlexibleSectionParser.SectionDefinition( - ts1 -> ts1.peek().getLexeme().equals("condition"), + // cond 区块:支持任意可解析为布尔的表达式 + sections.put("cond", new FlexibleSectionParser.SectionDefinition( + ts1 -> ts1.peek().getLexeme().equals("cond"), (ctx1, ts1) -> { - ParserUtils.matchHeader(ts1, "condition"); - condition[0] = new PrattExpressionParser().parse(ctx1); + ParserUtils.matchHeader(ts1, "cond"); + cond[0] = new PrattExpressionParser().parse(ctx1); ts1.expectType(TokenType.NEWLINE); ParserUtils.skipNewlines(ts1); } )); - // update 区块:目前仅支持单一变量赋值语句 - sections.put("update", new FlexibleSectionParser.SectionDefinition( - ts1 -> ts1.peek().getLexeme().equals("update"), + // step 区块:目前仅支持单一变量赋值语句 + sections.put("step", new FlexibleSectionParser.SectionDefinition( + ts1 -> ts1.peek().getLexeme().equals("step"), (ctx1, ts1) -> { // 获取当前 token 的行号、列号 int line = ctx.getTokens().peek().getLine(); int column = ctx.getTokens().peek().getCol(); - ParserUtils.matchHeader(ts1, "update"); + ParserUtils.matchHeader(ts1, "step"); String varName = ts1.expectType(TokenType.IDENTIFIER).getLexeme(); ts1.expect("="); ExpressionNode expr = new PrattExpressionParser().parse(ctx1); ts1.expectType(TokenType.NEWLINE); - update[0] = new AssignmentNode(varName, expr, new NodeContext(line, column, file)); + step[0] = new AssignmentNode(varName, expr, new NodeContext(line, column, file)); ParserUtils.skipNewlines(ts1); } )); @@ -151,6 +151,6 @@ public class LoopStatementParser implements StatementParser { ParserUtils.matchFooter(ts, "loop"); // 返回构造完成的 LoopNode - return new LoopNode(initializer[0], condition[0], update[0], body, new NodeContext(loop_line, loop_column, file)); + return new LoopNode(init[0], cond[0], step[0], body, new NodeContext(loop_line, loop_column, file)); } } From d2732857f1b47d3745c04fd5fb0769fff9a7e6c7 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:50:01 +0800 Subject: [PATCH 012/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20SnowEx?= =?UTF-8?q?ample=20=E4=B8=AD=E7=9A=84=E5=BE=AA=E7=8E=AF=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 loop 节点下的子节点名称从 initializer 改为 init - 将 loop 节点下的子节点名称从 condition改为 cond - 将 loop 节点下的子节点名称从 update 改为 step --- src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java b/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java index ffd18d1..7358487 100644 --- a/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java +++ b/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java @@ -39,11 +39,11 @@ public final class SnowExample { body: declare num1: int = 1 loop: - initializer: + init: declare counter:int = 1 - condition: + cond: counter <= n - update: + step: counter = counter + 1 body: num1 = num1 * counter From 054ab5d63dfd8b12081a71daf7c144209209b7b9 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:50:08 +0800 Subject: [PATCH 013/100] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20SnowEx?= =?UTF-8?q?ample=20=E4=B8=AD=E7=9A=84=E5=BE=AA=E7=8E=AF=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 loop 节点下的子节点名称从 initializer 改为 init - 将 loop 节点下的子节点名称从 condition改为 cond - 将 loop 节点下的子节点名称从 update 改为 step --- .../org/jcnc/snow/compiler/ir/builder/StatementBuilder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 30d672a..7472269 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 @@ -155,18 +155,18 @@ public class StatementBuilder { * @param loop 循环节点 */ private void buildLoop(LoopNode loop) { - if (loop.initializer() != null) build(loop.initializer()); + if (loop.init() != null) build(loop.init()); String lblStart = ctx.newLabel(); String lblEnd = ctx.newLabel(); // 循环开始标签 InstructionFactory.label(ctx, lblStart); // 条件不满足则跳出循环 - emitConditionalJump(loop.condition(), lblEnd); + emitConditionalJump(loop.cond(), lblEnd); // 构建循环体 buildStatements(loop.body()); // 更新部分(如 for 的 i++) - if (loop.update() != null) build(loop.update()); + if (loop.step() != null) build(loop.step()); // 跳回循环起点 InstructionFactory.jmp(ctx, lblStart); From 536ee64f6d2825b61f8f3f363e015ecb7d29cfe3 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 14 Jul 2025 23:51:36 +0800 Subject: [PATCH 014/100] =?UTF-8?q?refactor:=20=E4=BF=AE=E6=94=B9=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E5=85=B3=E9=94=AE=E5=AD=97=E5=B9=B6=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=BC=A9=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新保留关键字集合,将 'initializer'缩写为 'init','condition' 缩写为 'cond','update' 缩写为 'step' --- .../java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e6463f4..e94c54b 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 @@ -25,7 +25,7 @@ public class TokenFactory { /** * 语言的保留关键字集合。 */ - private static final Set KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "initializer", "condition", "update"); + private static final Set KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "init", "cond", "step"); /** * 内置类型名称集合,如 int、string 等。 From 8f96716ac48bd536614c016913d4e4b41c08531b Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 15 Jul 2025 00:03:34 +0800 Subject: [PATCH 015/100] =?UTF-8?q?docs:=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E7=B1=BB=E5=9E=8B=E5=92=8C=E5=AD=97=E9=9D=A2=E9=87=8F?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E7=9A=84=20Markdown=20=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整数值类型表格的格式,使其更加简洁易读 - 优化字面量后缀表格的布局,提高可读性 - 统一表格样式,去掉多余的空格和竖线 --- .../Snow-Lang-Grammar-Specification.md.md | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md index a60b3fd..a529bf4 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md @@ -298,14 +298,14 @@ end loop Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等: -| 类型名 | 关键字 | 位数 | 描述 | -|-------------|----------|-------|-----------------------------| -| byte8 | byte | 8 | 8 位有符号整数 | -| short16 | short | 16 | 16 位有符号整数 | -| int32 | int | 32 | 32 位有符号整数(默认整数类型)| -| long64 | long | 64 | 64 位有符号整数 | -| float32 | float | 32 | 32 位 IEEE-754 浮点数 | -| double64 | double | 64 | 64 位 IEEE-754 浮点数(默认浮点类型)| +| 类型名 | 关键字 | 位数 | 描述 | +|----------|--------|----|---------------------------| +| byte8 | byte | 8 | 8 位有符号整数 | +| short16 | short | 16 | 16 位有符号整数 | +| int32 | int | 32 | 32 位有符号整数(默认整数类型) | +| long64 | long | 64 | 64 位有符号整数 | +| float32 | float | 32 | 32 位 IEEE-754 浮点数 | +| double64 | double | 64 | 64 位 IEEE-754 浮点数(默认浮点类型) | **说明** * 没有无符号整型,所有整型均为有符号。 @@ -317,14 +317,14 @@ Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体 为指定具体类型,可在数值字面量后加后缀字母(大小写均可): -| 后缀 | 类型 | 例子 | -|------|-----------|-----------| -| b | byte | 7b, -2B | -| s | short | 123s | -| i | int | 100i | -| l | long | 5l, 123L | -| f | float | 3.14f | -| d | double | 1.0d | +| 后缀 | 类型 | 例子 | +|----|--------|----------| +| 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 2a31d57a530cada903e9dd0ae587ef46b906450e Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 15 Jul 2025 22:18:35 +0800 Subject: [PATCH 016/100] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=E8=A7=84?= =?UTF-8?q?=E5=88=99=E6=96=87=E4=BB=B6=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .lingma/rules/project_rule.md | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 .lingma/rules/project_rule.md diff --git a/.gitignore b/.gitignore index 21e01df..77c9d91 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ target/ ### Snow 虚拟机指令 ### *.water +/.lingma/ diff --git a/.lingma/rules/project_rule.md b/.lingma/rules/project_rule.md deleted file mode 100644 index aea8af4..0000000 --- a/.lingma/rules/project_rule.md +++ /dev/null @@ -1,2 +0,0 @@ -**添加规则文件可帮助模型精准理解你的编码偏好,如框架、代码风格等** -**规则文件只对当前工程生效,单文件限制10000字符。如果无需将该文件提交到远程 Git 仓库,请将其添加到 .gitignore** \ No newline at end of file From 59fdc6b39ea66658a319fed60f079756142eb918 Mon Sep 17 00:00:00 2001 From: zhangxun <1958638841@qq.com> Date: Wed, 16 Jul 2025 09:22:26 +0800 Subject: [PATCH 017/100] =?UTF-8?q?docs:=20=E5=AF=B9=E9=BD=90=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jcnc/snow/compiler/parser/ast/LoopNode.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java index 6beb716..153352c 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java @@ -14,11 +14,11 @@ import java.util.List; * 每一部分均对应为 AST 中的子节点,便于进一步语义分析与代码生成。 *

* - * @param init 在循环开始前执行的初始化语句 - * @param cond 每次迭代前评估的条件表达式,控制循环是否继续 - * @param step 每轮迭代完成后执行的更新语句 - * @param body 循环体语句列表,表示循环主体执行逻辑 - * @param context 节点的上下文信息(包含行号、列号、文件名等) + * @param init 在循环开始前执行的初始化语句 + * @param cond 每次迭代前评估的条件表达式,控制循环是否继续 + * @param step 每轮迭代完成后执行的更新语句 + * @param body 循环体语句列表,表示循环主体执行逻辑 + * @param context 节点的上下文信息(包含行号、列号、文件名等) */ public record LoopNode( StatementNode init, From 3b168a134a8e5f8f28d7b79de58147392743abaa Mon Sep 17 00:00:00 2001 From: zhangxun <1958638841@qq.com> Date: Wed, 16 Jul 2025 09:23:49 +0800 Subject: [PATCH 018/100] =?UTF-8?q?fix:=20=E5=AF=B9=E9=BD=90=20ASTPrinter?= =?UTF-8?q?=20=E4=B8=AD=20loop=20=E7=9A=84=E8=BE=93=E5=87=BA=EF=BC=88cond?= =?UTF-8?q?=20=E5=92=8C=20step=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java index 95b9708..91ed077 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java @@ -106,7 +106,7 @@ public class ASTPrinter { System.out.println(pad + "loop {"); print(init, indent + 1); System.out.println(pad + " cond: " + cond); - System.out.println(pad + " step: " + step); + System.out.println(pad + " step: " + step); System.out.println(pad + " body {"); for (StatementNode stmt : body) { print(stmt, indent + 2); From eae66eac8cf2f93c8c3d5ad1fa070ca5010c7d91 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 16 Jul 2025 10:57:13 +0800 Subject: [PATCH 019/100] =?UTF-8?q?docs:=20=E4=BC=98=E5=8C=96=20LexicalErr?= =?UTF-8?q?or=20=E7=B1=BB=E7=9A=84=E6=96=87=E6=A1=A3=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 LexicalError 类添加详细的类文档注释,说明其用途 - 为所有字段和构造方法添加规范的参数注释 - 优化 toString 方法的注释,明确其返回值内容 --- .../compiler/lexer/core/LexicalError.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalError.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalError.java index 81ac9ee..b036fa0 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalError.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalError.java @@ -1,11 +1,41 @@ package org.jcnc.snow.compiler.lexer.core; +/** + * 表示词法分析过程中发生的错误信息。 + *

+ * 该类用于封装词法分析(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 Date: Wed, 16 Jul 2025 10:57:29 +0800 Subject: [PATCH 020/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AF=8D?= =?UTF-8?q?=E6=B3=95=E5=BC=82=E5=B8=B8=E7=9A=84=E9=94=99=E8=AF=AF=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=8F=90=E7=A4=BA?= 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 8f8a940..b7cc295 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("Illegal character sequence '" + lexeme + "'", line, col); + throw new LexicalException("词法错误:非法字符序列 '" + lexeme + "'", line, col); } } From f6382c4ccd108f5e46f8704432c220a6f59c129d Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 16 Jul 2025 10:57:44 +0800 Subject: [PATCH 021/100] =?UTF-8?q?refactor(compiler):=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E8=AF=8D=E6=B3=95=E9=94=99=E8=AF=AF=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E4=B8=BA=E4=B8=AD=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 LexicalException 类中的英文错误信息改为中文 - 例:将 "Lexical error: Illegal character sequence '@' at 2:19" 改为 "词法错误:非法字符序列 '@' at2:19" --- .../org/jcnc/snow/compiler/lexer/core/LexicalException.java | 2 +- 1 file changed, 1 insertion(+), 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 cdd01cb..0d3f6be 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 @@ -11,7 +11,7 @@ package org.jcnc.snow.compiler.lexer.core; * *
  * 例:
- *     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 Date: Wed, 16 Jul 2025 11:26:12 +0800 Subject: [PATCH 022/100] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AF=8D?= =?UTF-8?q?=E6=B3=95=E9=94=99=E8=AF=AF=E5=BC=82=E5=B8=B8=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改了 LexicalException 类中错误信息的显示格式 - 新格式:文件名 + "行 " +行号 + ", 列 " + 列号 + ": " +错误类型 + ": " +详细信息 - 旧格式:文件名 + ":" + 行号 + ":" + 列号 + ": " + 错误类型 + " '" + 详细信息 + "'" --- .../org/jcnc/snow/compiler/lexer/core/LexicalException.java | 2 +- 1 file changed, 1 insertion(+), 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 0d3f6be..ad81965 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 @@ -11,7 +11,7 @@ package org.jcnc.snow.compiler.lexer.core; * *
  * 例:
- *     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 Date: Wed, 16 Jul 2025 18:00:38 +0800 Subject: [PATCH 023/100] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E8=AF=8D?= =?UTF-8?q?=E6=B3=95=E5=BC=82=E5=B8=B8=E4=B8=AD=E7=9A=84=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= 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 6d6bb2f..ff31df7 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 @@ -57,7 +57,7 @@ public class LexerEngine { report(errors); if (!errors.isEmpty()) { throw new LexicalException( - "Lexing failed with " + errors.size() + " error(s).", + "", context.getLine(), context.getCol() ); } From e931d9ec06e7e40d83beffc15d9a880d0848cef3 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 16 Jul 2025 21:31:07 +0800 Subject: [PATCH 024/100] =?UTF-8?q?style:=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=E5=92=8C=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitee/ISSUE_TEMPLATE/chore.yml | 4 +- .gitee/ISSUE_TEMPLATE/enhancement.yml | 4 +- .gitee/ISSUE_TEMPLATE/hotfix.yml | 2 +- .gitee/ISSUE_TEMPLATE/question.yml | 4 +- .gitee/ISSUE_TEMPLATE/refactor.yml | 4 +- .gitee/PULL_REQUEST_TEMPLATE.zh-CN.md | 4 +- README.md | 122 +++++++++--------- build/README.md | 14 +- build/build_project2tar.ps1 | 6 +- .../Snow-Lang-Git-Management.md | 72 +++++------ ...w-Lang-GraalVM-AOT-Native-Image-Package.md | 16 +-- docs/Snow-Lang-Journey/Snow-Lang-Journey.md | 52 ++++---- .../Snow-Lang-Roadmap-2025-06-11.md | 22 ++-- .../Snow-Lang-Grammar-Specification.md.md | 82 ++++++------ docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md | 36 +++--- playground/BugFarm/Bug1/Main.snow | 11 +- pom.xml | 8 +- .../jcnc/snow/cli/commands/BuildCommand.java | 4 +- .../jcnc/snow/cli/commands/CleanCommand.java | 4 +- .../snow/cli/commands/CompileCommand.java | 12 +- .../snow/cli/commands/GenerateCommand.java | 6 +- .../jcnc/snow/cli/commands/InitCommand.java | 4 +- .../snow/cli/commands/InstallCommand.java | 4 +- .../snow/cli/commands/PublishCommand.java | 4 +- .../jcnc/snow/cli/commands/RunCommand.java | 4 +- .../snow/cli/commands/VersionCommand.java | 4 +- .../backend/alloc/RegisterAllocator.java | 8 +- .../backend/builder/VMCodeGenerator.java | 6 +- .../backend/builder/VMProgramBuilder.java | 6 +- .../jcnc/snow/compiler/backend/doc/README.md | 24 ++-- .../backend/generator/BinaryOpGenerator.java | 6 +- .../backend/generator/CmpJumpGenerator.java | 2 +- .../backend/utils/IROpCodeMapper.java | 4 +- .../backend/utils/TypePromoteUtils.java | 24 ++-- .../ir/builder/ExpressionBuilder.java | 16 +-- .../compiler/ir/builder/FunctionBuilder.java | 8 +- .../compiler/ir/builder/IRBuilderScope.java | 2 +- .../snow/compiler/ir/builder/IRContext.java | 4 +- .../compiler/ir/builder/IRProgramBuilder.java | 10 +- .../ir/builder/InstructionFactory.java | 4 +- .../compiler/ir/builder/StatementBuilder.java | 4 +- .../ir/common/GlobalFunctionTable.java | 4 +- .../snow/compiler/ir/core/IRFunction.java | 2 +- .../jcnc/snow/compiler/ir/core/IROpCode.java | 106 +++++++-------- .../jcnc/snow/compiler/ir/core/IRValue.java | 8 +- .../jcnc/snow/compiler/ir/core/IRVisitor.java | 8 +- .../org/jcnc/snow/compiler/ir/doc/README.md | 22 ++-- .../BinaryOperationInstruction.java | 4 +- .../ir/instruction/CallInstruction.java | 2 +- .../ir/instruction/IRAddInstruction.java | 6 +- .../instruction/IRCompareJumpInstruction.java | 2 +- .../ir/instruction/IRJumpInstruction.java | 4 +- .../ir/instruction/IRReturnInstruction.java | 4 +- .../ir/instruction/LoadConstInstruction.java | 4 +- .../ir/instruction/ReturnInstruction.java | 14 +- .../UnaryOperationInstruction.java | 8 +- .../compiler/ir/utils/ComparisonUtils.java | 12 +- .../compiler/ir/utils/ExpressionUtils.java | 8 +- .../snow/compiler/ir/value/IRConstant.java | 12 +- .../compiler/ir/value/IRVirtualRegister.java | 6 +- .../compiler/lexer/core/LexerContext.java | 2 +- .../snow/compiler/lexer/core/LexerEngine.java | 10 +- .../compiler/lexer/core/LexicalException.java | 6 +- .../jcnc/snow/compiler/lexer/doc/README.md | 12 +- .../lexer/scanners/AbstractTokenScanner.java | 4 +- .../lexer/scanners/CommentTokenScanner.java | 12 +- .../scanners/IdentifierTokenScanner.java | 2 +- .../lexer/scanners/NewlineTokenScanner.java | 2 +- .../lexer/scanners/NumberTokenScanner.java | 20 +-- .../lexer/scanners/OperatorTokenScanner.java | 12 +- .../lexer/scanners/StringTokenScanner.java | 4 +- .../lexer/scanners/SymbolTokenScanner.java | 10 +- .../lexer/scanners/UnknownTokenScanner.java | 4 +- .../scanners/WhitespaceTokenScanner.java | 2 +- .../compiler/lexer/token/TokenFactory.java | 8 +- .../compiler/lexer/utils/TokenPrinter.java | 6 +- .../parser/ast/BinaryExpressionNode.java | 2 +- .../parser/ast/ExpressionStatementNode.java | 2 +- .../compiler/parser/ast/FunctionNode.java | 2 +- .../snow/compiler/parser/ast/ImportNode.java | 2 +- .../snow/compiler/parser/ast/ReturnNode.java | 2 +- .../parser/ast/UnaryExpressionNode.java | 6 +- .../snow/compiler/parser/ast/base/Node.java | 8 +- .../compiler/parser/core/ParserEngine.java | 2 +- .../jcnc/snow/compiler/parser/doc/README.md | 16 +-- .../expression/UnaryOperatorParselet.java | 8 +- .../expression/base/ExpressionParser.java | 2 +- .../parser/expression/base/InfixParselet.java | 2 +- .../expression/base/PrefixParselet.java | 2 +- .../factory/StatementParserFactory.java | 4 +- .../parser/factory/TopLevelParserFactory.java | 2 +- .../parser/function/FunctionParser.java | 6 +- .../compiler/parser/module/ImportParser.java | 4 +- .../compiler/parser/module/ModuleParser.java | 4 +- .../statement/DeclarationStatementParser.java | 6 +- .../statement/ExpressionStatementParser.java | 4 +- .../parser/statement/IfStatementParser.java | 6 +- .../parser/statement/LoopStatementParser.java | 22 ++-- .../statement/ReturnStatementParser.java | 4 +- .../parser/utils/ASTJsonSerializer.java | 4 +- .../parser/utils/FlexibleSectionParser.java | 4 +- .../compiler/parser/utils/JSONParser.java | 8 +- .../compiler/parser/utils/JsonFormatter.java | 2 +- .../compiler/parser/utils/ParserUtils.java | 2 +- .../semantic/analyzers/AnalyzerRegistry.java | 2 +- .../analyzers/base/ExpressionAnalyzer.java | 4 +- .../analyzers/base/StatementAnalyzer.java | 4 +- .../expression/BinaryExpressionAnalyzer.java | 10 +- .../expression/CallExpressionAnalyzer.java | 6 +- .../expression/IdentifierAnalyzer.java | 4 +- .../expression/NumberLiteralAnalyzer.java | 18 +-- .../expression/StringLiteralAnalyzer.java | 2 +- .../expression/UnaryExpressionAnalyzer.java | 14 +- .../UnsupportedExpressionAnalyzer.java | 2 +- .../statement/AssignmentAnalyzer.java | 4 +- .../statement/DeclarationAnalyzer.java | 12 +- .../analyzers/statement/IfAnalyzer.java | 12 +- .../analyzers/statement/LoopAnalyzer.java | 2 +- .../analyzers/statement/ReturnAnalyzer.java | 6 +- .../semantic/core/AnalyzerRegistrar.java | 4 +- .../semantic/core/BuiltinTypeRegistry.java | 4 +- .../snow/compiler/semantic/core/Context.java | 18 +-- .../semantic/core/FunctionChecker.java | 4 +- .../compiler/semantic/core/ModuleInfo.java | 2 +- .../semantic/core/SemanticAnalyzer.java | 20 +-- .../semantic/core/SemanticAnalyzerRunner.java | 4 +- .../semantic/core/SignatureRegistrar.java | 2 +- .../jcnc/snow/compiler/semantic/doc/README.md | 12 +- .../semantic/error/SemanticError.java | 4 +- .../snow/compiler/semantic/symbol/Symbol.java | 8 +- .../compiler/semantic/symbol/SymbolKind.java | 10 +- .../compiler/semantic/symbol/SymbolTable.java | 4 +- .../compiler/semantic/type/BuiltinType.java | 8 +- .../compiler/semantic/type/FunctionType.java | 12 +- .../snow/compiler/semantic/type/Type.java | 2 +- .../utils/SemanticAnalysisReporter.java | 4 +- src/main/java/org/jcnc/snow/pkg/doc/README.md | 16 +-- .../org/jcnc/snow/pkg/dsl/CloudDSLParser.java | 6 +- .../snow/pkg/lifecycle/LifecycleManager.java | 2 +- .../org/jcnc/snow/pkg/model/Dependency.java | 6 +- .../java/org/jcnc/snow/pkg/model/Project.java | 2 +- .../org/jcnc/snow/pkg/model/Repository.java | 2 +- .../org/jcnc/snow/pkg/tasks/CleanTask.java | 2 +- .../org/jcnc/snow/pkg/tasks/CompileTask.java | 6 +- .../org/jcnc/snow/pkg/tasks/GenerateTask.java | 4 +- .../java/org/jcnc/snow/pkg/tasks/RunTask.java | 2 +- .../snow/vm/module/LocalVariableStore.java | 2 +- 147 files changed, 696 insertions(+), 705 deletions(-) diff --git a/.gitee/ISSUE_TEMPLATE/chore.yml b/.gitee/ISSUE_TEMPLATE/chore.yml index 50f2a1f..3b4f317 100644 --- a/.gitee/ISSUE_TEMPLATE/chore.yml +++ b/.gitee/ISSUE_TEMPLATE/chore.yml @@ -11,7 +11,7 @@ body: attributes: label: 任务标题 description: 简要描述维护内容 - placeholder: "如:升级 JDK 版本" + placeholder: "如: 升级 JDK 版本" validations: required: true @@ -20,6 +20,6 @@ body: attributes: label: 任务详情 description: 描述执行步骤或相关脚本命令 - placeholder: "如:修改 pom.xml…" + placeholder: "如: 修改 pom.xml…" validations: required: false diff --git a/.gitee/ISSUE_TEMPLATE/enhancement.yml b/.gitee/ISSUE_TEMPLATE/enhancement.yml index 498eda1..3623c6d 100644 --- a/.gitee/ISSUE_TEMPLATE/enhancement.yml +++ b/.gitee/ISSUE_TEMPLATE/enhancement.yml @@ -20,7 +20,7 @@ body: attributes: label: 优化方案 description: 详细描述改进思路与实现方式 - placeholder: "如:缓存机制、算法优化…" + placeholder: "如: 缓存机制、算法优化…" validations: required: true @@ -29,6 +29,6 @@ body: attributes: label: 预期收益 description: 描述优化后带来的效益或体验提升 - placeholder: "如:响应时间缩短 30%…" + placeholder: "如: 响应时间缩短 30%…" validations: required: false diff --git a/.gitee/ISSUE_TEMPLATE/hotfix.yml b/.gitee/ISSUE_TEMPLATE/hotfix.yml index eb98fc4..7e5d25b 100644 --- a/.gitee/ISSUE_TEMPLATE/hotfix.yml +++ b/.gitee/ISSUE_TEMPLATE/hotfix.yml @@ -32,6 +32,6 @@ body: attributes: label: 修复截止日期 description: 填写计划完成的日期 (YYYY-MM-DD) - placeholder: "例如:2025-06-20" + placeholder: "例如: 2025-06-20" validations: required: false diff --git a/.gitee/ISSUE_TEMPLATE/question.yml b/.gitee/ISSUE_TEMPLATE/question.yml index fdbed9a..1cfa5fd 100644 --- a/.gitee/ISSUE_TEMPLATE/question.yml +++ b/.gitee/ISSUE_TEMPLATE/question.yml @@ -20,7 +20,7 @@ body: attributes: label: 已尝试方法 description: 列出已尝试过的解决方案或思路 - placeholder: "如:查阅文档、尝试示例代码…" + placeholder: "如: 查阅文档、尝试示例代码…" validations: required: false @@ -29,6 +29,6 @@ body: attributes: label: 期望答案 description: 描述希望获得的解答或帮助方向 - placeholder: "如:最佳实践、配置示例…" + placeholder: "如: 最佳实践、配置示例…" validations: required: false diff --git a/.gitee/ISSUE_TEMPLATE/refactor.yml b/.gitee/ISSUE_TEMPLATE/refactor.yml index fb575fd..6814f9f 100644 --- a/.gitee/ISSUE_TEMPLATE/refactor.yml +++ b/.gitee/ISSUE_TEMPLATE/refactor.yml @@ -20,7 +20,7 @@ body: attributes: label: 重构原因 description: 说明当前存在的痛点或待改进之处 - placeholder: "如:变量命名不规范、函数职责过多…" + placeholder: "如: 变量命名不规范、函数职责过多…" validations: required: true @@ -29,6 +29,6 @@ body: attributes: label: 预期效果 description: 说明重构后带来的好处或验证方式 - placeholder: "如:提高性能、增强可读性…" + placeholder: "如: 提高性能、增强可读性…" validations: required: false diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md index 711fceb..d66285d 100644 --- a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -3,14 +3,14 @@ https://gitee.com/jcnc-org/snow/blob/main/doc/Git-Management/Git-Management.md 提交 PR 后,请根据实际情况删除不适用的项。 -1. 请在右侧面板中: +1. 请在右侧面板中: - 关联 Issue - 选择 PR 类型(bug 修复 / 新功能 / 文档 / 优化 等) - 添加必要的标签和审查人 - 请添加里程碑 - 如必要请设置优先级 -2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如: +2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如: - [x] 已阅读并遵守项目规范 - [ ] 本地通过所有测试 - [ ] 文档已更新(如有必要) diff --git a/README.md b/README.md index 8593611..da8a7f2 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,11 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的 ## 开发环境安装 -1. **开发环境准备**: +1. **开发环境准备**: 1. 安装集成开发环境 [IntelliJ IDEA](https://www.jetbrains.com/idea/download) 2. 安装 Java 开发工具 [Graalvm-jdk-24](https://www.graalvm.org/downloads/) -2. **获取源码**: +2. **获取源码**: 将项目源码下载或克隆到本地目录。 ```bash git clone https://gitee.com/jcnc-org/snow.git @@ -285,37 +285,37 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的 独立编译不依赖 `.cloud` 文件,而是直接使用 `Snow` 编译器进行 `.snow` 文件的编译和执行。 -#### 独立编译步骤: +#### 独立编译步骤: -1. **运行编译器:** +1. **运行编译器: ** 你可以通过以下命令来编译单个或多个 `.snow` 文件,或者递归编译一个目录中的所有 `.snow` 源文件为`.water`虚拟机指令。 - * **单个文件编译:** + * **单个文件编译: ** ```bash Snow complete [SnowCode].snow ``` - * **多个文件编译:** + * **多个文件编译: ** ```bash Snow complete [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow -o [Name] ``` - * **目录递归编译:** + * **目录递归编译: ** ```bash Snow -d path/to/source_dir ``` -2. **查看编译输出:** - 编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出: +2. **查看编译输出: ** + 编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出: * **AST**(抽象语法树)部分以 JSON 格式输出。 * **IR**(中间表示)部分会列出逐行的中间代码。 * **VM code**(虚拟机指令)会展示虚拟机的字节码指令。 -3. **默认执行模式:** +3. **默认执行模式: ** 编译器会在 **DEBUG 模式** 下运行,显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。 --- @@ -324,30 +324,30 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的 集成编译需要使用 `.cloud` 文件来指定项目的配置和结构,适用于项目标准化、依赖管理、构建管理和项目分发等场景。 -#### 集成编译命令: +#### 集成编译命令: -1. **基本用法:** +1. **基本用法: ** ```bash snow [OPTIONS] ``` -2. **命令选项:** +2. **命令选项: ** - * `-h, --help`:显示帮助信息并退出。 - * `-v, --version`:打印 Snow 编程语言的版本并退出。 + * `-h, --help`: 显示帮助信息并退出。 + * `-v, --version`: 打印 Snow 编程语言的版本并退出。 -3. **可用命令:** +3. **可用命令: ** - * `compile`:将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。 - * `clean`:清理构建输出和本地缓存,移除中间产物,释放磁盘空间。 - * `version`:打印 Snow 的版本。 - * `run`:运行已编译的虚拟机字节码文件(`.water`)。 - * `init`:初始化一个新项目,生成 `project.cloud` 文件。 - * `generate`:根据 `project.cloud` 生成项目目录结构。 - * `build`:构建当前项目,按顺序解析依赖、编译和打包。 + * `compile`: 将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。 + * `clean`: 清理构建输出和本地缓存,移除中间产物,释放磁盘空间。 + * `version`: 打印 Snow 的版本。 + * `run`: 运行已编译的虚拟机字节码文件(`.water`)。 + * `init`: 初始化一个新项目,生成 `project.cloud` 文件。 + * `generate`: 根据 `project.cloud` 生成项目目录结构。 + * `build`: 构建当前项目,按顺序解析依赖、编译和打包。 -4. **例如,执行集成编译命令:** +4. **例如,执行集成编译命令: ** ```bash snow compile [SnowCode].snow @@ -355,14 +355,14 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的 * 此命令会使用 `.cloud` 文件中的配置信息来指导编译过程,并生成 `.water`。 -5. **使用帮助:** - 如果你需要了解某个命令的详细选项,可以使用: +5. **使用帮助: ** + 如果你需要了解某个命令的详细选项,可以使用: ```bash snow --help ``` - 例如,查看 `compile` 命令的具体选项: + 例如,查看 `compile` 命令的具体选项: ```bash snow compile --help @@ -372,7 +372,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的 ## 示例代码片段 -以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法: +以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法: ```snow module: Math @@ -407,10 +407,10 @@ module: Math end module ``` -上述代码定义了一个名为 `Math` 的模块,其中包含两个函数: +上述代码定义了一个名为 `Math` 的模块,其中包含两个函数: -* `main`:不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。 -* `factorial`:接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个 +* `main`: 不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。 +* `factorial`: 接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个 `loop` 循环(从 `counter = 1` 到 `counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。 @@ -418,45 +418,45 @@ end module ## 项目结构说明 -* `compiler/`:Snow 编译器源代码目录 +* `compiler/`: Snow 编译器源代码目录 - * `lexer/`:词法分析模块,负责将源码切分为 Token - * `parser/`:语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析) - * `semantic/`:语义分析模块,负责符号表管理、类型检查等 - * `ir/`:中间表示(IR)模块,生成并管理三地址码形式的中间代码 - * `backend/`:编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器 + * `lexer/`: 词法分析模块,负责将源码切分为 Token + * `parser/`: 语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析) + * `semantic/`: 语义分析模块,负责符号表管理、类型检查等 + * `ir/`: 中间表示(IR)模块,生成并管理三地址码形式的中间代码 + * `backend/`: 编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器 -* `vm/`:虚拟机相关源代码目录 +* `vm/`: 虚拟机相关源代码目录 - * `commands/`:定义 SnowVM 指令集的具体实现 - * `engine/`:核心执行引擎,提供指令执行和寄存器/栈管理 - * `execution/`:执行流程控制(按指令顺序执行、分支跳转等) - * `io/`:输入输出辅助类(加载指令、文件解析等) - * `gui/`:Swing 可视化调试面板,实时展示局部变量表 - * `factories/`、`utils/`:指令创建、日志调试等公共工具 + * `commands/`: 定义 SnowVM 指令集的具体实现 + * `engine/`: 核心执行引擎,提供指令执行和寄存器/栈管理 + * `execution/`: 执行流程控制(按指令顺序执行、分支跳转等) + * `io/`: 输入输出辅助类(加载指令、文件解析等) + * `gui/`: Swing 可视化调试面板,实时展示局部变量表 + * `factories/`、`utils/`: 指令创建、日志调试等公共工具 -* `pkg/`:内置构建与包管理器 **snow pkg** +* `pkg/`: 内置构建与包管理器 **snow pkg** - * `dsl/`:`.cloud` 描述文件解析器 - * `tasks/`:预设任务实现(`clean · compile · run · package · publish` 等) - * `resolver/`:本地/远程仓库解析与缓存 - * `lifecycle/`:任务生命周期钩子(pre/post 脚本等) - * `model/`:项目、依赖、版本等模型 - * `utils/`:文件、日志、校验和等通用工具 - * `doc/`:开发者文档与示例 `.cloud` 配置 + * `dsl/`: `.cloud` 描述文件解析器 + * `tasks/`: 预设任务实现(`clean · compile · run · package · publish` 等) + * `resolver/`: 本地/远程仓库解析与缓存 + * `lifecycle/`: 任务生命周期钩子(pre/post 脚本等) + * `model/`: 项目、依赖、版本等模型 + * `utils/`: 文件、日志、校验和等通用工具 + * `doc/`: 开发者文档与示例 `.cloud` 配置 -* `cli/`:独立的命令行前端 +* `cli/`: 独立的命令行前端 - * `commands/`:`compile` / `run` / `pkg` 等子命令实现 - * `api/`:公共选项解析、终端交互抽象 - * `utils/`:终端颜色、进度条、异常格式化等 - * `SnowCLI.java`:CLI 主入口 + * `commands/`: `compile` / `run` / `pkg` 等子命令实现 + * `api/`: 公共选项解析、终端交互抽象 + * `utils/`: 终端颜色、进度条、异常格式化等 + * `SnowCLI.java`: CLI 主入口 ## 版权声明 版权所有 © 2025 许轲(Luke),代表 SnowLang 项目。 -仓库地址: +仓库地址: 本项目依据 [Apache 2.0 许可证](LICENSE) 进行许可和发布。 “SnowLang 项目”为由许轲(Luke)发起的独立开源项目。 @@ -464,7 +464,7 @@ end module ## 加入我们 -- 微信:`xuxiaolankaka` -- QQ:`1399528359` -- 邮箱:`luke.k.xu [at] hotmail.com` +- 微信: `xuxiaolankaka` +- QQ: `1399528359` +- 邮箱: `luke.k.xu [at] hotmail.com` diff --git a/build/README.md b/build/README.md index 085aac2..bf9cdf7 100644 --- a/build/README.md +++ b/build/README.md @@ -2,27 +2,27 @@ 在执行 `build-project2tar.ps1` 脚本之前,您需要确保 PowerShell 的执行策略允许运行脚本。默认情况下,PowerShell 可能阻止未签名的脚本执行。因此,您需要设置适当的执行策略。 -#### 步骤 1:以管理员身份打开 PowerShell +#### 步骤 1: 以管理员身份打开 PowerShell * 在 Windows 系统中,搜索 **PowerShell**,右键点击 **Windows PowerShell**,并选择 **以管理员身份运行**。 -#### 步骤 2:设置 PowerShell 执行策略 +#### 步骤 2: 设置 PowerShell 执行策略 -为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter: +为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter: ```powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned ``` -#### 解释: +#### 解释: -* `-Scope CurrentUser`:此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。 -* `-ExecutionPolicy RemoteSigned`:此策略表示: +* `-Scope CurrentUser`: 此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。 +* `-ExecutionPolicy RemoteSigned`: 此策略表示: * 本地创建的脚本可以直接运行。 * 从互联网下载的脚本必须具备有效的数字签名才能运行。没有签名的脚本将无法执行,除非您先解除阻止该脚本。 -#### 步骤 3:运行 `build-project2tar.ps1` 脚本 +#### 步骤 3: 运行 `build-project2tar.ps1` 脚本 设置完成后,您可以在 PowerShell 中运行 `build-project2tar.ps1` 脚本。确保您已经切换到包含该脚本的目录,或提供完整的文件路径来执行它。 diff --git a/build/build_project2tar.ps1 b/build/build_project2tar.ps1 index 8e214ce..81b5d69 100644 --- a/build/build_project2tar.ps1 +++ b/build/build_project2tar.ps1 @@ -11,7 +11,7 @@ $parentDir = Split-Path -Parent $scriptDir $tarPath = Join-Path $parentDir $tarName # 输出开始创建 tar 包的消息 -Write-Output "开始创建 tar 包:$tarName 到 $parentDir ..." +Write-Output "开始创建 tar 包: $tarName 到 $parentDir ..." # 如果存在旧 tar 包,先删除它 if (Test-Path $tarPath) { @@ -26,7 +26,7 @@ if (-not (Get-Command $tarCommand -ErrorAction SilentlyContinue)) { exit 1 } -# 执行打包操作:切换到 org\jcnc 目录下再压缩 snow 文件夹 +# 执行打包操作: 切换到 org\jcnc 目录下再压缩 snow 文件夹 try { # 构建命令并执行 $tarCommandArgs = "-cf", $tarPath, "-C", "$scriptDir\..\src\main\java\org\jcnc", "snow" @@ -34,7 +34,7 @@ try { & $tarCommand @tarCommandArgs } catch { - Write-Error "❌ 创建 tar 包失败。错误信息:$_" + Write-Error "❌ 创建 tar 包失败。错误信息: $_" exit 1 } diff --git a/docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md b/docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md index 5f12e99..f61b01a 100644 --- a/docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md +++ b/docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md @@ -2,7 +2,7 @@ ## 1. 版本控制基础 -本项目使用 Git 进行版本控制,并遵循以下基本原则: +本项目使用 Git 进行版本控制,并遵循以下基本原则: * 所有代码更改必须通过 Git 提交,并推送至远程仓库。 * 每次提交必须包括清晰、简洁且具描述性的提交信息,确保团队成员能够轻松理解变更的目的和内容。 @@ -10,23 +10,23 @@ ## 2. 分支管理 -本项目采用以下分支策略进行代码管理: +本项目采用以下分支策略进行代码管理: ### 2.1 主分支 (`main`) -* **用途**:`main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。 -* **更新规则**:仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev` 或 `release` 分支合并到 `main` 时,必须打上版本标签。 +* **用途**: `main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。 +* **更新规则**: 仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev` 或 `release` 分支合并到 `main` 时,必须打上版本标签。 ### 2.2 开发分支 (`dev`) -* **用途**:`dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`。 -* **更新规则**:所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`。 +* **用途**: `dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`。 +* **更新规则**: 所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`。 ### 2.3 功能分支 (`feature/*`) -* **用途**:每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。 -* **命名规范**:`feature/功能描述`,例如:`feature/ast-folding`、`feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。 -* **开发流程**: +* **用途**: 每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。 +* **命名规范**: `feature/功能描述`,例如: `feature/ast-folding`、`feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。 +* **开发流程**: 1. 从 `dev` 分支拉取最新代码。 2. 完成功能开发后,在本地提交代码并推送至远程仓库。 @@ -34,9 +34,9 @@ ### 2.4 修复分支 (`bugfix/*`) -* **用途**:用于修复 Bug,修复分支可以从 `dev` 或 `main` 分支创建。 -* **命名规范**:`bugfix/bug描述`,例如:`bugfix/fix-ast-error`。 -* **开发流程**: +* **用途**: 用于修复 Bug,修复分支可以从 `dev` 或 `main` 分支创建。 +* **命名规范**: `bugfix/bug描述`,例如: `bugfix/fix-ast-error`。 +* **开发流程**: 1. 从 `dev` 或 `main` 分支拉取最新代码。 2. 完成修复后,提交修改并推送至远程仓库。 @@ -44,9 +44,9 @@ ### 2.5 发布分支 (`release/*`) -* **用途**:当 `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。 -* **命名规范**:`release/vX.X.X`,例如:`release/v1.0.0`。 -* **开发流程**: +* **用途**: 当 `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。 +* **命名规范**: `release/vX.X.X`,例如: `release/v1.0.0`。 +* **开发流程**: 1. 从 `dev` 分支创建 `release` 分支。 2. 在 `release` 分支上进行版本发布的最终准备工作,如文档更新、版本号调整等。 @@ -54,24 +54,24 @@ ### 2.6 热修复分支 (`hotfix/*`) -* **用途**:当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。 -* **命名规范**:`hotfix/bug描述`,例如:`hotfix/fix-production-crash`。 -* **开发流程**: +* **用途**: 当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。 +* **命名规范**: `hotfix/bug描述`,例如: `hotfix/fix-production-crash`。 +* **开发流程**: 1. 从 `main` 分支创建 `hotfix` 分支,确保该分支包含生产环境中最新的稳定版本。 2. 在 `hotfix` 分支上进行问题修复和相关调整。 3. 完成修复后,提交修改并推送至远程仓库。 4. 创建拉取请求(PR),将 `hotfix` 分支合并至 `main` 分支并打上版本标签,确保生产环境修复生效。 5. 将修复后的变更合并回 `dev` 分支,确保所有的修复和调整同步到开发分支,防止后续开发中出现同样的问题。 - 6. **回滚策略**:如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。 + 6. **回滚策略**: 如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。 ## 3. 提交规范 -为确保提交信息清晰且易于理解,遵循以下提交规范: +为确保提交信息清晰且易于理解,遵循以下提交规范: ### 3.1 提交信息格式 -提交信息应简洁且具有描述性,格式如下: +提交信息应简洁且具有描述性,格式如下: ``` [类型] 描述 @@ -81,20 +81,20 @@ #### 提交类型 -* `feat`:新增功能 -* `fix`:修复 Bug -* `docs`:文档更新 -* `style`:代码格式调整(不影响功能) -* `refactor`:代码重构 -* `test`:增加/修改测试 -* `chore`:工具配置等其他杂项任务 -* `ci`:持续集成相关改动 -* `perf`:性能优化 +* `feat`: 新增功能 +* `fix`: 修复 Bug +* `docs`: 文档更新 +* `style`: 代码格式调整(不影响功能) +* `refactor`: 代码重构 +* `test`: 增加/修改测试 +* `chore`: 工具配置等其他杂项任务 +* `ci`: 持续集成相关改动 +* `perf`: 性能优化 #### 示例 * `feat: 添加 IR 折叠功能` -* `fix: 修复问题 Y(原因:X bug,解决方案:Z)` +* `fix: 修复问题 Y(原因: X bug,解决方案: Z)` * `docs: 更新 API 文档` * `refactor: 优化 AST 逻辑` @@ -114,7 +114,7 @@ ### 4.2 代码审查 * 所有 PR 必须经过至少一名开发者的代码审查。 -* 审查时应关注以下方面: +* 审查时应关注以下方面: * 代码是否符合项目的编码规范。 * 是否提供了足够的单元测试覆盖。 @@ -124,14 +124,14 @@ ## 5. 版本发布 -版本发布基于 Git 标签,发布流程如下: +版本发布基于 Git 标签,发布流程如下: ### 5.1 打标签 -每当版本准备发布时,应在 `main` 分支上打上版本标签: +每当版本准备发布时,应在 `main` 分支上打上版本标签: -* **版本号规则**:采用语义化版本控制(SemVer)格式,版本号由三部分组成:`主版本号.次版本号.修订号`(例如:`v1.0.0`)。 -* **标签命令**: +* **版本号规则**: 采用语义化版本控制(SemVer)格式,版本号由三部分组成: `主版本号.次版本号.修订号`(例如: `v1.0.0`)。 +* **标签命令**: ```bash git tag v1.0.0 diff --git a/docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/Snow-Lang-GraalVM-AOT-Native-Image-Package.md b/docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/Snow-Lang-GraalVM-AOT-Native-Image-Package.md index 49c971c..0b3dc83 100644 --- a/docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/Snow-Lang-GraalVM-AOT-Native-Image-Package.md +++ b/docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/Snow-Lang-GraalVM-AOT-Native-Image-Package.md @@ -6,7 +6,7 @@ ## 2. 前置条件 -1. 操作系统:Linux/macOS/Windows +1. 操作系统: Linux/macOS/Windows 2. Java 项目(Maven) 3. GraalVM(建议 24+ 版本) @@ -14,10 +14,10 @@ ### 3.1 安装 GraalVM -1. 下载对应平台的 GraalVM Community 版本:[https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/) -2. 解压并配置环境变量: +1. 下载对应平台的 GraalVM Community 版本: [https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/) +2. 解压并配置环境变量: -3. 验证安装: +3. 验证安装: ```bash java -version @@ -44,12 +44,12 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc ## 4. Maven 项目配置文件 -通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件: +通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件: ```xml @@ -111,7 +111,7 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc @@ -169,6 +169,6 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc ![IMG_Maven_Package_1.png](img/IMG_Maven_Package_1.png) -3. 等待 Native Image 构建完成:这个过程可能较慢(数分钟)。 +3. 等待 Native Image 构建完成: 这个过程可能较慢(数分钟)。 4. 可执行文件即可直接运行,无需 JVM。 > 生成的可执行文件位于 target/ 目录。 diff --git a/docs/Snow-Lang-Journey/Snow-Lang-Journey.md b/docs/Snow-Lang-Journey/Snow-Lang-Journey.md index a967dc4..c203998 100644 --- a/docs/Snow-Lang-Journey/Snow-Lang-Journey.md +++ b/docs/Snow-Lang-Journey/Snow-Lang-Journey.md @@ -7,22 +7,22 @@ ## 1.2 背景与目标读者 -自 ChatGPT 3.5 诞生以来,越来越多的个人和企业将 LLM 生成的代码融入日常开发与自动化。然而,实践证明:LLM 生成的代码虽然“看起来没问题”,却常因对底层语言细节把握不准导致微妙 Bug——比如运算符优先级混淆、作用域处理错误、甚至基础库调用都无法编译通过。 +自 ChatGPT 3.5 诞生以来,越来越多的个人和企业将 LLM 生成的代码融入日常开发与自动化。然而,实践证明: LLM 生成的代码虽然“看起来没问题”,却常因对底层语言细节把握不准导致微妙 Bug——比如运算符优先级混淆、作用域处理错误、甚至基础库调用都无法编译通过。 -于是,我萌生了这样一个想法:**能否设计一门编程语言,让 LLM 在“语法层面”能够更精准、高效地理解和生成代码?** +于是,我萌生了这样一个想法: **能否设计一门编程语言,让 LLM 在“语法层面”能够更精准、高效地理解和生成代码?** -传统编程语言的设计多偏重“计算机”的执行效率,程序员往往在抽象表达和底层性能之间不断权衡。Ruby 之父松本行弘提出“为人而不是为机器编程”的理念。而在 LLM 日益普及的今天,我们应当承认:大型模型正成为“超级程序员”,它们不仅是助手,更是“代码生产的中介”。如果一门语言的语法和设计能最大化发挥 LLM 的推理与生成能力,人机协作的效率将被极大提升。 +传统编程语言的设计多偏重“计算机”的执行效率,程序员往往在抽象表达和底层性能之间不断权衡。Ruby 之父松本行弘提出“为人而不是为机器编程”的理念。而在 LLM 日益普及的今天,我们应当承认: 大型模型正成为“超级程序员”,它们不仅是助手,更是“代码生产的中介”。如果一门语言的语法和设计能最大化发挥 LLM 的推理与生成能力,人机协作的效率将被极大提升。 -因此,**Snow** 的使命是:让编程语言不再“让人头疼”,而是“让 LLM 更加从容地书写”。目标受众涵盖 LLM 爱好者、开发者、对编译原理感兴趣的学生,以及对性能有追求的工程师甚至是初学者——每个人都能在 Snow 中找到乐趣与成长。 +因此,**Snow** 的使命是: 让编程语言不再“让人头疼”,而是“让 LLM 更加从容地书写”。目标受众涵盖 LLM 爱好者、开发者、对编译原理感兴趣的学生,以及对性能有追求的工程师甚至是初学者——每个人都能在 Snow 中找到乐趣与成长。 ## 1.3 文章目的 -本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标: +本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标: -* **兴趣驱动的坚持**:用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。 -* **从规划到实践的拆解**:详解在有限资源下,如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。 -* **经验与反思**:不仅有“成功输出 1+1=2”的成就感,也有调试死循环、运算符冲突等踩坑经历,全方位展示编程语言设计的挑战与思考。 -* **激励与号召**:希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。 +* **兴趣驱动的坚持**: 用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。 +* **从规划到实践的拆解**: 详解在有限资源下,如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。 +* **经验与反思**: 不仅有“成功输出 1+1=2”的成就感,也有调试死循环、运算符冲突等踩坑经历,全方位展示编程语言设计的挑战与思考。 +* **激励与号召**: 希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。 --- @@ -31,18 +31,18 @@ ## 2.1 现有工具的痛点 * **编程语言过于灵活,缺乏规范** - 常见的编程语言如 Python、PHP、Ruby,虽然语法简洁、上手快,但“灵活性”本身也带来了不少隐患:变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考:如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶? + 常见的编程语言如 Python、PHP、Ruby,虽然语法简洁、上手快,但“灵活性”本身也带来了不少隐患: 变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考: 如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶? * **缺乏专为 LLM 设计的编程语言** - 当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如:部分语法容易混淆,作用域和可见性规则不直观,LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。 + 当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如: 部分语法容易混淆,作用域和可见性规则不直观,LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。 ## 2.2 触发想法的场景 * **对高效与规范的需求日益突出** - 在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论:能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。 + 在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论: 能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。 * **自研编程语言的大胆设想** - 随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP,总要写很多提示,还要人工修正各种细节。由此引发思考:如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率? + 随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP,总要写很多提示,还要人工修正各种细节。由此引发思考: 如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率? ## 2.3 项目愿景 @@ -62,12 +62,12 @@ ## 3.1 为什么开源 -* **获得社区反馈,检验设计思路**:闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。 -* **边开源边完善,更吸引贡献者**:功能精简但可用时就发布,容易吸引早期用户参与共建。 +* **获得社区反馈,检验设计思路**: 闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。 +* **边开源边完善,更吸引贡献者**: 功能精简但可用时就发布,容易吸引早期用户参与共建。 ## 3.2 开源准备工作 -* **许可证选择**: +* **许可证选择**: 采用 [Apache-2.0](https://gitee.com/jcnc-org/snow/blob/main/LICENSE),最大程度降低贡献门槛。 ## 3.3 项目运行输出 @@ -248,11 +248,11 @@ Process has ended ## 4.1 v0.2 初步目标 -1. **完善变量作用域与高级函数调用**: +1. **完善变量作用域与高级函数调用**: 支持函数参数、返回值、本地与全局变量隔离,以及闭包基础,为并发/异步打基础。 -2. **完善错误提示与调试信息**: +2. **完善错误提示与调试信息**: 报错更精准,方便新手调试。 -3. **预计发布日期:2025 年 7 月 30 日** +3. **预计发布日期: 2025 年 7 月 30 日** ## 4.2 v0.3 目标 1. **IDE的支持** @@ -262,11 +262,11 @@ Process has ended ## 4.3 v1.0 长期规划 -1. **初步标准库**: +1. **初步标准库**: I/O、字符串、JSON、文件系统,满足日常脚本需求。 -2. **包管理与模块加载**: +2. **包管理与模块加载**: 设计 `snowpkg`,支持一键安装依赖、自动模块导入。 -3. **社区协作与贡献**: +3. **社区协作与贡献**: 开设设计讨论区、每月线上分享,鼓励贡献代码与案例,让更多人参与 Snow 的成长。 --- @@ -275,15 +275,15 @@ Process has ended ## 5.1 学习收获与成就感 -回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是:让一个想法变成可运行的代码,哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。 +回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是: 让一个想法变成可运行的代码,哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。 ## 5.2 技术敬畏与情感共鸣 -也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节:多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。 +也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节: 多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。 ## 5.3 欢迎你的加入 -真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴: +真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴: 1. 在 Gitee 提交 Issue,反馈使用体验和建议; 2. Fork 仓库、贡献 PR,参与语法和功能共建; @@ -294,7 +294,7 @@ Process has ended > 微信: xuxiaolankaka > QQ: 1399528359 -对于从未写过语言的初学者,我想说:**不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。 +对于从未写过语言的初学者,我想说: **不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。 --- diff --git a/docs/Snow-Lang-Roadmap/Snow-Lang-Roadmap-2025-06-11.md b/docs/Snow-Lang-Roadmap/Snow-Lang-Roadmap-2025-06-11.md index 8e7ba82..7e28eda 100644 --- a/docs/Snow-Lang-Roadmap/Snow-Lang-Roadmap-2025-06-11.md +++ b/docs/Snow-Lang-Roadmap/Snow-Lang-Roadmap-2025-06-11.md @@ -1,6 +1,6 @@ # Snow 语言现状和下一阶段开发路线图 -> 日期:2025-06-11 +> 日期: 2025-06-11 ## 1. 代码结构与职责 | 层次 | 主要包/目录 | 说明 | @@ -30,7 +30,7 @@ 6. **VM** * 栈-基 / 寄存器混合架构 - * 96 条已实现指令(按数据宽度泛化:B/S/I/L/F/D) + * 96 条已实现指令(按数据宽度泛化: B/S/I/L/F/D) * 运行时启动器 `VMLauncher` @@ -50,7 +50,7 @@ ## 4. 下一阶段开发路线图 -> 优先级:P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期 +> 优先级: P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期 | 优先级 | 功能 | 关键任务 | |--------|------------------|----------------------------------------------------------------------------------------------------------------------| @@ -58,18 +58,18 @@ | **P0** | **一元表达式解析** | \* 实现 `UnaryOperatorParselet`(`-`, `+`, `!`)
\* 对应 `UnaryOpGenerator` 注册 | | **P1** | **数组与切片** | \* 设计 `ArrayType`(元素类型 + 维度)
\* 新增 `IndexExpressionNode`、`NewArrayNode`
\* VM 扩充 `ALOAD/ASTORE` 指令 | | **P1** | **基础标准库** | \* `print/println`, 文件读写
\* 编译期内置绑定到 VM calls | -| **P1** | **测试与 CI** | \* JUnit5 单测:Lexer / Parser / Semantic / VM
\* CI/CD 自动构建、示例编译运行 | -| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局
\* 方法调度:静态 or 虚表 | +| **P1** | **测试与 CI** | \* JUnit5 单测: Lexer / Parser / Semantic / VM
\* CI/CD 自动构建、示例编译运行 | +| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局
\* 方法调度: 静态 or 虚表 | | **P2** | **优化管线** | \* 常量折叠、公共子表达式消除
\* 简易死代码清除 | -| **P2** | **错误与异常系统** | \* 语法:`try … catch … end`
\* VM:展开-收缩栈,异常表 | -| **P2** | **包管理 & CLI** | \* `snowc` 命令:`build`, `run`, `test`
\* 本地缓存 `.snowpkg`与包版本语义 | +| **P2** | **错误与异常系统** | \* 语法: `try … catch … end`
\* VM: 展开-收缩栈,异常表 | +| **P2** | **包管理 & CLI** | \* `snowc` 命令: `build`, `run`, `test`
\* 本地缓存 `.snowpkg`与包版本语义 | ## 5.1 里程碑排期 | 时间 | 目标 | |---------|----------------------------------------| -| 2025-07 | 发布 **v0.2.0**:布尔类型 + 一元运算、20+ 单元测试 | -| 2025-08 | 发布 **v0.3.0**:数组/切片 & 基础标准库;引入 CLI | -| 2025-10 | 发布 **v0.4.0**:结构体支持、首批优化 Pass、>80% 覆盖率 | -| 2026-11 | 发布 **v1.0.0**:异常系统、稳定包管理、文档完善 | +| 2025-07 | 发布 **v0.2.0**: 布尔类型 + 一元运算、20+ 单元测试 | +| 2025-08 | 发布 **v0.3.0**: 数组/切片 & 基础标准库;引入 CLI | +| 2025-10 | 发布 **v0.4.0**: 结构体支持、首批优化 Pass、>80% 覆盖率 | +| 2026-11 | 发布 **v1.0.0**: 异常系统、稳定包管理、文档完善 | diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md index a529bf4..58fa46e 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md @@ -4,8 +4,8 @@ ## 0 · 符号约定 -* ⟦ … ⟧:可选项(0 或 1 次) -* { … }\*:可重复项(0 次或多次) +* ⟦ … ⟧: 可选项(0 或 1 次) +* { … }\*: 可重复项(0 次或多次) --- @@ -19,12 +19,12 @@ identifier ::= [A-Za-z_][A-Za-z0-9_]* ; ``` -* **区分大小写**:Foo 与 foo 为不同标识符。 +* **区分大小写**: Foo 与 foo 为不同标识符。 * 保留字 (见 §1.3) **禁止** 用作标识符。 ### 1.2 分隔符与强制空白 -相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例: +相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例: ```snow module: Foo // 推荐 @@ -44,22 +44,22 @@ end loop break continue self ### 1.4 文字量 (Literal) -* **整型**:123 0 -42 -* **浮点**:3.14 0.0 -* **布尔**:true false -* **字符串**:未来版本保留;当前规范未定义。 +* **整型**: 123 0 -42 +* **浮点**: 3.14 0.0 +* **布尔**: true false +* **字符串**: 未来版本保留;当前规范未定义。 ### 1.5 注释 -* **单行注释**:以 // 起,至当行行尾。 -* **多行注释**:/* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。 +* **单行注释**: 以 // 起,至当行行尾。 +* **多行注释**: /* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。 --- ### 1.6 换行与缩进 -* **只有换行有语义**:以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。 -* **缩进没有语义**:缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。 +* **只有换行有语义**: 以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。 +* **缩进没有语义**: 缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。 * 块体通过显式关闭关键字(如 end module、end function 等)结束。 * 若关闭关键字与开始关键字之间的缩进不一致,不会报错,仍以关闭关键字为准。 @@ -82,7 +82,7 @@ end module * **允许** 不同文件夹下声明同名模块,但模块全名(含包路径,用点分隔)在全项目中必须唯一。 * 若项目中出现重复的模块全名,编译阶段将报重定义错误。 -例如: +例如: > src/util/math.snow // module: util.math > src/core/math.snow // module: core.math > @@ -95,15 +95,15 @@ import: ⟦ as ⟧, ⟦ as ⟧, … ``` * **别名 (Alias)** 可为任何合法标识符,放在 as 关键字之后。 -* **重复导入**:对同一模块多次导入(无论是否带 alias)只解析一次,其余忽略告警。 -* **循环依赖**:当前规范未定义,若出现编译器可拒绝或延迟解析。 +* **重复导入**: 对同一模块多次导入(无论是否带 alias)只解析一次,其余忽略告警。 +* **循环依赖**: 当前规范未定义,若出现编译器可拒绝或延迟解析。 * **子模块**(诸如 A.B)暂不支持。 ### 2.3 全路径引用 * 跨模块引用必须使用 _Prefix_._Name_,其中 *Prefix* 是模块名或导入时的别名。 - 例如:Math.Point 或 M.sin。 -* **解析顺序**:未加前缀的标识符只在本模块查找;找不到则视为编译错误,不会隐式搜索导入模块。 + 例如: Math.Point 或 M.sin。 +* **解析顺序**: 未加前缀的标识符只在本模块查找;找不到则视为编译错误,不会隐式搜索导入模块。 --- @@ -111,27 +111,27 @@ import: ⟦ as ⟧, ⟦ as ⟧, … ### 3.1 作用域层级 -1. **模块顶层**:全局变量、结构体、模块级函数。 -2. **结构体内部**:字段、方法、构造函数。 -3. **函数/方法**:形参与局部变量。 +1. **模块顶层**: 全局变量、结构体、模块级函数。 +2. **结构体内部**: 字段、方法、构造函数。 +3. **函数/方法**: 形参与局部变量。 4. **局部嵌套块** (if / loop 等) 的局部变量。 ### 3.2 唯一性规则 -* **模块顶层唯一**:同一模块的 *结构体名*、*模块级函数名*、*全局变量名* **不得重名**。 -* **结构体内部**:字段名与方法名不得相同;**允许有多个与结构体名同名的函数(即构造函数重载),但其参数签名必须互不相同。** -* **构造函数重载**:结构体内部可以声明多个与结构体名同名的函数作为构造函数,参数类型与数量必须不同,否则属于 DuplicateName 错误。 -* **跨层级遮蔽**:内层可定义与外层同名标识符(除关键字限制外),遵循最近作用域原则。 +* **模块顶层唯一**: 同一模块的 *结构体名*、*模块级函数名*、*全局变量名* **不得重名**。 +* **结构体内部**: 字段名与方法名不得相同;**允许有多个与结构体名同名的函数(即构造函数重载),但其参数签名必须互不相同。** +* **构造函数重载**: 结构体内部可以声明多个与结构体名同名的函数作为构造函数,参数类型与数量必须不同,否则属于 DuplicateName 错误。 +* **跨层级遮蔽**: 内层可定义与外层同名标识符(除关键字限制外),遵循最近作用域原则。 ### 3.3 访问控制约定 -* **私有成员与方法**:以单个下划线 `_` 开头的变量名、字段名或方法名,**仅在其所属结构体或模块内部可见**。外部不可访问,编译器应报错 `AccessDenied`。 +* **私有成员与方法**: 以单个下划线 `_` 开头的变量名、字段名或方法名,**仅在其所属结构体或模块内部可见**。外部不可访问,编译器应报错 `AccessDenied`。 - 例如 `_foo`, `_barMethod`。 -* **公有成员与方法**:非下划线开头的变量、字段、方法,默认为公有。可在模块外部通过模块名/别名前缀访问。 +* **公有成员与方法**: 非下划线开头的变量、字段、方法,默认为公有。可在模块外部通过模块名/别名前缀访问。 #### 影响范围 -- **模块级变量与函数**:`globals` 和 `function` 语句声明的以 `_` 开头者,仅限本模块访问。 -- **结构体字段与方法**:声明为 `_name`、`_doSomething` 的,仅结构体本身或其方法体可访问。 +- **模块级变量与函数**: `globals` 和 `function` 语句声明的以 `_` 开头者,仅限本模块访问。 +- **结构体字段与方法**: 声明为 `_name`、`_doSomething` 的,仅结构体本身或其方法体可访问。 --- #### 访问示例 @@ -220,7 +220,7 @@ struct: StructName end struct ``` -**实例化**: +**实例化**: * declare p: Point = Point(1, 2) * declare p2: Point = Point(3) @@ -243,7 +243,7 @@ function: FuncName end function ``` -* **返回检查**:若 returns: 指定类型非 void,所有控制流路径必须显式 return 该类型值。 +* **返回检查**: 若 returns: 指定类型非 void,所有控制流路径必须显式 return 该类型值。 * 在 loop 内或经 break 跳出后能到达的路径亦计入检查;若缺失,编译错误。 --- @@ -287,7 +287,7 @@ loop: end loop ``` -* **作用域**:init 块声明的变量仅在本 loop 的 init/cond/step/body 有效。 +* **作用域**: init 块声明的变量仅在本 loop 的 init/cond/step/body 有效。 * break 立即终止当前循环;continue 跳过剩余 body,执行 step → cond。 --- @@ -296,7 +296,7 @@ end loop ### 6.1 数值类型 -Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等: +Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等: | 类型名 | 关键字 | 位数 | 描述 | |----------|--------|----|---------------------------| @@ -315,7 +315,7 @@ Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体 #### 数值字面量后缀 -为指定具体类型,可在数值字面量后加后缀字母(大小写均可): +为指定具体类型,可在数值字面量后加后缀字母(大小写均可): | 后缀 | 类型 | 例子 | |----|--------|----------| @@ -329,7 +329,7 @@ Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体 - 没有后缀的整数字面量自动为 `int`。 - 没有后缀的浮点字面量自动为 `double`。 -**示例:** +**示例: ** ```snow declare a: int = 7 // int (默认) declare b: long = 9l // long @@ -405,17 +405,17 @@ declare a: Point = Point(1, 2) ## 7 · 名字解析算法(概览) -1. **输入**:未限定前缀的标识符 N,当前作用域 S。 +1. **输入**: 未限定前缀的标识符 N,当前作用域 S。 2. 自内向外遍历作用域链查找 N;首次匹配即确定绑定。 3. 若遍历至模块顶层仍未匹配,编译错误 *UnresolvedIdentifier*。 -4. 限定名 Prefix.N:直接在模块表中查 Prefix(包括别名),成功后在该模块顶层查找 N;找不到即 *UnresolvedQualifiedIdentifier*。 +4. 限定名 Prefix.N: 直接在模块表中查 Prefix(包括别名),成功后在该模块顶层查找 N;找不到即 *UnresolvedQualifiedIdentifier*。 --- ## 8 · 编译单位与入口 -* **单一入口**:编译器需指定某模块某函数作为启动入口。 -* **模块初始化**:globals 块中的带初值变量在程序启动时自顶向下按出现顺序初始化;不同模块按依赖拓扑顺序初始化(循环依赖未定义)。 +* **单一入口**: 编译器需指定某模块某函数作为启动入口。 +* **模块初始化**: globals 块中的带初值变量在程序启动时自顶向下按出现顺序初始化;不同模块按依赖拓扑顺序初始化(循环依赖未定义)。 --- @@ -445,7 +445,7 @@ module: RectExample declare x: int declare y: int - // 构造函数1:两个参数 + // 构造函数1: 两个参数 function: Point params: declare x: int @@ -456,7 +456,7 @@ module: RectExample end body end function - // 构造函数2:一个参数 + // 构造函数2: 一个参数 function: Point params: declare xy: int @@ -553,7 +553,7 @@ end module ## 11 · 构造函数重载示例 -**示例:** +**示例: ** ````snow struct: Point diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md b/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md index 2ac5fdd..169fdb1 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md @@ -31,14 +31,14 @@ end module ### 数据类型 -bool 类型: +bool 类型: -两种值:`true` 和 `false` +两种值: `true` 和 `false` -数值类型: +数值类型: | Number | keyword | |----------|---------| @@ -51,7 +51,7 @@ bool 类型: 默认整数的类型为 int,浮点数的类型为 double。 -数值字面量后缀: +数值字面量后缀: | 数值字面量后缀 | 例子 | |---------|----| @@ -64,7 +64,7 @@ bool 类型: ### 变量 -定义变量的形式如下,中括号表示可选: +定义变量的形式如下,中括号表示可选: ```snow declare name: type [= initial_value] @@ -72,24 +72,24 @@ declare name: type [= initial_value] 其中 `name` 是变量名,`type` 是变量类型,`initial_value` 是初始值 -例: +例: ```snow declare x: int declare y: long = 123456789 ``` -读取变量值的方法,直接写变量的名字即可: +读取变量值的方法,直接写变量的名字即可: ```snow x ``` -设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可: +设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可: ```snow x = 10 ``` -于是可以通过这种方式让变量参与计算并保存结果: +于是可以通过这种方式让变量参与计算并保存结果: ```snow x = y + 1 ``` @@ -99,7 +99,7 @@ x = y + 1 ## 流程控制 ### if -if 语句的形式如下,else 是可选的: +if 语句的形式如下,else 是可选的: ```snow if cond then @@ -111,7 +111,7 @@ end if cond 可以是表达式(结果为 bool 类型)或者 bool 字面量 -例: +例: ```snow module: Main @@ -131,7 +131,7 @@ end module ``` ### loop -loop 语句的形式如下: +loop 语句的形式如下: ```snow loop: init: @@ -150,7 +150,7 @@ loop: end loop ``` -例子(求 1 ~ 100 的和): +例子(求 1 ~ 100 的和): ```snow module: Main function: main @@ -176,7 +176,7 @@ end module ``` ## 函数 -函数的形式如下: +函数的形式如下: ```snow function: add parameter: @@ -197,7 +197,7 @@ end function 通过 import 语句导入模块, snow 会自动将同名模块的函数合并。 -在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下: +在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下: ```snow module: Main @@ -213,7 +213,7 @@ end module 可以看到模块名是 Main,里面有函数 main。 -假如现在有一个模块 Math,代码如下: +假如现在有一个模块 Math,代码如下: ```snow // Math.snow module: Math @@ -229,7 +229,7 @@ module: Math end module ``` -可以使用 import 来导入 Math 模块: +可以使用 import 来导入 Math 模块: ```snow // main.snow module: Main @@ -244,7 +244,7 @@ module: Main end module ``` -可以同时导入多个模块,用逗号(半角)分隔模块名即可: +可以同时导入多个模块,用逗号(半角)分隔模块名即可: ```snow // main.snow module: Main diff --git a/playground/BugFarm/Bug1/Main.snow b/playground/BugFarm/Bug1/Main.snow index cc9117d..c77b004 100644 --- a/playground/BugFarm/Bug1/Main.snow +++ b/playground/BugFarm/Bug1/Main.snow @@ -1,17 +1,8 @@ module: Main function: main - return_type: int - body: - foo() - - return 0 - end body - end function - - function: foo return_type: void body: - + declare 1sum :int =1 end body end function end module \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2d33298..53b5d38 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ @@ -45,7 +45,7 @@ @@ -71,7 +71,7 @@ @@ -133,7 +133,7 @@ diff --git a/src/main/java/org/jcnc/snow/cli/commands/BuildCommand.java b/src/main/java/org/jcnc/snow/cli/commands/BuildCommand.java index 17e1c0f..47982f4 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/BuildCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/BuildCommand.java @@ -13,13 +13,13 @@ import java.nio.file.Path; import java.nio.file.Paths; /** - * CLI 命令:构建当前项目(包含依赖解析、编译、打包)。 + * CLI 命令: 构建当前项目(包含依赖解析、编译、打包)。 *

* 该命令会依次执行依赖解析、源码编译和产物打包阶段。 *

* *
- * 用法示例:
+ * 用法示例:
  * $ 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 命令: 编译当前项目。 * - *

工作模式说明:

+ *

工作模式说明:

*
    *
  • Cloud 模式 * - 项目根目录存在 {@code project.cloud} 时触发; * - 解析 build 区块,自动推导源码目录与输出文件名; - * - 用法:{@code snow compile [run]}
  • + * - 用法: {@code snow compile [run]} *
  • Local 模式 * - 未检测到 {@code project.cloud} 时回退; - * - 保持向后兼容:{@code snow compile [run] [-o ] [-d ] [file.snow …]}
  • + * - 保持向后兼容: {@code snow compile [run] [-o ] [-d ] [file.snow …]} *
* *

两种模式均将最终参数交由 {@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; * 各虚拟寄存器实际对应的物理寄存器或栈槽号。采用简单的线性扫描分配策略。 *

*

- * 分配过程如下: + * 分配过程如下: *

    *
  1. 优先为函数参数分配槽号,从 0 开始,按参数顺序递增。
  2. *
  3. 遍历函数体的每条指令,为尚未分配的目标寄存器及其操作数分配新的槽号。
  4. @@ -28,8 +28,8 @@ public final class RegisterAllocator { /** * 虚拟寄存器到槽号的分配映射表。 *

    - * 键:虚拟寄存器 {@link IRVirtualRegister}; - * 值:对应分配的槽编号 {@link Integer}。 + * 键: 虚拟寄存器 {@link IRVirtualRegister}; + * 值: 对应分配的槽编号 {@link Integer}。 *

    */ private final Map map = new HashMap<>(); @@ -37,7 +37,7 @@ public final class RegisterAllocator { /** * 为指定 IR 函数分配所有虚拟寄存器的槽号。 *

    - * 分配顺序说明: + * 分配顺序说明: *

      *
    1. 首先为所有参数分配槽号。
    2. *
    3. 然后线性遍历函数体,为每个指令涉及的虚拟寄存器(目标或操作数)分配槽号, 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 4bc2e11..8370e90 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 @@ -16,7 +16,7 @@ import java.util.stream.Collectors; * 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。 *

      *

      - * 工作流程简述: + * 工作流程简述: *

        *
      1. 接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。
      2. *
      3. 遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。
      4. @@ -28,8 +28,8 @@ public final class VMCodeGenerator { /** * 指令类型到生成器的注册表(调度表)。 *

        - * 键:IR 指令类型(Class对象), - * 值:对应的指令生成器实例。 + * 键: IR 指令类型(Class对象), + * 值: 对应的指令生成器实例。 *

        */ private final Map, InstructionGenerator> registry; diff --git a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java index c3b9be3..7ded37b 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java @@ -5,7 +5,7 @@ import org.jcnc.snow.vm.engine.VMOpCode; import java.util.*; /** - * VMProgramBuilder:构建线性 VM 程序(即按顺序存放所有 VM 指令)。 + * VMProgramBuilder: 构建线性 VM 程序(即按顺序存放所有 VM 指令)。 *

        * 本类用于编译器后端,将所有生成的 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` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。 -* **生成器调度**:`VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。 -* **程序构建与延迟修补**:`VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。 -* **操作码与常量映射**:`IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量,并根据值类型(I/L/F…)选择合适的 PUSH/STORE 操作码。 +* **线性扫描寄存器分配**: `RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。 +* **指令生成器体系**: `InstructionGenerator` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。 +* **生成器调度**: `VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。 +* **程序构建与延迟修补**: `VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。 +* **操作码与常量映射**: `IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量,并根据值类型(I/L/F…)选择合适的 PUSH/STORE 操作码。 ## 模块结构 @@ -51,6 +51,6 @@ backend/ * JDK 24 或更高版本 * Maven 构建管理 -* 推荐 IDE:IntelliJ IDEA +* 推荐 IDE: IntelliJ IDEA --- diff --git a/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java index 83c1747..497b8d1 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/generator/BinaryOpGenerator.java @@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger; * 并自动进行类型提升。 * 同时实现 "+0 → MOV" 的 Peephole 优化,避免多余的 PUSH/ADD 序列。 *

        - *

        类型提升优先级:D > F > L > I > S > B

        + *

        类型提升优先级: D > F > L > I > S > B

        */ public class BinaryOpGenerator implements InstructionGenerator { @@ -143,11 +143,11 @@ public class BinaryOpGenerator implements InstructionGenerator * * @param ins IR 条件比较跳转指令 - * @param out VMProgramBuilder:用于发出 VM 指令 + * @param out VMProgramBuilder: 用于发出 VM 指令 * @param slotMap 虚拟寄存器到 VM 槽位的映射表 * @param currentFn 当前处理的函数名(调试用,当前未使用) */ diff --git a/src/main/java/org/jcnc/snow/compiler/backend/utils/IROpCodeMapper.java b/src/main/java/org/jcnc/snow/compiler/backend/utils/IROpCodeMapper.java index 393e8a5..bb81d07 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/utils/IROpCodeMapper.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/utils/IROpCodeMapper.java @@ -20,8 +20,8 @@ public final class IROpCodeMapper { /** * IR 操作码到 VM 指令名的静态映射表。 *
          - *
        • 键:IR 操作码({@link IROpCode} 枚举项)
        • - *
        • 值:对应虚拟机指令名(字符串)
        • + *
        • 键: IR 操作码({@link IROpCode} 枚举项)
        • + *
        • 值: 对应虚拟机指令名(字符串)
        • *
        * 使用 {@link EnumMap},查找和存储高效。 */ diff --git a/src/main/java/org/jcnc/snow/compiler/backend/utils/TypePromoteUtils.java b/src/main/java/org/jcnc/snow/compiler/backend/utils/TypePromoteUtils.java index 207377e..b39ffb0 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/utils/TypePromoteUtils.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/utils/TypePromoteUtils.java @@ -1,25 +1,25 @@ package org.jcnc.snow.compiler.backend.utils; /** - * 工具类:提供基本数值类型的提升与类型转换辅助功能。 + * 工具类: 提供基本数值类型的提升与类型转换辅助功能。 *

        * 在进行数值类型运算、比较等操作时,低优先级的类型会被提升为高优先级类型参与运算。 * 例如 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生成阶段的核心工具。 *
        - * 主要职责包括: + * 主要职责包括: *

          *
        • 将数字字面量、标识符、二元表达式、函数调用等AST表达式节点,翻译为对应的IR指令序列
        • *
        • 管理并分配虚拟寄存器,保证IR操作的数据流正确
        • @@ -31,19 +31,19 @@ public record ExpressionBuilder(IRContext ctx) { /** * 构建并返回某个表达式节点对应的虚拟寄存器。 * - *

          会根据节点的实际类型分别处理: + *

          会根据节点的实际类型分别处理: *

            - *
          • 数字字面量:新建常量寄存器
          • - *
          • 布尔字面量:生成值为 0 或 1 的常量寄存器
          • - *
          • 标识符:查找当前作用域中的寄存器
          • - *
          • 二元表达式:递归处理子表达式并进行相应运算
          • - *
          • 一元运算符: + *
          • 数字字面量: 新建常量寄存器
          • + *
          • 布尔字面量: 生成值为 0 或 1 的常量寄存器
          • + *
          • 标识符: 查找当前作用域中的寄存器
          • + *
          • 二元表达式: 递归处理子表达式并进行相应运算
          • + *
          • 一元运算符: *
              *
            • -x(取负,生成 NEG_I32 指令)与
            • *
            • code>!x(逻辑非,转换为 x == 0 比较指令)
            • *
            *
          • - *
          • 函数调用:生成对应的Call指令
          • + *
          • 函数调用: 生成对应的Call指令
          • *
          • 其它类型不支持,抛出异常
          • *
          * diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java index c9f4fd5..56ffd3f 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java @@ -19,7 +19,7 @@ public class FunctionBuilder { /** * 将 AST 中的 FunctionNode 构建为可执行的 IRFunction。 *

          - * 构建过程包括: + * 构建过程包括: *

            *
          1. 初始化 IRFunction 实例和上下文
          2. *
          3. 根据函数返回类型,设置默认类型后缀,便于表达式推断
          4. @@ -37,7 +37,7 @@ public class FunctionBuilder { GlobalFunctionTable.register(functionNode.name(), functionNode.returnType()); - // 0) 基本初始化:创建 IRFunction 实例与对应上下文 + // 0) 基本初始化: 创建 IRFunction 实例与对应上下文 IRFunction irFunction = new IRFunction(functionNode.name()); IRContext irContext = new IRContext(irFunction); @@ -53,14 +53,14 @@ public class FunctionBuilder { ExpressionUtils.setDefaultSuffix(_returnSuffix); try { - // 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域 + // 2) 声明形参: 为每个参数分配虚拟寄存器并声明到作用域 for (ParameterNode p : functionNode.parameters()) { IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器 irContext.getScope().declare(p.name(), p.type(), reg); // 变量名→寄存器绑定 irFunction.addParameter(reg); // 添加到函数参数列表 } - // 3) 生成函数体 IR:遍历每条语句,逐一转化 + // 3) 生成函数体 IR: 遍历每条语句,逐一转化 StatementBuilder stmtBuilder = new StatementBuilder(irContext); for (StatementNode stmt : functionNode.body()) { stmtBuilder.build(stmt); diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java index 3cd5deb..209b4fa 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java @@ -9,7 +9,7 @@ import java.util.Map; /** * IRBuilderScope 用于管理单个函数内变量名与虚拟寄存器的映射关系。 * - *

            主要功能包括: + *

            主要功能包括: *

              *
            • 维护在当前作用域中已声明变量的寄存器分配信息;
            • *
            • 支持将已有虚拟寄存器与变量名重新绑定;
            • diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java index 26b8c0d..ca870c0 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java @@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; * 以及与之配套的作用域管理(IRBuilderScope), * 并简化虚拟寄存器分配与 IR 指令添加操作。 * - *

              本类提供以下核心功能: + *

              本类提供以下核心功能: *

                *
              • 持有并操作当前 IRFunction 对象;
              • *
              • 管理变量名与虚拟寄存器的映射关系;
              • @@ -62,7 +62,7 @@ public class IRContext { /** * 获取当前函数的变量与寄存器映射作用域。 * - *

                包内可见:仅限 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。 * - *

                主要职责: + *

                主要职责: *

                  *
                • 遍历输入的顶层节点,识别 ModuleNode、FunctionNode 及脚本式顶层 StatementNode;
                • *
                • 对 ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram;
                • @@ -36,13 +36,13 @@ public final class IRProgramBuilder { for (Node node : roots) { switch (node) { case ModuleNode moduleNode -> - // 模块节点:批量构建并添加模块内所有函数 + // 模块节点: 批量构建并添加模块内所有函数 moduleNode.functions().forEach(f -> irProgram.add(buildFunction(f))); case FunctionNode functionNode -> - // 顶层函数节点:直接构建并添加 + // 顶层函数节点: 直接构建并添加 irProgram.add(buildFunction(functionNode)); case StatementNode statementNode -> - // 脚本式顶层语句:封装为“_start”函数后构建并添加 + // 脚本式顶层语句: 封装为“_start”函数后构建并添加 irProgram.add(buildFunction(wrapTopLevel(statementNode))); default -> // 严格校验节点类型,遇不支持者立即失败 @@ -65,7 +65,7 @@ public final class IRProgramBuilder { /** * 将单个脚本式顶层 StatementNode 封装为名称固定的“_start”函数节点。 * - *

                  封装规则: + *

                  封装规则: *

                    *
                  • 函数名固定为“_start”;
                  • *
                  • 返回类型设为 null,由后续流程处理;
                  • diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java index 6c5881a..1c4dd8a 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java @@ -80,7 +80,7 @@ public class InstructionFactory { /** * Move 指令(src → dest)。若寄存器相同也安全。 *

                    - * 实现方式: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 { /** * 存储全局函数返回类型映射表。 *
                      - *
                    • Key:函数名(不含模块限定)
                    • - *
                    • Value:返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}
                    • + *
                    • Key: 函数名(不含模块限定)
                    • + *
                    • Value: 返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}
                    • *
                    */ private static final Map RETURN_TYPES = new ConcurrentHashMap<>(); diff --git a/src/main/java/org/jcnc/snow/compiler/ir/core/IRFunction.java b/src/main/java/org/jcnc/snow/compiler/ir/core/IRFunction.java index 74cbd08..2179e5a 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/core/IRFunction.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/core/IRFunction.java @@ -112,7 +112,7 @@ public class IRFunction { } /** - * 以IR代码表示,示例: + * 以IR代码表示,示例: *
                          * 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 值类型包括:

                    *
                      - *
                    • {@link IRVirtualRegister}:虚拟寄存器,表示计算结果或中间变量
                    • - *
                    • {@link IRConstant}:常量值,表示不可变的字面量或数值
                    • - *
                    • {@link IRLabel}:标签,表示跳转指令的目标地址
                    • + *
                    • {@link IRVirtualRegister}: 虚拟寄存器,表示计算结果或中间变量
                    • + *
                    • {@link IRConstant}: 常量值,表示不可变的字面量或数值
                    • + *
                    • {@link IRLabel}: 标签,表示跳转指令的目标地址
                    • *
                    * *

                    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} 方法,实现对指令的分发与处理。 - * 不同的访问者实现可用于执行不同任务,例如: + * 不同的访问者实现可用于执行不同任务,例如: *

                    *
                      - *
                    • {@code IRPrinter}:打印指令内容
                    • - *
                    • {@code IROptimizer}:分析与重写 IR 以优化性能
                    • - *
                    • {@code IRCodeGenerator}:生成平台相关的机器码或汇编代码
                    • + *
                    • {@code IRPrinter}: 打印指令内容
                    • + *
                    • {@code IROptimizer}: 分析与重写 IR 以优化性能
                    • + *
                    • {@code IRCodeGenerator}: 生成平台相关的机器码或汇编代码
                    • *
                    * *

                    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 operands() { List ops = new ArrayList<>(); diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java index f35cfa3..4df8d8d 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java @@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import java.util.List; /** - * IRAddInstruction —— 表示一个加法指令,形如:dest = lhs + rhs + * IRAddInstruction —— 表示一个加法指令,形如: dest = lhs + rhs *

                    * 本类是一个具体的 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 right ) jump targetLabel; *

                    * 其中 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 + * 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} 定义,目前常见的一元操作包括: *

                      - *
                    • NEG_I32 —— 整数取负:dest = -val
                    • + *
                    • NEG_I32 —— 整数取负: dest = -val
                    • *
                    • (可扩展)逻辑非、按位非等
                    • *
                    */ @@ -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 指令。 *

                    * - * 类型判定支持: + * 类型判定支持: *
                      - *
                    • 字面量后缀:支持 B/S/I/L/F/D(大小写均可)
                    • - *
                    • 浮点数支持:如无后缀但有小数点,视为 double
                    • - *
                    • 变量类型:根据传入变量表推断类型,未识别则默认 int
                    • + *
                    • 字面量后缀: 支持 B/S/I/L/F/D(大小写均可)
                    • + *
                    • 浮点数支持: 如无后缀但有小数点,视为 double
                    • + *
                    • 变量类型: 根据传入变量表推断类型,未识别则默认 int
                    • *
                    */ 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; /** * 表达式分析与操作符选择工具类。 *

                    - * 主要功能: + * 主要功能: * - 解析字面量常量,自动推断类型 * - 自动匹配并选择适合的算术/比较操作码 * - 表达式类型的合并与类型提升 @@ -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)形式的核心。 * 每个虚拟寄存器在程序中只被赋值一次,其值来源于一条明确的指令输出。 *

                    - * 特点: + * 特点: *

                      *
                    • 每个寄存器有唯一编号 {@code id},由 {@code IRFunction.newRegister()} 自动生成
                    • *
                    • 实现 {@link IRValue} 接口,可作为 IRInstruction 的操作数
                    • - *
                    • 具备良好的打印与调试格式:%id
                    • + *
                    • 具备良好的打印与调试格式: %id
                    • *
                    * * 适用于表达式求值、参数传递、函数返回值、临时变量等所有中间值场景。 @@ -23,7 +23,7 @@ public record IRVirtualRegister(int id) implements IRValue { /** * 将虚拟寄存器转换为字符串格式,方便输出和调试。 - * 格式为:%,例如 %3 表示编号为 3 的虚拟寄存器。 + * 格式为: %,例如 %3 表示编号为 3 的虚拟寄存器。 * * @return 格式化的字符串表示 */ diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java index 4462fca..70cf64e 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java @@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.lexer.base.TokenScanner; * 是 {@link TokenScanner} 实现进行词法识别的基础设施。 *

                    *

                    - * 设计要点: + * 设计要点: *

                      *
                    • 构造时统一将 Windows 换行符 (\r\n) 转换为 Unix 风格 (\n)。
                    • *
                    • 所有坐标均以 1 为起始行/列号,更贴合人类直觉。
                    • 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 ff31df7..5343ebe 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 @@ -12,7 +12,7 @@ import java.util.List; /** * Snow 语言词法分析器核心实现。 - *

                      采用“先扫描 → 后批量校验 → 统一报告”策略: + *

                      采用“先扫描 → 后批量校验 → 统一报告”策略: *

                        *
                      1. {@link #scanAllTokens()}— 用扫描器链把字符流拆成 {@link Token}
                      2. *
                      3. {@link #validateTokens()}— 基于 token 序列做轻量上下文校验
                      4. @@ -68,7 +68,7 @@ public class LexerEngine { System.out.println("\n## 词法分析通过,没有发现错误\n"); return; } - System.err.println("\n词法分析发现 " + errors.size() + " 个错误:"); + System.err.println("\n词法分析发现 " + errors.size() + " 个错误: "); errors.forEach(e -> System.err.println(" " + e)); } @@ -76,7 +76,7 @@ public class LexerEngine { public List getErrors() { return List.copyOf(errors); } /** - * 逐字符扫描:依次尝试各扫描器;扫描器抛出的 + * 逐字符扫描: 依次尝试各扫描器;扫描器抛出的 * {@link LexicalException} 被捕获并转为 {@link LexicalError}。 */ private void scanAllTokens() { @@ -105,7 +105,7 @@ public class LexerEngine { } /** - * 目前包含三条规则:
                        + * 目前包含三条规则:
                        * 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; *
                      5. 完全禁止 Java 堆栈信息输出,使命令行输出保持整洁。
                      6. *
                    *
                    - * 例:
                    - *     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 { } /** - * 抽象方法:由子类实现具体的扫描逻辑。 + * 抽象方法: 由子类实现具体的扫描逻辑。 *

                    * 实现应消费一定字符并根据规则构造 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:

                    *
                      - *
                    1. 单行注释:以 {@code //} 开头,直至行尾或文件末尾。
                    2. - *
                    3. 多行注释:以 {@code /*} 开头,以 */ 结束,可跨多行。
                    4. + *
                    5. 单行注释: 以 {@code //} 开头,直至行尾或文件末尾。
                    6. + *
                    7. 多行注释: 以 {@code /*} 开头,以 */ 结束,可跨多行。
                    8. *
                    * - *

                    本扫描器遵循“发现即捕获”原则:注释文本被完整保留在 Token 中,供后续的文档提取、源映射等分析使用。

                    + *

                    本扫描器遵循“发现即捕获”原则: 注释文本被完整保留在 Token 中,供后续的文档提取、源映射等分析使用。

                    * *

                    错误处理策略

                    *
                      - *
                    • 未终止的多行注释:若文件结束时仍未遇到 */,抛出 {@link LexicalException}。
                    • + *
                    • 未终止的多行注释: 若文件结束时仍未遇到 */,抛出 {@link LexicalException}。
                    • *
                    */ 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} —— 标识符扫描器,负责识别源代码中的标识符(如变量名、函数名等)。 * - *

                    标识符的识别遵循以下规则:

                    + *

                    标识符的识别遵循以下规则:

                    *
                      *
                    • 标识符必须以字母(A-Z,a-z)或下划线(_)开头。
                    • *
                    • 标识符的后续字符可以是字母、数字(0-9)或下划线。
                    • 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 0f63e70..6964dfd 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 @@ -5,7 +5,7 @@ import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.lexer.token.TokenType; /** - * 换行符扫描器:将源代码中的换行符(\n)识别为 {@code NEWLINE} 类型的 Token。 + * 换行符扫描器: 将源代码中的换行符(\n)识别为 {@code NEWLINE} 类型的 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,当前支持: *

                        *
                      1. 十进制整数(如 0,42,123456)
                      2. *
                      3. 十进制小数(如 3.14,0.5)
                      4. @@ -18,7 +18,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; * 如果后续需要支持科学计数法、下划线分隔符、不同进制等,只需扩展现有状态机的转移规则。 * *
                        - * 状态机简述:
                        + * 状态机简述: 
                          *   INT_PART   --'.'-->  DEC_POINT
                          *      |                 |
                          *      |                 v
                        @@ -27,28 +27,28 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
                          *      v
                          *   DEC_POINT  --digit--> FRAC_PART
                          * 
                        - * 状态说明: + * 状态说明: *
                          - *
                        • INT_PART :读取整数部分,遇到 '.' 进入 DEC_POINT,否则结束。
                        • - *
                        • DEC_POINT :已读到小数点,必须下一个字符是数字,否则报错。
                        • - *
                        • FRAC_PART :读取小数部分,遇非法字符则结束主体。
                        • - *
                        • END :主体扫描结束,进入后缀/尾随字符判定。
                        • + *
                        • INT_PART : 读取整数部分,遇到 '.' 进入 DEC_POINT,否则结束。
                        • + *
                        • DEC_POINT : 已读到小数点,必须下一个字符是数字,否则报错。
                        • + *
                        • FRAC_PART : 读取小数部分,遇非法字符则结束主体。
                        • + *
                        • END : 主体扫描结束,进入后缀/尾随字符判定。
                        • *
                        * - * 错误处理策略: + * 错误处理策略: *
                          *
                        1. 数字后跟未知字母(如 42X)—— 抛出 LexicalException
                        2. *
                        3. 数字与合法后缀间有空白(如 3 L)—— 抛出 LexicalException
                        4. *
                        5. 小数点后缺失数字(如 1.)—— 抛出 LexicalException
                        6. *
                        * - * 支持的单字符类型后缀包括:b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set。 + * 支持的单字符类型后缀包括: b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set。 */ public class NumberTokenScanner extends AbstractTokenScanner { /** * 支持的单字符类型后缀集合。 - * 包含:b, s, l, f, d 及其大写形式。 + * 包含: b, s, l, f, d 及其大写形式。 * 对于多字符后缀,可扩展为 Set 并在扫描尾部做贪婪匹配。 */ private static final String SUFFIX_CHARS = "bslfdBSLFD"; 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 951b1c5..58bb1a9 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 @@ -8,14 +8,14 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; * 运算符扫描器(OperatorTokenScanner) * *

                        负责在词法分析阶段识别由 = ! < > | & % 等字符 - * 起始的单字符或双字符运算符,并生成相应 {@link Token}:

                        + * 起始的单字符或双字符运算符,并生成相应 {@link Token}:

                        * *
                          - *
                        • 赋值 / 比较:{@code =}, {@code ==}, {@code !=}
                        • - *
                        • 关系运算:{@code >}, {@code >=}, {@code <}, {@code <=}
                        • - *
                        • 逻辑运算:{@code &&}, {@code ||}
                        • - *
                        • 取模运算:{@code %}
                        • - *
                        • 逻辑非:{@code !}
                        • + *
                        • 赋值 / 比较: {@code =}, {@code ==}, {@code !=}
                        • + *
                        • 关系运算: {@code >}, {@code >=}, {@code <}, {@code <=}
                        • + *
                        • 逻辑运算: {@code &&}, {@code ||}
                        • + *
                        • 取模运算: {@code %}
                        • + *
                        • 逻辑非: {@code !}
                        • *
                        * *

                        如果无法匹配到合法组合,将返回 {@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; /** - * 字符串扫描器:处理双引号包裹的字符串字面量,支持基本的转义字符。 + * 字符串扫描器: 处理双引号包裹的字符串字面量,支持基本的转义字符。 *

                        - * 支持格式示例: + * 支持格式示例: *

                          *
                        • "hello"
                        • *
                        • "line\\nbreak"
                        • diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java index 8e4eedd..2085fef 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java @@ -5,13 +5,13 @@ 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; *

                          * *

                          - * 主要功能与特性: + * 主要功能与特性: *

                            *
                          • 统一管理语言关键字和类型名集合,便于扩展与维护。
                          • *
                          • 自动推断 Token 类型,无需外部干预。
                          • @@ -35,7 +35,7 @@ public class TokenFactory { /** * 创建一个根据内容自动推断类型的 {@link Token} 实例。 *

                            - * 优先级顺序为:类型(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 节点,记录运算符与操作数。
                            • *
                      * - *

                      此类仅负责语法结构的构建: + *

                      此类仅负责语法结构的构建: *

                        *
                      • 类型正确性在 {@code UnaryExpressionAnalyzer} 中校验;
                      • *
                      • IR 生成在 {@code ExpressionBuilder.buildUnary} 中完成。
                      • diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java index bbf15ed..fd388fd 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java @@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; * 构建一个有效的 {@link ExpressionNode} 抽象语法树结构。 *

                        *

                        - * 不同的实现可以采用不同的解析技术: + * 不同的实现可以采用不同的解析技术: *

                          *
                        • 递归下降(Recursive Descent)
                        • *
                        • Pratt Parser(前缀/中缀优先级驱动)
                        • diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java index c886a83..7ced99b 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java @@ -11,7 +11,7 @@ import org.jcnc.snow.compiler.parser.expression.Precedence; * 是 Pratt 解析器架构中处理中缀操作的关键组件。 *

                          *

                          - * 每个中缀解析器负责: + * 每个中缀解析器负责: *

                            *
                          • 根据左侧已解析的表达式,结合当前运算符继续解析右侧部分
                          • *
                          • 提供运算符优先级,用于判断是否继续嵌套解析
                          • diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java index 426a62f..0864eda 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java @@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.lexer.token.Token; * {@code PrefixParselet} 是用于解析前缀表达式的通用接口。 *

                            * 前缀表达式是以某个词法单元(Token)作为起始的表达式结构, - * 常见类型包括: + * 常见类型包括: *

                              *
                            • 数字字面量(如 {@code 42})
                            • *
                            • 标识符(如 {@code foo})
                            • diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java index d3b4578..06be40a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java @@ -18,7 +18,7 @@ import java.util.HashMap; */ public class StatementParserFactory { - /** 注册表:语句关键字 -> 对应语句解析器 */ + /** 注册表: 语句关键字 -> 对应语句解析器 */ private static final Map registry = new HashMap<>(); static { @@ -28,7 +28,7 @@ public class StatementParserFactory { registry.put("loop", new LoopStatementParser()); registry.put("return", new ReturnStatementParser()); - // 默认处理器:表达式语句 + // 默认处理器: 表达式语句 registry.put("", new ExpressionStatementParser()); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java index 82c486f..eb838be 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java @@ -18,7 +18,7 @@ public class TopLevelParserFactory { /** 关键字 → 解析器注册表 */ private static final Map registry = new HashMap<>(); - /** 缺省解析器:脚本模式(单条语句可执行) */ + /** 缺省解析器: 脚本模式(单条语句可执行) */ private static final TopLevelParser DEFAULT = new ScriptTopLevelParser(); static { diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java index 17597c0..39d928a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java @@ -22,7 +22,7 @@ import java.util.*; * 实现 {@link TopLevelParser} 接口,用于将源代码中的函数块解析为抽象语法树(AST)中的 {@link FunctionNode}。 * *

                              - * 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分: + * 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分: *

                              * *
                                @@ -110,7 +110,7 @@ public class FunctionParser implements TopLevelParser { * 构造函数定义中各区块的解析规则(parameter、return_type、body)。 * *

                                - * 每个 {@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 语句,并返回表示被导入模块的语法树节点列表。 *

                                - * 该方法会依次执行以下操作: + * 该方法会依次执行以下操作: *

                                  *
                                1. 确认当前语句以关键字 {@code import} 开头。
                                2. *
                                3. 确认后跟一个冒号 {@code :}。
                                4. 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} 语法树节点。
                                        * 

                                  - * 解析过程包括: + * 解析过程包括: *

                                    *
                                  1. 匹配模块声明起始 {@code module: IDENTIFIER}。
                                  2. *
                                  3. 收集模块体内所有 import 和 function 语句,允许穿插空行。
                                  4. 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}。 *

                                      - * 解析流程如下: + * 解析流程如下: *

                                        *
                                      1. 匹配关键字 {@code declare};
                                      2. *
                                      3. 读取变量名称(标识符类型);
                                      4. 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} 抽象语法树节点。
                                                  * 

                                            - * 解析逻辑如下: + * 解析逻辑如下: *

                                              *
                                            1. 匹配起始关键字 {@code return}。
                                            2. *
                                            3. 判断其后是否为 {@code NEWLINE},若否则表示存在返回值表达式。
                                            4. 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 标准的字符串
                                                  • *
                                                  *

                                                  * - * 设计要点: + * 设计要点: *
                                                    *
                                                  1. 仅提供静态方法入口,无状态,线程安全
                                                  2. *
                                                  3. 解析器内部采用 char[] 缓冲区,支持高性能处理
                                                  4. 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} 用于对数字字面量表达式进行语义分析并推断其精确类型。 *

                                                                - * 类型判定逻辑如下: + * 类型判定逻辑如下: *

                                                                  - *
                                                                1. 首先检查字面量末尾是否带有类型后缀(不区分大小写): + *
                                                                2. 首先检查字面量末尾是否带有类型后缀(不区分大小写): *
                                                                    - *
                                                                  • {@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})
                                                                  • *
                                                                  *
                                                                3. - *
                                                                4. 若无后缀,则: + *
                                                                5. 若无后缀,则: *
                                                                    *
                                                                  • 只要文本中包含 {@code '.'} 或 {@code e/E},即判为 double 类型
                                                                  • *
                                                                  • 否则默认判为 int 类型
                                                                  • @@ -37,7 +37,7 @@ public class NumberLiteralAnalyzer implements ExpressionAnalyzer - * 分析流程: + * 分析流程: *
                                                                      *
                                                                    1. 若字面量以后缀结尾,直接按后缀映射类型。
                                                                    2. *
                                                                    3. 否则,若含有小数点或科学计数法标记,则为 double,否则为 int。
                                                                    4. 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} 类型。
                                                                        • *
                                                                        * - *

                                                                        分析流程: + *

                                                                        分析流程: *

                                                                          *
                                                                        1. 递归分析操作数表达式,获取其类型 {@code operandType}。
                                                                        2. - *
                                                                        3. 根据运算符检查类型合法性: + *
                                                                        4. 根据运算符检查类型合法性: *
                                                                            *
                                                                          • 若类型不符,记录 {@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) { /** * 执行函数体检查流程。 *

                                                                                          - * 对所有模块中的所有函数依次进行处理: + * 对所有模块中的所有函数依次进行处理: *

                                                                                            *
                                                                                          1. 查找模块对应的 {@link ModuleInfo};
                                                                                          2. *
                                                                                          3. 创建函数局部符号表 {@link SymbolTable},并注册所有参数变量;
                                                                                          4. 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}。 *

                                                                                              - * 语义分析流程分为三个阶段: + * 语义分析流程分为三个阶段: *

                                                                                                - *
                                                                                              1. 模块注册:将所有用户模块的名称添加至全局模块表中,供后续导入检查与引用;
                                                                                              2. - *
                                                                                              3. 函数签名注册:提取函数定义的签名(名称与类型),填入每个模块对应的 {@link ModuleInfo};
                                                                                              4. - *
                                                                                              5. 函数体检查:遍历每个函数体,对所有语句与表达式执行类型检查和语义验证。
                                                                                              6. + *
                                                                                              7. 模块注册: 将所有用户模块的名称添加至全局模块表中,供后续导入检查与引用;
                                                                                              8. + *
                                                                                              9. 函数签名注册: 提取函数定义的签名(名称与类型),填入每个模块对应的 {@link ModuleInfo};
                                                                                              10. + *
                                                                                              11. 函数体检查: 遍历每个函数体,对所有语句与表达式执行类型检查和语义验证。
                                                                                              12. *
                                                                                              *

                                                                                              - * 内部使用组件: + * 内部使用组件: *

                                                                                                - *
                                                                                              • {@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 { /** * 根据名称解析符号,支持作用域链向上递归查找。 - *

                                                                                                    查找策略: + *

                                                                                                    查找策略: *

                                                                                                      *
                                                                                                    1. 优先在当前作用域中查找该符号名称;
                                                                                                    2. *
                                                                                                    3. 若未找到且存在父作用域,则递归向上查找;
                                                                                                    4. 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,当前支持: *

                                                                                                                    *
                                                                                                                  1. 十进制整数(如 0,42,123456)
                                                                                                                  2. *
                                                                                                                  3. 十进制小数(如 3.14,0.5)
                                                                                                                  4. *
                                                                                                                  5. 单字符类型后缀(如 2.0f,255B,合法集合见 SUFFIX_CHARS)
                                                                                                                  6. *
                                                                                                                  - * + *

                                                                                                                  * 如果后续需要支持科学计数法、下划线分隔符、不同进制等,只需扩展现有状态机的转移规则。 * *

                                                                                                                  - * 状态机简述: 
                                                                                                                  + * 状态机简述:
                                                                                                                    *   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 : 主体扫描结束,进入后缀/尾随字符判定。
                                                                                                                  • *
                                                                                                                  - * - * 错误处理策略: + *

                                                                                                                  + * 错误处理策略: *

                                                                                                                    *
                                                                                                                  1. 数字后跟未知字母(如 42X)—— 抛出 LexicalException
                                                                                                                  2. *
                                                                                                                  3. 数字与合法后缀间有空白(如 3 L)—— 抛出 LexicalException
                                                                                                                  4. *
                                                                                                                  5. 小数点后缺失数字(如 1.)—— 抛出 LexicalException
                                                                                                                  6. *
                                                                                                                  - * + *

                                                                                                                  * 支持的单字符类型后缀包括: 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:

                                                                                                              + *
                                                                                                                + *
                                                                                                              1. Parses the system call identifier from the instruction parameters.
                                                                                                              2. + *
                                                                                                              3. Invokes the corresponding system-level function or service based on the system call identifier.
                                                                                                              4. + *
                                                                                                              5. Returns the result of the system call operation.
                                                                                                              6. + */ 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; *
                                                                                                              7. 小数点后缺失数字(如 1.)—— 抛出 LexicalException
                                                                                                              8. *
                                                                                                              *

                                                                                                              - * 支持的单字符类型后缀包括: 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:

                                                                                                                    + *
                                                                                                                      + *
                                                                                                                    1. Parses the object reference literal (e.g., a string) from the instruction parameters.
                                                                                                                    2. + *
                                                                                                                    3. Creates or interprets the reference as an object instance if necessary.
                                                                                                                    4. + *
                                                                                                                    5. Pushes the reference object onto the operand stack.
                                                                                                                    6. + *
                                                                                                                    7. Increments the program counter (PC) to proceed with the next sequential instruction.
                                                                                                                    8. + *
                                                                                                                    + * + *

                                                                                                                    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:

                                                                                                                    + *
                                                                                                                      + *
                                                                                                                    1. Parses the target slot index from the instruction parameters.
                                                                                                                    2. + *
                                                                                                                    3. Retrieves the reference object stored at the specified slot in the local variable table + * of the current stack frame.
                                                                                                                    4. + *
                                                                                                                    5. Pushes the retrieved reference onto the operand stack.
                                                                                                                    6. + *
                                                                                                                    7. Increments the program counter (PC) to proceed with the next sequential instruction.
                                                                                                                    8. + *
                                                                                                                    + * + *

                                                                                                                    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:

                                                                                                                    + *
                                                                                                                      + *
                                                                                                                    1. Parses the target slot index from the instruction parameters.
                                                                                                                    2. + *
                                                                                                                    3. Pops the top reference object from the operand stack.
                                                                                                                    4. + *
                                                                                                                    5. Stores the popped reference object into the specified slot in the local variable table + * of the current stack frame.
                                                                                                                    6. + *
                                                                                                                    7. Increments the program counter (PC) to proceed with the next sequential instruction.
                                                                                                                    8. + *
                                                                                                                    + * + *

                                                                                                                    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} 子类完成实际生成。 *

                                                                                                                    *

                                                                                                                    - * 工作流程简述: + * 工作流程简述: *

                                                                                                                      *
                                                                                                                    1. 接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。
                                                                                                                    2. *
                                                                                                                    3. 遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。
                                                                                                                    4. @@ -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/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 @@