!43 release: 合并 v0.5.0 版本至 main 分支

Merge pull request !43 from Luke/release/v0.5.0
This commit is contained in:
Luke 2025-07-24 14:33:19 +00:00 committed by Gitee
commit 9a4ebaadce
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
205 changed files with 3272 additions and 1403 deletions

View File

@ -69,7 +69,7 @@ body:
attributes: attributes:
label: 软件版本/分支 label: 软件版本/分支
options: options:
- v0.4.2 - v0.5.0
- main - main
- dev - dev
- 其他 - 其他

View File

@ -11,7 +11,7 @@ body:
attributes: attributes:
label: 任务标题 label: 任务标题
description: 简要描述维护内容 description: 简要描述维护内容
placeholder: "如升级 JDK 版本" placeholder: "如: 升级 JDK 版本"
validations: validations:
required: true required: true
@ -20,6 +20,6 @@ body:
attributes: attributes:
label: 任务详情 label: 任务详情
description: 描述执行步骤或相关脚本命令 description: 描述执行步骤或相关脚本命令
placeholder: "如修改 pom.xml…" placeholder: "如: 修改 pom.xml…"
validations: validations:
required: false required: false

View File

@ -20,7 +20,7 @@ body:
attributes: attributes:
label: 优化方案 label: 优化方案
description: 详细描述改进思路与实现方式 description: 详细描述改进思路与实现方式
placeholder: "如缓存机制、算法优化…" placeholder: "如: 缓存机制、算法优化…"
validations: validations:
required: true required: true
@ -29,6 +29,6 @@ body:
attributes: attributes:
label: 预期收益 label: 预期收益
description: 描述优化后带来的效益或体验提升 description: 描述优化后带来的效益或体验提升
placeholder: "如响应时间缩短 30%…" placeholder: "如: 响应时间缩短 30%…"
validations: validations:
required: false required: false

View File

@ -32,6 +32,6 @@ body:
attributes: attributes:
label: 修复截止日期 label: 修复截止日期
description: 填写计划完成的日期 (YYYY-MM-DD) description: 填写计划完成的日期 (YYYY-MM-DD)
placeholder: "例如2025-06-20" placeholder: "例如: 2025-06-20"
validations: validations:
required: false required: false

View File

@ -20,7 +20,7 @@ body:
attributes: attributes:
label: 已尝试方法 label: 已尝试方法
description: 列出已尝试过的解决方案或思路 description: 列出已尝试过的解决方案或思路
placeholder: "如查阅文档、尝试示例代码…" placeholder: "如: 查阅文档、尝试示例代码…"
validations: validations:
required: false required: false
@ -29,6 +29,6 @@ body:
attributes: attributes:
label: 期望答案 label: 期望答案
description: 描述希望获得的解答或帮助方向 description: 描述希望获得的解答或帮助方向
placeholder: "如最佳实践、配置示例…" placeholder: "如: 最佳实践、配置示例…"
validations: validations:
required: false required: false

View File

@ -20,7 +20,7 @@ body:
attributes: attributes:
label: 重构原因 label: 重构原因
description: 说明当前存在的痛点或待改进之处 description: 说明当前存在的痛点或待改进之处
placeholder: "如变量命名不规范、函数职责过多…" placeholder: "如: 变量命名不规范、函数职责过多…"
validations: validations:
required: true required: true
@ -29,6 +29,6 @@ body:
attributes: attributes:
label: 预期效果 label: 预期效果
description: 说明重构后带来的好处或验证方式 description: 说明重构后带来的好处或验证方式
placeholder: "如提高性能、增强可读性…" placeholder: "如: 提高性能、增强可读性…"
validations: validations:
required: false required: false

View File

@ -3,14 +3,14 @@
https://gitee.com/jcnc-org/snow/blob/main/doc/Git-Management/Git-Management.md https://gitee.com/jcnc-org/snow/blob/main/doc/Git-Management/Git-Management.md
提交 PR 后,请根据实际情况删除不适用的项。 提交 PR 后,请根据实际情况删除不适用的项。
1. 请在右侧面板中 1. 请在右侧面板中:
- 关联 Issue - 关联 Issue
- 选择 PR 类型bug 修复 / 新功能 / 文档 / 优化 等) - 选择 PR 类型bug 修复 / 新功能 / 文档 / 优化 等)
- 添加必要的标签和审查人 - 添加必要的标签和审查人
- 请添加里程碑 - 请添加里程碑
- 如必要请设置优先级 - 如必要请设置优先级
2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如 2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如:
- [x] 已阅读并遵守项目规范 - [x] 已阅读并遵守项目规范
- [ ] 本地通过所有测试 - [ ] 本地通过所有测试
- [ ] 文档已更新(如有必要) - [ ] 文档已更新(如有必要)

1
.gitignore vendored
View File

@ -40,3 +40,4 @@ target/
### Snow 虚拟机指令 ### ### Snow 虚拟机指令 ###
*.water *.water
/.lingma/

View File

@ -4,12 +4,6 @@
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/BugFarm/Bug1 -o target/Bug1" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/BugFarm/Bug1 -o target/Bug1" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo1 -o target/Demo1" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo1 -o target/Demo1 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo10 -o target/Demo10" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo10 -o target/Demo10 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo12 -o target/Demo12" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo12 -o target/Demo12 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -2,7 +2,7 @@
<configuration default="false" name="Demo13" type="Application" factoryName="Application" folderName="Demo"> <configuration default="false" name="Demo13" type="Application" factoryName="Application" folderName="Demo">
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo13 -o target/Demo13" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo13 -o target/Demo13 -debug" />
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

10
.run/Demo14.run.xml Normal file
View File

@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Demo14" type="Application" factoryName="Application" folderName="Demo">
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo14 -o target/Demo14 -debug" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo2 -o target/Demo2" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo2 -o target/Demo2 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo3 -o target/Demo3" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo3 -o target/Demo3 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo4 -o target/Demo4" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo4 -o target/Demo4 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo5 -o target/Demo5" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo5 -o target/Demo5 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo6 -o target/Demo6" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo6 -o target/Demo6 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo7 -o target/Demo7" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo7 -o target/Demo7 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo8 -o target/Demo8" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo8 -o target/Demo8 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,13 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" /> <option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo9 -o target/Demo9" /> <option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo9 -o target/Demo9 -debug" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,12 +3,6 @@
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="--help" /> <option name="PROGRAM_PARAMETERS" value="--help" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.cli.SnowCLI" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

15
.run/Snow.run.xml Normal file
View File

@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Snow" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.cli.SnowCLI" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -3,12 +3,6 @@
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" /> <option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" /> <module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="--version" /> <option name="PROGRAM_PARAMETERS" value="--version" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.jcnc.snow.cli.SnowCLI" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2"> <method v="2">
<option name="Make" enabled="true" /> <option name="Make" enabled="true" />
</method> </method>

View File

@ -3,7 +3,6 @@
<toRun name="Demo1" type="Application" /> <toRun name="Demo1" type="Application" />
<toRun name="Demo10" type="Application" /> <toRun name="Demo10" type="Application" />
<toRun name="Demo11" type="Application" /> <toRun name="Demo11" type="Application" />
<toRun name="Demo11" type="Application" />
<toRun name="Demo12" type="Application" /> <toRun name="Demo12" type="Application" />
<toRun name="Demo13" type="Application" /> <toRun name="Demo13" type="Application" />
<toRun name="Demo2" type="Application" /> <toRun name="Demo2" type="Application" />

292
README.md
View File

@ -11,8 +11,8 @@
<a href="https://gitee.com/jcnc-org/snow/blob/main/LICENSE"> <a href="https://gitee.com/jcnc-org/snow/blob/main/LICENSE">
<img src="https://img.shields.io/badge/%20license-Apache--2.0%20-blue" alt=""> <img src="https://img.shields.io/badge/%20license-Apache--2.0%20-blue" alt="">
</a> </a>
<a href="https://gitee.com/jcnc-org/snow/tree/v0.4.2/"> <a href="https://gitee.com/jcnc-org/snow/tree/v0.5.0/">
<img src="https://img.shields.io/badge/version-v0.4.2-blue" alt=""> <img src="https://img.shields.io/badge/version-v0.5.0-blue" alt="">
</a> </a>
</p> </p>
@ -53,12 +53,12 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
| 类别 | 关键特性 | | 类别 | 关键特性 |
|----------|---------------------------------------------------------------------------------------------------| |----------|---------------------------------------------------------------------------------------------------|
| 语言层 | `module` / `import` / `function` / `loop` / `ifelse` / Pratt 表达式解析<br>静态类型检查 & 作用域分析 | | 语言层 | module / import / function / loop / ifelse / Pratt 表达式解析<br>静态类型检查 & 作用域分析 |
| 编译器前端 | **Lexer / Parser / Semantic Analyzer** 全栈自研,生成 JSON-AST | | 编译器前端 | Lexer / Parser / Semantic Analyzer 全栈自研,生成 JSON-AST |
| IR & 后端 | 三地址式 IR ➜ 线性扫描寄存器分配 ➜ SnowVM 指令 | | IR & 后端 | 三地址式 IR ➜ 线性扫描寄存器分配 ➜ SnowVM 指令 |
| 虚拟机 | 栈 + 寄存器混合架构、GUI 局部变量监视 | | 虚拟机 | 栈 + 寄存器混合架构、GUI 局部变量监视 |
| snow pkg | - `.cloud` DSL 描述项目、依赖与构建<br>- 预设 `clean / compile / run / package / publish` 任务<br>- 离线缓存与远程仓库解析 | | snow pkg | - `.cloud` DSL 描述项目、依赖与构建<br>- 预设 `clean / compile / run / package / publish` 任务<br>- 离线缓存与远程仓库解析 |
| CLI | `snow init`, `snow compile`, `snow run`, `snow clean`, `snow build`, `snow generate` | | CLI | init, compile, run, clean, build, generate,debug |
## Snow-Lang 官网 ## Snow-Lang 官网
@ -69,7 +69,10 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
[https://gitee.com/jcnc-org/snow/releases](https://gitee.com/jcnc-org/snow/releases) [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) [Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
@ -83,11 +86,11 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
## 开发环境安装 ## 开发环境安装
1. **开发环境准备** 1. **开发环境准备**:
1. 安装集成开发环境 [IntelliJ IDEA](https://www.jetbrains.com/idea/download) 1. 安装集成开发环境 [IntelliJ IDEA](https://www.jetbrains.com/idea/download)
2. 安装 Java 开发工具 [Graalvm-jdk-24](https://www.graalvm.org/downloads/) 2. 安装 Java 开发工具 [Graalvm-jdk-24](https://www.graalvm.org/downloads/)
2. **获取源码** 2. **获取源码**:
将项目源码下载或克隆到本地目录。 将项目源码下载或克隆到本地目录。
```bash ```bash
git clone https://gitee.com/jcnc-org/snow.git git clone https://gitee.com/jcnc-org/snow.git
@ -115,6 +118,59 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
end body end body
end function end function
end module end module
line col type lexeme
----------------------------------------------------
1 1 KEYWORD module
1 7 COLON :
1 9 IDENTIFIER Main
1 13 NEWLINE \n
2 5 KEYWORD import
2 11 COLON :
2 12 IDENTIFIER Math
2 16 NEWLINE \n
3 5 KEYWORD function
3 13 COLON :
3 15 IDENTIFIER main
3 19 NEWLINE \n
4 9 KEYWORD return_type
4 20 COLON :
4 22 TYPE int
4 25 NEWLINE \n
5 9 KEYWORD body
5 13 COLON :
5 14 NEWLINE \n
6 13 IDENTIFIER Math
6 17 DOT .
6 18 IDENTIFIER add
6 21 LPAREN (
6 22 NUMBER_LITERAL 6
6 23 COMMA ,
6 24 NUMBER_LITERAL 1
6 25 RPAREN )
6 26 NEWLINE \n
7 13 KEYWORD return
7 20 NUMBER_LITERAL 0
7 21 NEWLINE \n
8 9 KEYWORD end
8 13 KEYWORD body
8 17 NEWLINE \n
9 5 KEYWORD end
9 9 KEYWORD function
9 17 NEWLINE \n
10 1 KEYWORD end
10 5 KEYWORD module
10 1 EOF
## 词法分析通过,没有发现错误
#### Math.snow #### Math.snow
module: Math module: Math
function: add function: add
@ -127,6 +183,65 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
end body end body
end function end function
end module end module
line col type lexeme
----------------------------------------------------
1 1 KEYWORD module
1 7 COLON :
1 9 IDENTIFIER Math
1 13 NEWLINE \n
2 5 KEYWORD function
2 13 COLON :
2 15 IDENTIFIER add
2 18 NEWLINE \n
3 9 KEYWORD parameter
3 18 COLON :
3 19 NEWLINE \n
4 13 KEYWORD declare
4 21 IDENTIFIER n1
4 23 COLON :
4 25 TYPE int
4 28 NEWLINE \n
5 13 KEYWORD declare
5 21 IDENTIFIER n2
5 23 COLON :
5 25 TYPE int
5 28 NEWLINE \n
6 9 KEYWORD return_type
6 20 COLON :
6 22 TYPE int
6 25 NEWLINE \n
7 9 KEYWORD body
7 13 COLON :
7 14 NEWLINE \n
8 12 KEYWORD return
8 19 IDENTIFIER n1
8 22 PLUS +
8 24 IDENTIFIER n2
8 26 NEWLINE \n
9 9 KEYWORD end
9 13 KEYWORD body
9 17 NEWLINE \n
10 5 KEYWORD end
10 9 KEYWORD function
10 17 NEWLINE \n
11 1 KEYWORD end
11 5 KEYWORD module
11 1 EOF
## 词法分析通过,没有发现错误
## 语义分析通过,没有发现错误
### AST ### AST
[ [
{ {
@ -134,8 +249,8 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
"name": "Main", "name": "Main",
"imports": [ "imports": [
{ {
"module": "Math", "type": "Import",
"type": "Import" "module": "Math"
} }
], ],
"functions": [ "functions": [
@ -237,7 +352,6 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
RET %2 RET %2
} }
### VM code ### VM code
0000: I_PUSH 6 0000: I_PUSH 6
0001: I_STORE 0 0001: I_STORE 0
@ -245,35 +359,41 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
0003: I_STORE 1 0003: I_STORE 1
0004: I_LOAD 0 0004: I_LOAD 0
0005: I_LOAD 1 0005: I_LOAD 1
0006: CALL 12 2 0006: CALL 13 2
0007: I_STORE 2 0007: I_STORE 2
0008: I_PUSH 0 0008: I_PUSH 0
0009: I_STORE 3 0009: I_STORE 3
0010: I_LOAD 3 0010: I_LOAD 3
0011: HALT 0011: HALT
0012: I_LOAD 0 0012: HALT
0013: I_LOAD 1 0013: I_LOAD 0
0014: I_ADD 0014: I_LOAD 1
0015: I_STORE 2 0015: I_ADD
0016: I_LOAD 2 0016: I_STORE 2
0017: RET 0017: I_LOAD 2
0018: RET
0019: RET
Written to D:\Devs\IdeaProjects\Snow\target\Demo1.water Written to D:\Devs\IdeaProjects\Snow\target\Demo1.water
=== Launching VM === === Launching VM ===
Calling function at address: 12
Calling function at address: 13
Return 7 Return 7
Process has ended Process has ended
Operand Stack state:[0] Operand Stack state:[0]
--- Call Stack State --- --- Call Stack State ---
### VM Local Variable Table: ### VM Local Variable Table:
0: 6 0: 6
1: 1 1: 1
2: 7 2: 7
3: 0 3: 0
=== VM exited ===
````` `````
## 编译 Snow 源代码 ## 编译 Snow 源代码
@ -282,38 +402,38 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
独立编译不依赖 `.cloud` 文件,而是直接使用 `Snow` 编译器进行 `.snow` 文件的编译和执行。 独立编译不依赖 `.cloud` 文件,而是直接使用 `Snow` 编译器进行 `.snow` 文件的编译和执行。
#### 独立编译步骤 #### 独立编译步骤:
1. **运行编译器** 1. **运行编译器:**
你可以通过以下命令来编译单个或多个 `.snow` 文件,或者递归编译一个目录中的所有 `.snow` 源文件为`.water`虚拟机指令。 你可以通过以下命令来编译单个或多个 `.snow` 文件,或者递归编译一个目录中的所有 `.snow` 源文件为`.water`虚拟机指令。
* **单个文件编译** * **单个文件编译:**
```bash ```bash
Snow complete [SnowCode].snow Snow complete [SnowCode].snow
``` ```
* **多个文件编译** * **多个文件编译:**
```bash ```bash
Snow complete [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow -o [Name] Snow complete [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow -o [Name]
``` ```
* **目录递归编译** * **目录递归编译:**
```bash ```bash
Snow -d path/to/source_dir Snow -d path/to/source_dir
``` ```
2. **查看编译输出** 2. **查看编译输出:**
编译过程会输出源代码、抽象语法树AST、中间表示IR以及虚拟机指令等内容。你可以看到如下几个分段输出 编译过程会输出源代码、抽象语法树AST、中间表示IR以及虚拟机指令等内容。你可以看到如下几个分段输出:
* **AST**(抽象语法树)部分以 JSON 格式输出。 * **AST**(抽象语法树)部分以 JSON 格式输出。
* **IR**(中间表示)部分会列出逐行的中间代码。 * **IR**(中间表示)部分会列出逐行的中间代码。
* **VM code**(虚拟机指令)会展示虚拟机的字节码指令。 * **VM code**(虚拟机指令)会展示虚拟机的字节码指令。
3. **默认执行模式** 3. **默认执行模式:**
编译器会在 **DEBUG 模式** 下运行,显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。 编译器会在 **RUN 模式** 下运行,**DEBUG 模式**显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。
--- ---
@ -321,30 +441,30 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
集成编译需要使用 `.cloud` 文件来指定项目的配置和结构,适用于项目标准化、依赖管理、构建管理和项目分发等场景。 集成编译需要使用 `.cloud` 文件来指定项目的配置和结构,适用于项目标准化、依赖管理、构建管理和项目分发等场景。
#### 集成编译命令 #### 集成编译命令:
1. **基本用法** 1. **基本用法:**
```bash ```bash
snow [OPTIONS] <command> snow [OPTIONS] <command>
``` ```
2. **命令选项** 2. **命令选项:**
* `-h, --help`显示帮助信息并退出。 * `-h, --help`: 显示帮助信息并退出。
* `-v, --version`打印 Snow 编程语言的版本并退出。 * `-v, --version`: 打印 Snow 编程语言的版本并退出。
3. **可用命令** 3. **可用命令:**
* `compile``.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。 * `compile`: `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。
* `clean`清理构建输出和本地缓存,移除中间产物,释放磁盘空间。 * `clean`: 清理构建输出和本地缓存,移除中间产物,释放磁盘空间。
* `version`打印 Snow 的版本。 * `version`: 打印 Snow 的版本。
* `run`运行已编译的虚拟机字节码文件(`.water`)。 * `run`: 运行已编译的虚拟机字节码文件(`.water`)。
* `init`初始化一个新项目,生成 `project.cloud` 文件。 * `init`: 初始化一个新项目,生成 `project.cloud` 文件。
* `generate`根据 `project.cloud` 生成项目目录结构。 * `generate`: 根据 `project.cloud` 生成项目目录结构。
* `build`构建当前项目,按顺序解析依赖、编译和打包。 * `build`: 构建当前项目,按顺序解析依赖、编译和打包。
4. **例如,执行集成编译命令** 4. **例如,执行集成编译命令:**
```bash ```bash
snow compile [SnowCode].snow snow compile [SnowCode].snow
@ -352,14 +472,14 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
* 此命令会使用 `.cloud` 文件中的配置信息来指导编译过程,并生成 `.water` * 此命令会使用 `.cloud` 文件中的配置信息来指导编译过程,并生成 `.water`
5. **使用帮助** 5. **使用帮助:**
如果你需要了解某个命令的详细选项,可以使用 如果你需要了解某个命令的详细选项,可以使用:
```bash ```bash
snow <command> --help snow <command> --help
``` ```
例如,查看 `compile` 命令的具体选项 例如,查看 `compile` 命令的具体选项:
```bash ```bash
snow compile --help snow compile --help
@ -369,7 +489,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
## 示例代码片段 ## 示例代码片段
以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法 以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法:
```snow ```snow
module: Math module: Math
@ -388,11 +508,11 @@ module: Math
body: body:
declare num1:int = 1 declare num1:int = 1
loop: loop:
initializer: init:
declare counter:int = 1 declare counter:int = 1
condition: cond:
counter <= n counter <= n
update: step:
counter = counter + 1 counter = counter + 1
body: body:
num1 = num1 * counter num1 = num1 * counter
@ -404,10 +524,10 @@ module: Math
end module end module
``` ```
上述代码定义了一个名为 `Math` 的模块,其中包含两个函数 上述代码定义了一个名为 `Math` 的模块,其中包含两个函数:
* `main`不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0` * `main`: 不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`
* `factorial`接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1``1`,然后通过一个 * `factorial`: 接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1``1`,然后通过一个
`loop` 循环(从 `counter = 1``counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。 `loop` 循环(从 `counter = 1``counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。
@ -415,53 +535,59 @@ end module
## 项目结构说明 ## 项目结构说明
* `compiler/`Snow 编译器源代码目录 * `compiler/`: Snow 编译器源代码目录
* `lexer/`词法分析模块,负责将源码切分为 Token * `lexer/`: 词法分析模块,负责将源码切分为 Token
* `parser/`语法分析模块,将 Token 流解析为 AST含模块/函数/语句解析) * `parser/`: 语法分析模块,将 Token 流解析为 AST含模块/函数/语句解析)
* `semantic/`语义分析模块,负责符号表管理、类型检查等 * `semantic/`: 语义分析模块,负责符号表管理、类型检查等
* `ir/`中间表示IR模块生成并管理三地址码形式的中间代码 * `ir/`: 中间表示IR模块生成并管理三地址码形式的中间代码
* `backend/`编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器 * `backend/`: 编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
* `vm/`虚拟机相关源代码目录 * `vm/`: 虚拟机相关源代码目录
* `commands/`定义 SnowVM 指令集的具体实现 * `commands/`: 定义 SnowVM 指令集的具体实现
* `engine/`核心执行引擎,提供指令执行和寄存器/栈管理 * `engine/`: 核心执行引擎,提供指令执行和寄存器/栈管理
* `execution/`执行流程控制(按指令顺序执行、分支跳转等) * `execution/`: 执行流程控制(按指令顺序执行、分支跳转等)
* `io/`输入输出辅助类(加载指令、文件解析等) * `io/`: 输入输出辅助类(加载指令、文件解析等)
* `gui/`Swing 可视化调试面板,实时展示局部变量表 * `gui/`: Swing 可视化调试面板,实时展示局部变量表
* `factories/``utils/`指令创建、日志调试等公共工具 * `factories/``utils/`: 指令创建、日志调试等公共工具
* `pkg/`内置构建与包管理器 **snow pkg** * `pkg/`: 内置构建与包管理器 **snow pkg**
* `dsl/``.cloud` 描述文件解析器 * `dsl/`: `.cloud` 描述文件解析器
* `tasks/`预设任务实现(`clean · compile · run · package · publish` 等) * `tasks/`: 预设任务实现(`clean · compile · run · package · publish` 等)
* `resolver/`本地/远程仓库解析与缓存 * `resolver/`: 本地/远程仓库解析与缓存
* `lifecycle/`任务生命周期钩子pre/post 脚本等) * `lifecycle/`: 任务生命周期钩子pre/post 脚本等)
* `model/`项目、依赖、版本等模型 * `model/`: 项目、依赖、版本等模型
* `utils/`文件、日志、校验和等通用工具 * `utils/`: 文件、日志、校验和等通用工具
* `doc/`开发者文档与示例 `.cloud` 配置 * `doc/`: 开发者文档与示例 `.cloud` 配置
* `cli/`独立的命令行前端 * `cli/`: 独立的命令行前端
* `commands/``compile` / `run` / `pkg` 等子命令实现 * `commands/`: `compile` / `run` / `pkg` 等子命令实现
* `api/`公共选项解析、终端交互抽象 * `api/`: 公共选项解析、终端交互抽象
* `utils/`终端颜色、进度条、异常格式化等 * `utils/`: 终端颜色、进度条、异常格式化等
* `SnowCLI.java`CLI 主入口 * `SnowCLI.java`: CLI 主入口
## 版权声明 ## 版权声明
版权所有 © 2025 许轲Luke代表 SnowLang 项目。 版权所有 © 2025 许轲Luke代表 SnowLang 项目。
仓库地址<https://gitee.com/jcnc-org/snow> 仓库地址: <https://gitee.com/jcnc-org/snow>
本项目依据 [Apache 2.0 许可证](LICENSE) 进行许可和发布。 本项目依据 [Apache 2.0 许可证](LICENSE) 进行许可和发布。
“SnowLang 项目”为由许轲Luke发起的独立开源项目。 “SnowLang 项目”为由许轲Luke发起的独立开源项目。
未来,项目可能会成立正式的组织或实体,以进一步负责本项目的开发和管理。 未来,项目可能会成立正式的组织或实体,以进一步负责本项目的开发和管理。
## 支持我们
如果你喜欢我们的项目,欢迎给我们一个 Star
你们的关注和支持,是我们团队持续进步的动力源泉!谢谢大家!
## 加入我们 ## 加入我们
- 微信:`xuxiaolankaka` - 微信: `xuxiaolankaka`
- QQ`1399528359` - QQ: `1399528359`
- 邮箱:`luke.k.xu [at] hotmail.com` - 邮箱: `luke.k.xu [at] hotmail.com`

View File

@ -2,27 +2,27 @@
在执行 `build-project2tar.ps1` 脚本之前,您需要确保 PowerShell 的执行策略允许运行脚本。默认情况下PowerShell 可能阻止未签名的脚本执行。因此,您需要设置适当的执行策略。 在执行 `build-project2tar.ps1` 脚本之前,您需要确保 PowerShell 的执行策略允许运行脚本。默认情况下PowerShell 可能阻止未签名的脚本执行。因此,您需要设置适当的执行策略。
#### 步骤 1以管理员身份打开 PowerShell #### 步骤 1: 以管理员身份打开 PowerShell
* 在 Windows 系统中,搜索 **PowerShell**,右键点击 **Windows PowerShell**,并选择 **以管理员身份运行** * 在 Windows 系统中,搜索 **PowerShell**,右键点击 **Windows PowerShell**,并选择 **以管理员身份运行**
#### 步骤 2设置 PowerShell 执行策略 #### 步骤 2: 设置 PowerShell 执行策略
为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter 为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter:
```powershell ```powershell
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
``` ```
#### 解释 #### 解释:
* `-Scope CurrentUser`此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。 * `-Scope CurrentUser`: 此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。
* `-ExecutionPolicy RemoteSigned`:此策略表示: * `-ExecutionPolicy RemoteSigned`: 此策略表示:
* 本地创建的脚本可以直接运行。 * 本地创建的脚本可以直接运行。
* 从互联网下载的脚本必须具备有效的数字签名才能运行。没有签名的脚本将无法执行,除非您先解除阻止该脚本。 * 从互联网下载的脚本必须具备有效的数字签名才能运行。没有签名的脚本将无法执行,除非您先解除阻止该脚本。
#### 步骤 3运行 `build-project2tar.ps1` 脚本 #### 步骤 3: 运行 `build-project2tar.ps1` 脚本
设置完成后,您可以在 PowerShell 中运行 `build-project2tar.ps1` 脚本。确保您已经切换到包含该脚本的目录,或提供完整的文件路径来执行它。 设置完成后,您可以在 PowerShell 中运行 `build-project2tar.ps1` 脚本。确保您已经切换到包含该脚本的目录,或提供完整的文件路径来执行它。

View File

@ -11,7 +11,7 @@ $parentDir = Split-Path -Parent $scriptDir
$tarPath = Join-Path $parentDir $tarName $tarPath = Join-Path $parentDir $tarName
# 输出开始创建 tar 包的消息 # 输出开始创建 tar 包的消息
Write-Output "开始创建 tar 包$tarName$parentDir ..." Write-Output "开始创建 tar 包: $tarName$parentDir ..."
# 如果存在旧 tar 包,先删除它 # 如果存在旧 tar 包,先删除它
if (Test-Path $tarPath) { if (Test-Path $tarPath) {
@ -26,7 +26,7 @@ if (-not (Get-Command $tarCommand -ErrorAction SilentlyContinue)) {
exit 1 exit 1
} }
# 执行打包操作切换到 org\jcnc 目录下再压缩 snow 文件夹 # 执行打包操作: 切换到 org\jcnc 目录下再压缩 snow 文件夹
try { try {
# 构建命令并执行 # 构建命令并执行
$tarCommandArgs = "-cf", $tarPath, "-C", "$scriptDir\..\src\main\java\org\jcnc", "snow" $tarCommandArgs = "-cf", $tarPath, "-C", "$scriptDir\..\src\main\java\org\jcnc", "snow"
@ -34,7 +34,7 @@ try {
& $tarCommand @tarCommandArgs & $tarCommand @tarCommandArgs
} catch { } catch {
Write-Error "❌ 创建 tar 包失败。错误信息$_" Write-Error "❌ 创建 tar 包失败。错误信息: $_"
exit 1 exit 1
} }

View File

@ -2,7 +2,7 @@
## 1. 版本控制基础 ## 1. 版本控制基础
本项目使用 Git 进行版本控制,并遵循以下基本原则 本项目使用 Git 进行版本控制,并遵循以下基本原则:
* 所有代码更改必须通过 Git 提交,并推送至远程仓库。 * 所有代码更改必须通过 Git 提交,并推送至远程仓库。
* 每次提交必须包括清晰、简洁且具描述性的提交信息,确保团队成员能够轻松理解变更的目的和内容。 * 每次提交必须包括清晰、简洁且具描述性的提交信息,确保团队成员能够轻松理解变更的目的和内容。
@ -10,23 +10,23 @@
## 2. 分支管理 ## 2. 分支管理
本项目采用以下分支策略进行代码管理 本项目采用以下分支策略进行代码管理:
### 2.1 主分支 (`main`) ### 2.1 主分支 (`main`)
* **用途**`main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。 * **用途**: `main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。
* **更新规则**仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev``release` 分支合并到 `main` 时,必须打上版本标签。 * **更新规则**: 仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev``release` 分支合并到 `main` 时,必须打上版本标签。
### 2.2 开发分支 (`dev`) ### 2.2 开发分支 (`dev`)
* **用途**`dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main` * **用途**: `dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`
* **更新规则**所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main` * **更新规则**: 所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`
### 2.3 功能分支 (`feature/*`) ### 2.3 功能分支 (`feature/*`)
* **用途**每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。 * **用途**: 每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。
* **命名规范**`feature/功能描述`,例如:`feature/ast-folding``feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。 * **命名规范**: `feature/功能描述`,例如: `feature/ast-folding``feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。
* **开发流程** * **开发流程**:
1. 从 `dev` 分支拉取最新代码。 1. 从 `dev` 分支拉取最新代码。
2. 完成功能开发后,在本地提交代码并推送至远程仓库。 2. 完成功能开发后,在本地提交代码并推送至远程仓库。
@ -34,9 +34,9 @@
### 2.4 修复分支 (`bugfix/*`) ### 2.4 修复分支 (`bugfix/*`)
* **用途**用于修复 Bug修复分支可以从 `dev``main` 分支创建。 * **用途**: 用于修复 Bug修复分支可以从 `dev``main` 分支创建。
* **命名规范**`bugfix/bug描述`,例如:`bugfix/fix-ast-error` * **命名规范**: `bugfix/bug描述`,例如: `bugfix/fix-ast-error`
* **开发流程** * **开发流程**:
1. 从 `dev``main` 分支拉取最新代码。 1. 从 `dev``main` 分支拉取最新代码。
2. 完成修复后,提交修改并推送至远程仓库。 2. 完成修复后,提交修改并推送至远程仓库。
@ -44,9 +44,9 @@
### 2.5 发布分支 (`release/*`) ### 2.5 发布分支 (`release/*`)
* **用途**`dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。 * **用途**: `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。
* **命名规范**`release/vX.X.X`,例如:`release/v1.0.0` * **命名规范**: `release/vX.X.X`,例如: `release/v1.0.0`
* **开发流程** * **开发流程**:
1. 从 `dev` 分支创建 `release` 分支。 1. 从 `dev` 分支创建 `release` 分支。
2. 在 `release` 分支上进行版本发布的最终准备工作,如文档更新、版本号调整等。 2. 在 `release` 分支上进行版本发布的最终准备工作,如文档更新、版本号调整等。
@ -54,24 +54,24 @@
### 2.6 热修复分支 (`hotfix/*`) ### 2.6 热修复分支 (`hotfix/*`)
* **用途**当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。 * **用途**: 当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。
* **命名规范**`hotfix/bug描述`,例如:`hotfix/fix-production-crash` * **命名规范**: `hotfix/bug描述`,例如: `hotfix/fix-production-crash`
* **开发流程** * **开发流程**:
1. 从 `main` 分支创建 `hotfix` 分支,确保该分支包含生产环境中最新的稳定版本。 1. 从 `main` 分支创建 `hotfix` 分支,确保该分支包含生产环境中最新的稳定版本。
2. 在 `hotfix` 分支上进行问题修复和相关调整。 2. 在 `hotfix` 分支上进行问题修复和相关调整。
3. 完成修复后,提交修改并推送至远程仓库。 3. 完成修复后,提交修改并推送至远程仓库。
4. 创建拉取请求PR`hotfix` 分支合并至 `main` 分支并打上版本标签,确保生产环境修复生效。 4. 创建拉取请求PR`hotfix` 分支合并至 `main` 分支并打上版本标签,确保生产环境修复生效。
5. 将修复后的变更合并回 `dev` 分支,确保所有的修复和调整同步到开发分支,防止后续开发中出现同样的问题。 5. 将修复后的变更合并回 `dev` 分支,确保所有的修复和调整同步到开发分支,防止后续开发中出现同样的问题。
6. **回滚策略**如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。 6. **回滚策略**: 如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。
## 3. 提交规范 ## 3. 提交规范
为确保提交信息清晰且易于理解,遵循以下提交规范 为确保提交信息清晰且易于理解,遵循以下提交规范:
### 3.1 提交信息格式 ### 3.1 提交信息格式
提交信息应简洁且具有描述性,格式如下 提交信息应简洁且具有描述性,格式如下:
``` ```
[类型] 描述 [类型] 描述
@ -81,20 +81,20 @@
#### 提交类型 #### 提交类型
* `feat`新增功能 * `feat`: 新增功能
* `fix`修复 Bug * `fix`: 修复 Bug
* `docs`文档更新 * `docs`: 文档更新
* `style`代码格式调整(不影响功能) * `style`: 代码格式调整(不影响功能)
* `refactor`代码重构 * `refactor`: 代码重构
* `test`增加/修改测试 * `test`: 增加/修改测试
* `chore`工具配置等其他杂项任务 * `chore`: 工具配置等其他杂项任务
* `ci`持续集成相关改动 * `ci`: 持续集成相关改动
* `perf`性能优化 * `perf`: 性能优化
#### 示例 #### 示例
* `feat: 添加 IR 折叠功能` * `feat: 添加 IR 折叠功能`
* `fix: 修复问题 Y原因X bug解决方案Z` * `fix: 修复问题 Y原因: X bug解决方案: Z`
* `docs: 更新 API 文档` * `docs: 更新 API 文档`
* `refactor: 优化 AST 逻辑` * `refactor: 优化 AST 逻辑`
@ -114,7 +114,7 @@
### 4.2 代码审查 ### 4.2 代码审查
* 所有 PR 必须经过至少一名开发者的代码审查。 * 所有 PR 必须经过至少一名开发者的代码审查。
* 审查时应关注以下方面 * 审查时应关注以下方面:
* 代码是否符合项目的编码规范。 * 代码是否符合项目的编码规范。
* 是否提供了足够的单元测试覆盖。 * 是否提供了足够的单元测试覆盖。
@ -124,14 +124,14 @@
## 5. 版本发布 ## 5. 版本发布
版本发布基于 Git 标签,发布流程如下 版本发布基于 Git 标签,发布流程如下:
### 5.1 打标签 ### 5.1 打标签
每当版本准备发布时,应在 `main` 分支上打上版本标签 每当版本准备发布时,应在 `main` 分支上打上版本标签:
* **版本号规则**采用语义化版本控制SemVer格式版本号由三部分组成`主版本号.次版本号.修订号`(例如:`v1.0.0`)。 * **版本号规则**: 采用语义化版本控制SemVer格式版本号由三部分组成: `主版本号.次版本号.修订号`(例如: `v1.0.0`)。
* **标签命令** * **标签命令**:
```bash ```bash
git tag v1.0.0 git tag v1.0.0

View File

@ -6,7 +6,7 @@
## 2. 前置条件 ## 2. 前置条件
1. 操作系统Linux/macOS/Windows 1. 操作系统: Linux/macOS/Windows
2. Java 项目Maven 2. Java 项目Maven
3. GraalVM建议 24+ 版本) 3. GraalVM建议 24+ 版本)
@ -14,10 +14,10 @@
### 3.1 安装 GraalVM ### 3.1 安装 GraalVM
1. 下载对应平台的 GraalVM Community 版本[https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/) 1. 下载对应平台的 GraalVM Community 版本: [https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/)
2. 解压并配置环境变量 2. 解压并配置环境变量:
3. 验证安装 3. 验证安装:
```bash ```bash
java -version 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 项目配置文件 ## 4. Maven 项目配置文件
通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件 通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件:
```xml ```xml
<profiles> <profiles>
<!-- <!--
原生镜像构建Linux 平台 原生镜像构建: Linux 平台
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件 - 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
- 依赖 musl libc需提前安装并配置 musl-gcc 工具链 - 依赖 musl libc需提前安装并配置 musl-gcc 工具链
--> -->
@ -111,7 +111,7 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc
</profile> </profile>
<!-- <!--
原生镜像构建Windows 平台 原生镜像构建: Windows 平台
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件 - 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
- Windows 上不使用 musl因此不配置静态链接 - Windows 上不使用 musl因此不配置静态链接
--> -->
@ -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) ![IMG_Maven_Package_1.png](img/IMG_Maven_Package_1.png)
3. 等待 Native Image 构建完成这个过程可能较慢(数分钟)。 3. 等待 Native Image 构建完成: 这个过程可能较慢(数分钟)。
4. 可执行文件即可直接运行,无需 JVM。 4. 可执行文件即可直接运行,无需 JVM。
> 生成的可执行文件位于 target/ 目录。 > 生成的可执行文件位于 target/ 目录。

View File

@ -7,22 +7,22 @@
## 1.2 背景与目标读者 ## 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 文章目的 ## 1.3 文章目的
本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标 本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标:
* **兴趣驱动的坚持**用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。 * **兴趣驱动的坚持**: 用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。
* **从规划到实践的拆解**详解在有限资源下如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。 * **从规划到实践的拆解**: 详解在有限资源下如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。
* **经验与反思**不仅有“成功输出 1+1=2”的成就感也有调试死循环、运算符冲突等踩坑经历全方位展示编程语言设计的挑战与思考。 * **经验与反思**: 不仅有“成功输出 1+1=2”的成就感也有调试死循环、运算符冲突等踩坑经历全方位展示编程语言设计的挑战与思考。
* **激励与号召**希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。 * **激励与号召**: 希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。
--- ---
@ -31,18 +31,18 @@
## 2.1 现有工具的痛点 ## 2.1 现有工具的痛点
* **编程语言过于灵活,缺乏规范** * **编程语言过于灵活,缺乏规范**
常见的编程语言如 Python、PHP、Ruby虽然语法简洁、上手快但“灵活性”本身也带来了不少隐患变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶? 常见的编程语言如 Python、PHP、Ruby虽然语法简洁、上手快但“灵活性”本身也带来了不少隐患: 变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考: 如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶?
* **缺乏专为 LLM 设计的编程语言** * **缺乏专为 LLM 设计的编程语言**
当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如部分语法容易混淆作用域和可见性规则不直观LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。 当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如: 部分语法容易混淆作用域和可见性规则不直观LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。
## 2.2 触发想法的场景 ## 2.2 触发想法的场景
* **对高效与规范的需求日益突出** * **对高效与规范的需求日益突出**
在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。 在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论: 能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。
* **自研编程语言的大胆设想** * **自研编程语言的大胆设想**
随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP总要写很多提示还要人工修正各种细节。由此引发思考如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率? 随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP总要写很多提示还要人工修正各种细节。由此引发思考: 如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率?
## 2.3 项目愿景 ## 2.3 项目愿景
@ -62,12 +62,12 @@
## 3.1 为什么开源 ## 3.1 为什么开源
* **获得社区反馈,检验设计思路**闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。 * **获得社区反馈,检验设计思路**: 闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。
* **边开源边完善,更吸引贡献者**功能精简但可用时就发布,容易吸引早期用户参与共建。 * **边开源边完善,更吸引贡献者**: 功能精简但可用时就发布,容易吸引早期用户参与共建。
## 3.2 开源准备工作 ## 3.2 开源准备工作
* **许可证选择** * **许可证选择**:
采用 [Apache-2.0](https://gitee.com/jcnc-org/snow/blob/main/LICENSE),最大程度降低贡献门槛。 采用 [Apache-2.0](https://gitee.com/jcnc-org/snow/blob/main/LICENSE),最大程度降低贡献门槛。
## 3.3 项目运行输出 ## 3.3 项目运行输出
@ -248,11 +248,11 @@ Process has ended
## 4.1 v0.2 初步目标 ## 4.1 v0.2 初步目标
1. **完善变量作用域与高级函数调用** 1. **完善变量作用域与高级函数调用**:
支持函数参数、返回值、本地与全局变量隔离,以及闭包基础,为并发/异步打基础。 支持函数参数、返回值、本地与全局变量隔离,以及闭包基础,为并发/异步打基础。
2. **完善错误提示与调试信息** 2. **完善错误提示与调试信息**:
报错更精准,方便新手调试。 报错更精准,方便新手调试。
3. **预计发布日期2025 年 7 月 30 日** 3. **预计发布日期: 2025 年 7 月 30 日**
## 4.2 v0.3 目标 ## 4.2 v0.3 目标
1. **IDE的支持** 1. **IDE的支持**
@ -262,11 +262,11 @@ Process has ended
## 4.3 v1.0 长期规划 ## 4.3 v1.0 长期规划
1. **初步标准库** 1. **初步标准库**:
I/O、字符串、JSON、文件系统满足日常脚本需求。 I/O、字符串、JSON、文件系统满足日常脚本需求。
2. **包管理与模块加载** 2. **包管理与模块加载**:
设计 `snowpkg`,支持一键安装依赖、自动模块导入。 设计 `snowpkg`,支持一键安装依赖、自动模块导入。
3. **社区协作与贡献** 3. **社区协作与贡献**:
开设设计讨论区、每月线上分享,鼓励贡献代码与案例,让更多人参与 Snow 的成长。 开设设计讨论区、每月线上分享,鼓励贡献代码与案例,让更多人参与 Snow 的成长。
--- ---
@ -275,15 +275,15 @@ Process has ended
## 5.1 学习收获与成就感 ## 5.1 学习收获与成就感
回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是让一个想法变成可运行的代码哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。 回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是: 让一个想法变成可运行的代码哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。
## 5.2 技术敬畏与情感共鸣 ## 5.2 技术敬畏与情感共鸣
也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。 也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节: 多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。
## 5.3 欢迎你的加入 ## 5.3 欢迎你的加入
真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴 真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴:
1. 在 Gitee 提交 Issue反馈使用体验和建议 1. 在 Gitee 提交 Issue反馈使用体验和建议
2. Fork 仓库、贡献 PR参与语法和功能共建 2. Fork 仓库、贡献 PR参与语法和功能共建
@ -294,7 +294,7 @@ Process has ended
> 微信: xuxiaolankaka > 微信: xuxiaolankaka
> QQ: 1399528359 > QQ: 1399528359
对于从未写过语言的初学者,我想说**不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。 对于从未写过语言的初学者,我想说: **不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。
--- ---

View File

@ -1,6 +1,6 @@
# Snow 语言现状和下一阶段开发路线图 # Snow 语言现状和下一阶段开发路线图
> 日期2025-06-11 > 日期: 2025-06-11
## 1. 代码结构与职责 ## 1. 代码结构与职责
| 层次 | 主要包/目录 | 说明 | | 层次 | 主要包/目录 | 说明 |
@ -30,7 +30,7 @@
6. **VM** 6. **VM**
* 栈-基 / 寄存器混合架构 * 栈-基 / 寄存器混合架构
* 96 条已实现指令(按数据宽度泛化B/S/I/L/F/D * 96 条已实现指令(按数据宽度泛化: B/S/I/L/F/D
* 运行时启动器 `VMLauncher` * 运行时启动器 `VMLauncher`
@ -50,7 +50,7 @@
## 4. 下一阶段开发路线图 ## 4. 下一阶段开发路线图
> 优先级P0 = 当前版本必须P1 = 下一个小版本P2 = 中长期 > 优先级: P0 = 当前版本必须P1 = 下一个小版本P2 = 中长期
| 优先级 | 功能 | 关键任务 | | 优先级 | 功能 | 关键任务 |
|--------|------------------|----------------------------------------------------------------------------------------------------------------------| |--------|------------------|----------------------------------------------------------------------------------------------------------------------|
@ -58,18 +58,18 @@
| **P0** | **一元表达式解析** | \* 实现 `UnaryOperatorParselet``-`, `+`, `!`)<br>\* 对应 `UnaryOpGenerator` 注册 | | **P0** | **一元表达式解析** | \* 实现 `UnaryOperatorParselet``-`, `+`, `!`)<br>\* 对应 `UnaryOpGenerator` 注册 |
| **P1** | **数组与切片** | \* 设计 `ArrayType`(元素类型 + 维度)<br>\* 新增 `IndexExpressionNode``NewArrayNode`<br>\* VM 扩充 `ALOAD/ASTORE` 指令 | | **P1** | **数组与切片** | \* 设计 `ArrayType`(元素类型 + 维度)<br>\* 新增 `IndexExpressionNode``NewArrayNode`<br>\* VM 扩充 `ALOAD/ASTORE` 指令 |
| **P1** | **基础标准库** | \* `print/println`, 文件读写<br>\* 编译期内置绑定到 VM calls | | **P1** | **基础标准库** | \* `print/println`, 文件读写<br>\* 编译期内置绑定到 VM calls |
| **P1** | **测试与 CI** | \* JUnit5 单测Lexer / Parser / Semantic / VM<br>\* CI/CD 自动构建、示例编译运行 | | **P1** | **测试与 CI** | \* JUnit5 单测: Lexer / Parser / Semantic / VM<br>\* CI/CD 自动构建、示例编译运行 |
| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局<br>\* 方法调度静态 or 虚表 | | **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局<br>\* 方法调度: 静态 or 虚表 |
| **P2** | **优化管线** | \* 常量折叠、公共子表达式消除<br>\* 简易死代码清除 | | **P2** | **优化管线** | \* 常量折叠、公共子表达式消除<br>\* 简易死代码清除 |
| **P2** | **错误与异常系统** | \* 语法`try … catch … end`<br>\* VM展开-收缩栈,异常表 | | **P2** | **错误与异常系统** | \* 语法: `try … catch … end`<br>\* VM: 展开-收缩栈,异常表 |
| **P2** | **包管理 & CLI** | \* `snowc` 命令`build`, `run`, `test`<br>\* 本地缓存 `.snowpkg`与包版本语义 | | **P2** | **包管理 & CLI** | \* `snowc` 命令: `build`, `run`, `test`<br>\* 本地缓存 `.snowpkg`与包版本语义 |
## 5.1 里程碑排期 ## 5.1 里程碑排期
| 时间 | 目标 | | 时间 | 目标 |
|---------|----------------------------------------| |---------|----------------------------------------|
| 2025-07 | 发布 **v0.2.0**布尔类型 + 一元运算、20+ 单元测试 | | 2025-07 | 发布 **v0.2.0**: 布尔类型 + 一元运算、20+ 单元测试 |
| 2025-08 | 发布 **v0.3.0**数组/切片 & 基础标准库;引入 CLI | | 2025-08 | 发布 **v0.3.0**: 数组/切片 & 基础标准库;引入 CLI |
| 2025-10 | 发布 **v0.4.0**结构体支持、首批优化 Pass、>80% 覆盖率 | | 2025-10 | 发布 **v0.4.0**: 结构体支持、首批优化 Pass、>80% 覆盖率 |
| 2026-11 | 发布 **v1.0.0**异常系统、稳定包管理、文档完善 | | 2026-11 | 发布 **v1.0.0**: 异常系统、稳定包管理、文档完善 |

View File

@ -0,0 +1,581 @@
# SnowLang 语法规范
---
## 0 · 符号约定
* ⟦ … ⟧: 可选项0 或 1 次)
* { … }\*: 可重复项0 次或多次)
---
## 1 · 词汇结构
### 1.1 编码与字符集
源文件采用 UTF8 编码。除注释外,标识符只允许英文大小写字母 (AZ az)、数字 (09) 与下划线 _首字符不能为数字。
```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: <ModuleName>
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: <ModuleA>⟦ as <AliasA>⟧, <ModuleB>⟦ as <AliasB>⟧, …
```
* **别名 (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 |
| l | long | 5l, 123L |
| f | float | 3.14f |
- 没有后缀的整数字面量自动为 `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
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:
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) // 匹配第二个构造函数
````

View File

@ -31,14 +31,14 @@ end module
### 数据类型 ### 数据类型
bool 类型 bool 类型:
两种值`true``false` 两种值: `true``false`
数值类型 数值类型:
| Number | keyword | | Number | keyword |
|----------|---------| |----------|---------|
@ -51,7 +51,7 @@ bool 类型:
默认整数的类型为 int浮点数的类型为 double。 默认整数的类型为 int浮点数的类型为 double。
数值字面量后缀 数值字面量后缀:
| 数值字面量后缀 | 例子 | | 数值字面量后缀 | 例子 |
|---------|----| |---------|----|
@ -64,7 +64,7 @@ bool 类型:
### 变量 ### 变量
定义变量的形式如下,中括号表示可选 定义变量的形式如下,中括号表示可选:
```snow ```snow
declare name: type [= initial_value] declare name: type [= initial_value]
@ -72,24 +72,24 @@ declare name: type [= initial_value]
其中 `name` 是变量名,`type` 是变量类型,`initial_value` 是初始值 其中 `name` 是变量名,`type` 是变量类型,`initial_value` 是初始值
:
```snow ```snow
declare x: int declare x: int
declare y: long = 123456789 declare y: long = 123456789
``` ```
读取变量值的方法,直接写变量的名字即可 读取变量值的方法,直接写变量的名字即可:
```snow ```snow
x x
``` ```
设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可 设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可:
```snow ```snow
x = 10 x = 10
``` ```
于是可以通过这种方式让变量参与计算并保存结果 于是可以通过这种方式让变量参与计算并保存结果:
```snow ```snow
x = y + 1 x = y + 1
``` ```
@ -99,19 +99,19 @@ x = y + 1
## 流程控制 ## 流程控制
### if ### if
if 语句的形式如下else 是可选的 if 语句的形式如下else 是可选的:
```snow ```snow
if condition then if cond then
// 条件成立执行的代码 // 条件成立执行的代码
else else
// 以上条件不成立执行的代码 // 以上条件不成立执行的代码
end if end if
``` ```
condition 可以是表达式(结果为 bool 类型)或者 bool 字面量 cond 可以是表达式(结果为 bool 类型)或者 bool 字面量
:
```snow ```snow
module: Main module: Main
@ -131,17 +131,17 @@ end module
``` ```
### loop ### loop
loop 语句的形式如下 loop 语句的形式如下:
```snow ```snow
loop: loop:
initializer: init:
// 循环开始前可声明循环变量,有且只能声明一个 // 循环开始前可声明循环变量,有且只能声明一个
declare i: int = 1 declare i: int = 1
condition: cond:
// 循环条件,成立则执行 body 的代码, // 循环条件,成立则执行 body 的代码,
// 不成立则退出循环,有且只能写一条 // 不成立则退出循环,有且只能写一条
i <= 100 i <= 100
update: step:
// 循环体执行完后执行的代码,有且只能写一条 // 循环体执行完后执行的代码,有且只能写一条
i = i + 1 i = i + 1
body: body:
@ -150,7 +150,7 @@ loop:
end loop end loop
``` ```
例子(求 1 ~ 100 的和) 例子(求 1 ~ 100 的和):
```snow ```snow
module: Main module: Main
function: main function: main
@ -158,11 +158,11 @@ module: Main
body: body:
declare sum: int = 0 declare sum: int = 0
loop: loop:
initializer: init:
declare i: int = 1 declare i: int = 1
condition: cond:
i <= 100 i <= 100
update: step:
i = i + 1 i = i + 1
body: body:
sum = sum + i sum = sum + i
@ -176,7 +176,7 @@ end module
``` ```
## 函数 ## 函数
函数的形式如下 函数的形式如下:
```snow ```snow
function: add function: add
parameter: parameter:
@ -197,7 +197,7 @@ end function
通过 import 语句导入模块, 通过 import 语句导入模块,
snow 会自动将同名模块的函数合并。 snow 会自动将同名模块的函数合并。
在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下 在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下:
```snow ```snow
module: Main module: Main
@ -213,7 +213,7 @@ end module
可以看到模块名是 Main里面有函数 main。 可以看到模块名是 Main里面有函数 main。
假如现在有一个模块 Math代码如下 假如现在有一个模块 Math代码如下:
```snow ```snow
// Math.snow // Math.snow
module: Math module: Math
@ -229,7 +229,7 @@ module: Math
end module end module
``` ```
可以使用 import 来导入 Math 模块 可以使用 import 来导入 Math 模块:
```snow ```snow
// main.snow // main.snow
module: Main module: Main
@ -244,7 +244,7 @@ module: Main
end module end module
``` ```
可以同时导入多个模块,用逗号(半角)分隔模块名即可 可以同时导入多个模块,用逗号(半角)分隔模块名即可:
```snow ```snow
// main.snow // main.snow
module: Main module: Main

View File

@ -1,7 +1,8 @@
# SnowVM-OpCode # SnowVM-OpCode
## 1. Byte8 区域0x0000-0x001F ## Type Control (0x0000-0x00BF)
### Byte8 (0x0000-0x001F)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|----------|--------|----------------| |----------|--------|----------------|
| B\_ADD | 0x0000 | byte8 加法 | | B\_ADD | 0x0000 | byte8 加法 |
@ -26,7 +27,7 @@
--- ---
## 2. Short16 区域0x0020-0x003F ### Short16 (0x0020-0x003F)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|----------|--------|------------------| |----------|--------|------------------|
@ -52,7 +53,7 @@
--- ---
## 3. Int32 区域0x0040-0x005F ### Int32 (0x0040-0x005F)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|----------|--------|----------------| |----------|--------|----------------|
@ -78,7 +79,7 @@
--- ---
## 4. Long64 区域0x0060-0x007F ### Long64 区域0x0060-0x007F
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|----------|--------|-----------------| |----------|--------|-----------------|
@ -104,7 +105,7 @@
--- ---
## 5. Float32 区域0x0080-0x009F ### Float32 区域0x0080-0x009F
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|----------|--------|------------------| |----------|--------|------------------|
@ -127,7 +128,7 @@
--- ---
## 6. Double64 区域0x00A0-0x00BF ### Double64 区域0x00A0-0x00BF
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|----------|--------|-------------------| |----------|--------|-------------------|
@ -150,7 +151,7 @@
--- ---
## 7. 类型转换0x00C0-0x00DF ## Type Conversion (0x00C0-0x00DF)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|-----|--------|--------------------| |-----|--------|--------------------|
@ -185,11 +186,17 @@
| D2L | 0x00DC | double64 转 long64 | | D2L | 0x00DC | double64 转 long64 |
| D2F | 0x00DD | double64 转 float32 | | D2F | 0x00DD | double64 转 float32 |
--- ---
## Reference Control (0x00E0-0x00EF)
| 指令名 | 十六进制 | 说明 |
|----------|--------|---------------------------|
| R\_PUSH | 0x00E0 | 将对象引用压入操作数栈 |
| R\_LOAD | 0x00E1 | 从本地变量表加载对象引用并压入操作数栈 |
| R\_STORE | 0x00E2 | 将操作数栈顶的对象引用弹出并存入本地变量表指定槽位 |
## 8. 栈控制0x0100-0x01FF
## Stack Control (0x0100-0x01FF)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|------|--------|----------| |------|--------|----------|
@ -199,7 +206,7 @@
--- ---
## 9. 流程控制0x0200-0x02FF ## Flow Control (0x0200-0x02FF)
| 指令名 | 十六进制/十进制 | 说明 | | 指令名 | 十六进制/十进制 | 说明 |
|------|----------|-------| |------|----------|-------|
@ -209,7 +216,7 @@
--- ---
## 10. 寄存器控制0x0300-0x03FF ## Register Control (0x0300-0x03FF)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|-----|--------|---------| |-----|--------|---------|
@ -217,7 +224,7 @@
--- ---
## 11. 系统控制0x0400-0x04FF ## System Control (0x0400-0x04FF)
| 指令名 | 十六进制 | 说明 | | 指令名 | 十六进制 | 说明 |
|-------------|--------|------| |-------------|--------|------|

View File

@ -15,11 +15,11 @@ module: Math
body: body:
declare num1:int = 1 declare num1:int = 1
loop: loop:
initializer: init:
declare counter:int = 1 declare counter:int = 1
condition: cond:
counter <= n counter <= n
update: step:
counter = counter + 1 counter = counter + 1
body: body:
num1 = num1 * counter num1 = num1 * counter

11
lib/os/OS.snow Normal file
View File

@ -0,0 +1,11 @@
module: os
import: os
function: print
parameter:
declare i1: int
return_type: void
body:
syscall("PRINT",i1)
end body
end function
end module

View File

@ -3,11 +3,11 @@ function: main
return_type: int return_type: int
body: body:
loop: loop:
initializer: init:
declare i:int = 0 declare i:int = 0
condition: cond:
1 == 1 1 == 1
update: step:
i = i + 1 i = i + 1
body: body:

View File

@ -1,17 +1,8 @@
module: Main module: Main
function: main function: main
return_type: int
body:
foo()
return 0
end body
end function
function: foo
return_type: void return_type: void
body: body:
declare abc:int =1
end body end body
end function end function
end module end module

View File

@ -7,34 +7,34 @@ module: Main
5 == 7b 5 == 7b
5 == 7l 5 == 7l
5 == 7f 5 == 7f
5 == 7d 5 == 7.0
5b == 5b 5b == 5b
5b == 5s 5b == 5s
5b == 5l 5b == 5l
5b == 5f 5b == 5f
5b == 5d 5b == 5.0
5s == 5s 5s == 5s
5s == 5l 5s == 5l
5s == 5f 5s == 5f
5s == 5d 5s == 5.0
5l == 5l 5l == 5l
5l == 5f 5l == 5f
5l == 5d 5l == 5.0
5f == 5f 5f == 5f
5f == 5d 5f == 5.0
5d == 5d 5.0 == 5.0
declare b: byte = 8b declare b: byte = 8b
declare s: short = 8s declare s: short = 8s
declare i: int = 8 declare i: int = 8
declare l: long = 8l declare l: long = 8l
declare f: float = 8f declare f: float = 8f
declare d: double = 8d declare d: double = 8
b == b b == b
b == s b == s

View File

@ -0,0 +1,9 @@
module: Main
import: os
function: main
return_type: void
body:
print(222)
end body
end function
end module

View File

@ -0,0 +1,11 @@
module: os
import: os
function: print
parameter:
declare i1: int
return_type: void
body:
syscall("PRINT",i1)
end body
end function
end module

View File

@ -5,11 +5,11 @@ module: Main
body: body:
declare b1: boolean = true declare b1: boolean = true
loop: loop:
initializer: init:
declare i:int = 0 declare i:int = 0
condition: cond:
b1 b1
update: step:
i = i + 1 i = i + 1
body: body:

View File

@ -15,11 +15,11 @@ module: Math
body: body:
declare num1:int = 1 declare num1:int = 1
loop: loop:
initializer: init:
declare counter:int = 1 declare counter:int = 1
condition: cond:
counter <= n counter <= n
update: step:
counter = counter + 1 counter = counter + 1
body: body:
num1 = num1 * counter num1 = num1 * counter

10
pom.xml
View File

@ -7,7 +7,7 @@
<groupId>org.jcnc.snow</groupId> <groupId>org.jcnc.snow</groupId>
<artifactId>Snow</artifactId> <artifactId>Snow</artifactId>
<version>0.4.2</version> <version>0.5.0</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -31,7 +31,7 @@
<plugins> <plugins>
<!-- <!--
Java 编译插件 Java 编译插件:
- 使用 Maven 自带的 maven-compiler-plugin 进行源码编译 - 使用 Maven 自带的 maven-compiler-plugin 进行源码编译
- <fork>true</fork> 表示在单独的进程中执行 javac提高兼容性 - <fork>true</fork> 表示在单独的进程中执行 javac提高兼容性
--> -->
@ -45,7 +45,7 @@
</plugin> </plugin>
<!-- <!--
Jar 打包插件 Jar 打包插件:
- 使用 maven-jar-plugin 将编译产物打包成可执行 JAR - 使用 maven-jar-plugin 将编译产物打包成可执行 JAR
- 在 MANIFEST 中指定主类,支持命令行直接 java -jar 调用 - 在 MANIFEST 中指定主类,支持命令行直接 java -jar 调用
--> -->
@ -71,7 +71,7 @@
<profiles> <profiles>
<!-- <!--
原生镜像构建Linux 平台 原生镜像构建: Linux 平台
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件 - 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
- 依赖 musl libc需提前安装并配置 musl-gcc 工具链 - 依赖 musl libc需提前安装并配置 musl-gcc 工具链
--> -->
@ -133,7 +133,7 @@
</profile> </profile>
<!-- <!--
原生镜像构建Windows 平台 原生镜像构建: Windows 平台
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件 - 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
- Windows 上不使用 musl因此不配置静态链接 - Windows 上不使用 musl因此不配置静态链接
--> -->

View File

@ -4,6 +4,8 @@ import org.jcnc.snow.cli.api.CLICommand;
import org.jcnc.snow.cli.commands.*; import org.jcnc.snow.cli.commands.*;
import org.jcnc.snow.cli.utils.CLIUtils; import org.jcnc.snow.cli.utils.CLIUtils;
import org.jcnc.snow.cli.utils.VersionUtils; import org.jcnc.snow.cli.utils.VersionUtils;
import org.jcnc.snow.common.Mode;
import org.jcnc.snow.common.SnowConfig;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;

View File

@ -13,13 +13,13 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
* CLI 命令构建当前项目包含依赖解析编译打包 * CLI 命令: 构建当前项目包含依赖解析编译打包
* <p> * <p>
* 该命令会依次执行依赖解析源码编译和产物打包阶段 * 该命令会依次执行依赖解析源码编译和产物打包阶段
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow build * $ snow build
* </pre> * </pre>
*/ */

View File

@ -6,13 +6,13 @@ import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
import org.jcnc.snow.pkg.tasks.CleanTask; import org.jcnc.snow.pkg.tasks.CleanTask;
/** /**
* CLI 命令清理构建输出和本地缓存目录 * CLI 命令: 清理构建输出和本地缓存目录
* <p> * <p>
* 用于清除项目生成的 builddist 等中间产物保持工作区整洁 * 用于清除项目生成的 builddist 等中间产物保持工作区整洁
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow clean * $ snow clean
* </pre> * </pre>
*/ */

View File

@ -13,17 +13,17 @@ import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* CLI 命令编译当前项目 * CLI 命令: 编译当前项目
* *
* <p>工作模式说明</p> * <p>工作模式说明: </p>
* <ul> * <ul>
* <li><strong>Cloud 模式</strong> * <li><strong>Cloud 模式</strong>
* - 项目根目录存在 {@code project.cloud} 时触发 * - 项目根目录存在 {@code project.cloud} 时触发
* - 解析 build 区块自动推导源码目录与输出文件名 * - 解析 build 区块自动推导源码目录与输出文件名
* - 用法{@code snow compile [run]}</li> * - 用法: {@code snow compile [run]}</li>
* <li><strong>Local 模式</strong> * <li><strong>Local 模式</strong>
* - 未检测到 {@code project.cloud} 时回退 * - 未检测到 {@code project.cloud} 时回退
* - 保持向后兼容{@code snow compile [run] [-o <name>] [-d <srcDir>] [file.snow ]}</li> * - 保持向后兼容: {@code snow compile [run] [-o <name>] [-d <srcDir>] [file.snow ]}</li>
* </ul> * </ul>
* *
* <p>两种模式均将最终参数交由 {@link CompileTask} 处理</p> * <p>两种模式均将最终参数交由 {@link CompileTask} 处理</p>
@ -60,19 +60,19 @@ public final class CompileCommand implements CLICommand {
List<String> argList = new ArrayList<>(); List<String> argList = new ArrayList<>();
// 保留用户在 cloud 模式下传入的 run 标志 // 保留用户在 cloud 模式下传入的 run / -debug 标志
for (String a : args) { for (String a : args) {
if ("run".equals(a)) { if ("run".equals(a) || "-debug".equals(a)) {
argList.add("run"); argList.add(a);
} }
} }
/* 源码目录build.srcDir -> 默认 src */ /* 源码目录: build.srcDir -> 默认 src */
String srcDir = project.getBuild().get("srcDir", "src"); String srcDir = project.getBuild().get("srcDir", "src");
argList.add("-d"); argList.add("-d");
argList.add(srcDir); argList.add(srcDir);
/* 输出名称build.output -> fallback to artifact */ /* 输出名称: build.output -> fallback to artifact */
String output = project.getBuild().get("output", project.getArtifact()); String output = project.getBuild().get("output", project.getArtifact());
argList.add("-o"); argList.add("-o");
argList.add(output); argList.add(output);

View File

@ -12,19 +12,19 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
* CLI 命令根据 project.cloud 生成项目目录结构 * CLI 命令: 根据 project.cloud 生成项目目录结构
* <p> * <p>
* 负责解析云项目描述文件并通过 {@link GenerateTask} * 负责解析云项目描述文件并通过 {@link GenerateTask}
* INIT 生命周期阶段内生成基础目录结构 * INIT 生命周期阶段内生成基础目录结构
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow generate * $ snow generate
* </pre> * </pre>
* *
* <p> * <p>
* 注意事项 * 注意事项:
* - 若当前目录不存在 project.cloud则提示用户先执行 `snow init` * - 若当前目录不存在 project.cloud则提示用户先执行 `snow init`
* - 执行成功后会输出已创建的目录/文件 * - 执行成功后会输出已创建的目录/文件
* </p> * </p>

View File

@ -8,13 +8,13 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
* CLI 命令初始化项目配置文件 * CLI 命令: 初始化项目配置文件
* <p> * <p>
* 用于快速生成 DSL 配置文件project.cloud * 用于快速生成 DSL 配置文件project.cloud
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow init * $ snow init
* </pre> * </pre>
*/ */

View File

@ -8,13 +8,13 @@ import org.jcnc.snow.pkg.resolver.DependencyResolver;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
* CLI 命令解析并下载项目依赖到本地缓存 * CLI 命令: 解析并下载项目依赖到本地缓存
* <p> * <p>
* 适用于离线使用和依赖预热场景会自动读取项目描述文件并处理依赖缓存 * 适用于离线使用和依赖预热场景会自动读取项目描述文件并处理依赖缓存
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow install * $ snow install
* </pre> * </pre>
*/ */

View File

@ -10,14 +10,14 @@ import org.jcnc.snow.pkg.tasks.PublishTask;
import java.nio.file.Paths; import java.nio.file.Paths;
/** /**
* CLI 命令将已构建的项目包发布到远程仓库 * CLI 命令: 将已构建的项目包发布到远程仓库
* <p> * <p>
* 用于持续集成交付或分发场景 * 用于持续集成交付或分发场景
* 支持自动读取 DSL 项目描述文件并注册和执行发布生命周期阶段的任务 * 支持自动读取 DSL 项目描述文件并注册和执行发布生命周期阶段的任务
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow publish * $ snow publish
* </pre> * </pre>
*/ */

View File

@ -4,14 +4,14 @@ import org.jcnc.snow.cli.api.CLICommand;
import org.jcnc.snow.pkg.tasks.RunTask; import org.jcnc.snow.pkg.tasks.RunTask;
/** /**
* CLI 命令运行已编译的 VM 字节码文件.water * CLI 命令: 运行已编译的 VM 字节码文件.water
* <p> * <p>
* 仅解析参数并委托给 {@link RunTask} * 仅解析参数并委托给 {@link RunTask}
* VM 运行逻辑下沉至 pkg 保持 CLI 无状态薄封装 * VM 运行逻辑下沉至 pkg 保持 CLI 无状态薄封装
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow run main.water * $ snow run main.water
* </pre> * </pre>
*/ */

View File

@ -4,13 +4,13 @@ import org.jcnc.snow.cli.SnowCLI;
import org.jcnc.snow.cli.api.CLICommand; import org.jcnc.snow.cli.api.CLICommand;
/** /**
* CLI 子命令输出当前 Snow 工具的版本号 * CLI 子命令: 输出当前 Snow 工具的版本号
* <p> * <p>
* 用于显示当前 CLI 工具版本便于诊断升级兼容性确认等场景 * 用于显示当前 CLI 工具版本便于诊断升级兼容性确认等场景
* </p> * </p>
* *
* <pre> * <pre>
* 用法示例 * 用法示例:
* $ snow version * $ snow version
* </pre> * </pre>
*/ */

View File

@ -26,12 +26,21 @@ public class CLIUtils {
"-v", "--version" "-v", "--version"
); );
/**
* 全局调试标志集合支持 "-debug""--debug"
*/
public static final Set<String> GLOBAL_DEBUG_FLAGS = Set.of(
"--debug"
);
/** /**
* 全局选项列表包括帮助和版本选项的描述 * 全局选项列表包括帮助和版本选项的描述
*/ */
public static final List<Option> GLOBAL_OPTIONS = List.of( public static final List<Option> GLOBAL_OPTIONS = List.of(
new Option(List.of("-h", "--help"), "Show this help message and exit"), new Option(List.of("-h", "--help"), "Show this help message and exit"),
new Option(List.of("-v", "--version"), "Print snow programming language version and exit") new Option(List.of("-v", "--version"), "Print snow programming language version and exit"),
new Option(List.of("-debug", "--debug"), "Enable debug mode with verbose internal logs")
); );
/** /**

View File

@ -0,0 +1,20 @@
package org.jcnc.snow.common;
/**
* 程序的运行/调试模式枚举
* <ul>
* <li>RUN运行模式</li>
* <li>DEBUG调试模式</li>
* </ul>
*/
public enum Mode {
/**
* 运行模式
*/
RUN,
/**
* 调试模式
*/
DEBUG
}

View File

@ -0,0 +1,58 @@
package org.jcnc.snow.common;
/**
* 全局编译/运行配置和调试输出工具类
* <p>
* 用于统一设置程序的运行模式并在调试模式下输出日志信息
* </p>
*/
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;
}
}

View File

@ -15,7 +15,7 @@ import java.util.Map;
* 各虚拟寄存器实际对应的物理寄存器或栈槽号采用简单的线性扫描分配策略 * 各虚拟寄存器实际对应的物理寄存器或栈槽号采用简单的线性扫描分配策略
* </p> * </p>
* <p> * <p>
* 分配过程如下 * 分配过程如下:
* <ol> * <ol>
* <li>优先为函数参数分配槽号 0 开始按参数顺序递增</li> * <li>优先为函数参数分配槽号 0 开始按参数顺序递增</li>
* <li>遍历函数体的每条指令为尚未分配的目标寄存器及其操作数分配新的槽号</li> * <li>遍历函数体的每条指令为尚未分配的目标寄存器及其操作数分配新的槽号</li>
@ -28,8 +28,8 @@ public final class RegisterAllocator {
/** /**
* 虚拟寄存器到槽号的分配映射表 * 虚拟寄存器到槽号的分配映射表
* <p> * <p>
* 虚拟寄存器 {@link IRVirtualRegister} * : 虚拟寄存器 {@link IRVirtualRegister}
* 对应分配的槽编号 {@link Integer} * : 对应分配的槽编号 {@link Integer}
* </p> * </p>
*/ */
private final Map<IRVirtualRegister, Integer> map = new HashMap<>(); private final Map<IRVirtualRegister, Integer> map = new HashMap<>();
@ -37,7 +37,7 @@ public final class RegisterAllocator {
/** /**
* 为指定 IR 函数分配所有虚拟寄存器的槽号 * 为指定 IR 函数分配所有虚拟寄存器的槽号
* <p> * <p>
* 分配顺序说明 * 分配顺序说明:
* <ol> * <ol>
* <li>首先为所有参数分配槽号</li> * <li>首先为所有参数分配槽号</li>
* <li>然后线性遍历函数体为每个指令涉及的虚拟寄存器目标或操作数分配槽号 * <li>然后线性遍历函数体为每个指令涉及的虚拟寄存器目标或操作数分配槽号

View File

@ -1,6 +1,7 @@
package org.jcnc.snow.compiler.backend.builder; package org.jcnc.snow.compiler.backend.builder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator; 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.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRInstruction; import org.jcnc.snow.compiler.ir.core.IRInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
@ -16,7 +17,7 @@ import java.util.stream.Collectors;
* 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成 * 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成
* </p> * </p>
* <p> * <p>
* 工作流程简述 * 工作流程简述:
* <ol> * <ol>
* <li>接收一组已注册的 IR 指令生成器并建立类型到生成器的映射表</li> * <li>接收一组已注册的 IR 指令生成器并建立类型到生成器的映射表</li>
* <li>遍历 IR 函数体的每条指令根据类型找到对应的生成器调用其 generate 方法生成 VM 指令</li> * <li>遍历 IR 函数体的每条指令根据类型找到对应的生成器调用其 generate 方法生成 VM 指令</li>
@ -28,8 +29,8 @@ public final class VMCodeGenerator {
/** /**
* 指令类型到生成器的注册表调度表 * 指令类型到生成器的注册表调度表
* <p> * <p>
* IR 指令类型Class对象 * : IR 指令类型Class对象
* 对应的指令生成器实例 * : 对应的指令生成器实例
* </p> * </p>
*/ */
private final Map<Class<? extends IRInstruction>, InstructionGenerator<? extends IRInstruction>> registry; private final Map<Class<? extends IRInstruction>, InstructionGenerator<? extends IRInstruction>> registry;
@ -74,18 +75,26 @@ public final class VMCodeGenerator {
*/ */
public void generate(IRFunction fn) { public void generate(IRFunction fn) {
this.currentFn = fn.name(); this.currentFn = fn.name();
out.beginFunction(currentFn); // 输出函数起始
/* 登记函数入口地址 —— 解决 CALL 未解析符号问题 */
out.beginFunction(currentFn);
/* 逐条分发 IR 指令给对应的生成器 */
for (IRInstruction ins : fn.body()) { for (IRInstruction ins : fn.body()) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// 取得与当前 IR 指令类型匹配的生成器泛型强转消除类型警告
InstructionGenerator<IRInstruction> gen = InstructionGenerator<IRInstruction> gen =
(InstructionGenerator<IRInstruction>) registry.get(ins.getClass()); (InstructionGenerator<IRInstruction>) registry.get(ins.getClass());
if (gen == null) { if (gen == null) {
throw new IllegalStateException("Unsupported IR: " + ins); throw new IllegalStateException("Unsupported IR: " + ins);
} }
// 通过多态分发到实际生成器
gen.generate(ins, out, slotMap, currentFn); gen.generate(ins, out, slotMap, currentFn);
} }
out.endFunction(); // 输出函数结束
/* 强制补上函数结尾的返回/终止指令 */
String retOpcode = "main".equals(currentFn) ? "HALT" : "RET";
out.emit(OpHelper.opcode(retOpcode));
/* 结束函数 */
out.endFunction();
} }
} }

View File

@ -5,7 +5,7 @@ import org.jcnc.snow.vm.engine.VMOpCode;
import java.util.*; import java.util.*;
/** /**
* VMProgramBuilder构建线性 VM 程序即按顺序存放所有 VM 指令 * VMProgramBuilder: 构建线性 VM 程序即按顺序存放所有 VM 指令
* <p> * <p>
* 本类用于编译器后端将所有生成的 VM 指令包括分支和调用指令统一存储管理 * 本类用于编译器后端将所有生成的 VM 指令包括分支和调用指令统一存储管理
* 支持符号如函数入口标签地址的延迟解析与回填fix-up机制 * 支持符号如函数入口标签地址的延迟解析与回填fix-up机制
@ -22,7 +22,7 @@ public final class VMProgramBuilder {
/** 未解析目标的分支指令JUMP/IC_* 等待修补) */ /** 未解析目标的分支指令JUMP/IC_* 等待修补) */
private record BranchFix(int index, String label) {} private record BranchFix(int index, String label) {}
/** 占位符用于表示尚未确定的符号地址 */ /** 占位符: 用于表示尚未确定的符号地址 */
private static final String PLACEHOLDER = "-1"; private static final String PLACEHOLDER = "-1";
/** 按顺序存放的 VM 指令文本 */ /** 按顺序存放的 VM 指令文本 */
@ -102,7 +102,7 @@ public final class VMProgramBuilder {
/** /**
* 生成 CALL 指令 * 生成 CALL 指令
* 支持延迟修补若目标已知直接写入地址否则写入占位并登记 fix-up * 支持延迟修补: 若目标已知直接写入地址否则写入占位并登记 fix-up
* @param target 目标函数名 * @param target 目标函数名
* @param nArgs 参数个数 * @param nArgs 参数个数
*/ */

View File

@ -5,22 +5,22 @@
## 项目简介 ## 项目简介
**后端模块Backend** 是 [Snow 编译器]() 的核心组成部分之一承接中间表示IR与运行时虚拟机VM之间的桥梁。 **后端模块Backend** 是 [Snow 编译器]() 的核心组成部分之一承接中间表示IR与运行时虚拟机VM之间的桥梁。
它主要完成以下工作 它主要完成以下工作:
1. **寄存器分配**将 IR 中的虚拟寄存器映射为物理槽号或栈槽; 1. **寄存器分配**: 将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
2. **指令生成与调度**为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本; 2. **指令生成与调度**: 为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
3. **程序构建**管理函数入口、标签定义、延迟修补fix-upCALL/JUMP 等控制流指令地址; 3. **程序构建**: 管理函数入口、标签定义、延迟修补fix-upCALL/JUMP 等控制流指令地址;
4. **操作码与常量映射**提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。 4. **操作码与常量映射**: 提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
后端模块设计注重可扩展性各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。 后端模块设计注重可扩展性: 各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
## 核心功能 ## 核心功能
* **线性扫描寄存器分配**`RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。 * **线性扫描寄存器分配**: `RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。
* **指令生成器体系**`InstructionGenerator<T>` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。 * **指令生成器体系**: `InstructionGenerator<T>` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。
* **生成器调度**`VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。 * **生成器调度**: `VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。
* **程序构建与延迟修补**`VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。 * **程序构建与延迟修补**: `VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。
* **操作码与常量映射**`IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量并根据值类型I/L/F…选择合适的 PUSH/STORE 操作码。 * **操作码与常量映射**: `IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量并根据值类型I/L/F…选择合适的 PUSH/STORE 操作码。
## 模块结构 ## 模块结构
@ -51,6 +51,6 @@ backend/
* JDK 24 或更高版本 * JDK 24 或更高版本
* Maven 构建管理 * Maven 构建管理
* 推荐 IDEIntelliJ IDEA * 推荐 IDE: IntelliJ IDEA
--- ---

View File

@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* 并自动进行类型提升 * 并自动进行类型提升
* 同时实现 "+0 → MOV" Peephole 优化避免多余的 PUSH/ADD 序列 * 同时实现 "+0 → MOV" Peephole 优化避免多余的 PUSH/ADD 序列
* </p> * </p>
* <p>类型提升优先级D &gt; F &gt; L &gt; I &gt; S &gt; B</p> * <p>类型提升优先级: D &gt; F &gt; L &gt; I &gt; S &gt; B</p>
*/ */
public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationInstruction> { public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationInstruction> {
@ -143,11 +143,11 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
// 条件跳转成立 lblTrue // 条件跳转成立 lblTrue
out.emitBranch(branchOp, lblTrue); out.emitBranch(branchOp, lblTrue);
// 不成立 0 // 不成立: 0
out.emit(OpHelper.opcode("I_PUSH") + " 0"); out.emit(OpHelper.opcode("I_PUSH") + " 0");
out.emitBranch(OpHelper.opcode("JUMP"), lblEnd); out.emitBranch(OpHelper.opcode("JUMP"), lblEnd);
// 成立分支 1 // 成立分支: 1
out.emit(lblTrue + ":"); out.emit(lblTrue + ":");
out.emit(OpHelper.opcode("I_PUSH") + " 1"); out.emit(OpHelper.opcode("I_PUSH") + " 1");

View File

@ -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.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.utils.OpHelper; import org.jcnc.snow.compiler.backend.utils.OpHelper;
import org.jcnc.snow.compiler.ir.common.GlobalFunctionTable; 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.instruction.CallInstruction;
import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; 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 指令 * <b>CallGenerator - IR {@code CallInstruction} 生成 VM 指令</b>
*
* <p>
* 本类负责将中间表示IR中的函数调用指令 {@link CallInstruction} 转换为虚拟机VM指令
* 支持普通函数调用和特殊的 syscall 指令转换
* </p>
*
* <p>
* <b>能力说明</b>
* <ul>
* <li>支持识别 {@code IRConstant} 直接字面量或已绑定到虚拟寄存器的字符串常量直接降级为 {@code SYSCALL &lt;SUBCMD&gt;} 指令</li>
* <li>对普通函数完成参数加载调用返回值保存等指令生成</li>
* </ul>
* </p>
*/ */
public class CallGenerator implements InstructionGenerator<CallInstruction> { public class CallGenerator implements InstructionGenerator<CallInstruction> {
/**
* <虚拟寄存器 id, 对应的字符串常量>
* <p>用于记录虚拟寄存器与其绑定字符串常量的映射 {@link LoadConstGenerator} 在编译期间填充</p>
*/
private static final Map<Integer, String> STRING_CONST_POOL = new HashMap<>();
/**
* 注册字符串常量到虚拟寄存器
* <p> {@link LoadConstGenerator} 在加载字符串常量时调用</p>
*
* @param regId 虚拟寄存器 id
* @param value 字符串常量值
*/
public static void registerStringConst(int regId, String value) {
STRING_CONST_POOL.put(regId, value);
}
/**
* 返回本生成器支持的 IR 指令类型CallInstruction
*/
@Override @Override
public Class<CallInstruction> supportedClass() { public Class<CallInstruction> supportedClass() {
return CallInstruction.class; return CallInstruction.class;
} }
/**
* 生成 VM 指令的主逻辑
*
* @param ins 当前 IR 指令函数调用
* @param out 指令输出构建器
* @param slotMap IR 虚拟寄存器与物理槽位映射
* @param currentFn 当前函数名
*/
@Override @Override
public void generate(CallInstruction ins, public void generate(CallInstruction ins,
VMProgramBuilder out, VMProgramBuilder out,
Map<IRVirtualRegister, Integer> slotMap, Map<IRVirtualRegister, Integer> slotMap,
String currentFn) { String currentFn) {
/* 1. 推断返回值类型(用于非 void 情况下的 I/F/D/L_STORE */ /* ========== 特殊处理 syscall 调用 ========== */
char retType = 'I'; if ("syscall".equals(ins.getFunctionName()) ||
ins.getFunctionName().endsWith(".syscall")) {
List<IRValue> 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()) { if (!ins.getArguments().isEmpty()) {
int firstSlot = slotMap.get((IRVirtualRegister) ins.getArguments().getFirst()); int firstSlot = slotMap.get((IRVirtualRegister) ins.getArguments().getFirst());
retType = out.getSlotType(firstSlot); retType = out.getSlotType(firstSlot);
if (retType == '\0') retType = 'I'; if (retType == '\0') retType = 'I';
} }
/* 2. 依次加载实参 */ // ---------- 2. 加载全部实参 ----------
for (var arg : ins.getArguments()) { for (var arg : ins.getArguments()) {
int slotId = slotMap.get((IRVirtualRegister) arg); int slotId = slotMap.get((IRVirtualRegister) arg);
char t = out.getSlotType(slotId); char t = out.getSlotType(slotId);
if (t == '\0') t = 'I'; if (t == '\0') t = 'I'; // 默认整型
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId); out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
} }
/* 3. 发出 CALL 指令 */ // ---------- 3. 发出 CALL 指令 ----------
out.emitCall(ins.getFunctionName(), ins.getArguments().size()); out.emitCall(ins.getFunctionName(), ins.getArguments().size());
/* 3.5 若被调用函数返回 void则无需保存返回值 */ // ---------- 3.5 如果为 void 返回直接结束 ----------
String rt = GlobalFunctionTable.getReturnType(ins.getFunctionName()); if ("void".equals(GlobalFunctionTable.getReturnType(ins.getFunctionName()))) {
if ("void".equals(rt)) { return;
return; // 直接结束 _STORE
} }
/* 4. 保存返回值到目标槽 */ // ---------- 4. 保存返回值 ----------
int destSlot = slotMap.get(ins.getDest()); int destSlot = slotMap.get(ins.getDest());
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot); out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
out.setSlotType(destSlot, retType); out.setSlotType(destSlot, retType);

View File

@ -47,7 +47,7 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
* </ol> * </ol>
* *
* @param ins IR 条件比较跳转指令 * @param ins IR 条件比较跳转指令
* @param out VMProgramBuilder用于发出 VM 指令 * @param out VMProgramBuilder: 用于发出 VM 指令
* @param slotMap 虚拟寄存器到 VM 槽位的映射表 * @param slotMap 虚拟寄存器到 VM 槽位的映射表
* @param currentFn 当前处理的函数名调试用当前未使用 * @param currentFn 当前处理的函数名调试用当前未使用
*/ */

View File

@ -10,16 +10,18 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map; import java.util.Map;
/** /**
* 常量加载指令生成器 * <b>LoadConstGenerator - IR {@code LoadConstInstruction} 生成 VM 指令</b>
* 该类用于生成将常量加载到虚拟机寄存器的指令包括 PUSH 常量值和 STORE 到指定槽位 *
* 并为每个槽位设置正确的类型前缀 'I', 'L', 'F' * <p>
* 本类负责将 IR 层的常量加载指令 {@link LoadConstInstruction} 转换为对应的虚拟机指令
* 额外支持如果常量类型为 {@code String}会同步登记到
* {@link CallGenerator} 的字符串常量池方便 syscall 降级场景使用
* </p>
*/ */
public class LoadConstGenerator implements InstructionGenerator<LoadConstInstruction> { public class LoadConstGenerator implements InstructionGenerator<LoadConstInstruction> {
/** /**
* 返回本生成器支持的指令类型 LoadConstInstruction * 指定本生成器支持的 IR 指令类型LoadConstInstruction
*
* @return 支持的指令类型的 Class 对象
*/ */
@Override @Override
public Class<LoadConstInstruction> supportedClass() { public Class<LoadConstInstruction> supportedClass() {
@ -27,49 +29,49 @@ public class LoadConstGenerator implements InstructionGenerator<LoadConstInstruc
} }
/** /**
* 生成一条常量加载指令的目标虚拟机代码 * 生成 VM 指令主流程
* *
* @param ins 当前要生成的 LoadConstInstruction 指令 * @param ins 当前常量加载指令
* @param out VMProgramBuilder用于输出生成的虚拟机指令 * @param out 指令输出构建器
* @param slotMap IR 虚拟寄存器到实际槽位编号的映射表 * @param slotMap 虚拟寄存器与物理槽位映射
* @param currentFn 当前函数名如有需要可使用 * @param currentFn 当前函数名
*/ */
@Override @Override
public void generate(LoadConstInstruction ins, public void generate(LoadConstInstruction ins,
VMProgramBuilder out, VMProgramBuilder out,
Map<IRVirtualRegister, Integer> slotMap, Map<IRVirtualRegister, Integer> slotMap,
String currentFn) { String currentFn) {
// 1. 获取常量值第一个操作数必为常量
/* 1. 获取常量值 */
IRConstant constant = (IRConstant) ins.operands().getFirst(); IRConstant constant = (IRConstant) ins.operands().getFirst();
Object value = constant.value(); Object value = constant.value();
// 2. 生成 PUSH 指令将常量值推入操作数栈 /* 2. 生成 PUSH 指令,将常量值入栈 */
// 通过 OpHelper 辅助方法获取合适的数据类型前缀 out.emit(OpHelper.pushOpcodeFor(value) + " " + value);
String pushOp = OpHelper.pushOpcodeFor(value);
out.emit(pushOp + " " + value);
// 3. 生成 STORE 指令将栈顶的值存入对应槽位寄存器 /* 3. STORE 到目标槽位 */
// 同样通过 OpHelper 获取对应类型的 STORE 指令
String storeOp = OpHelper.storeOpcodeFor(value);
// 获取目标虚拟寄存器对应的槽位编号
int slot = slotMap.get(ins.dest()); int slot = slotMap.get(ins.dest());
out.emit(storeOp + " " + slot); out.emit(OpHelper.storeOpcodeFor(value) + " " + slot);
// 4. 根据常量的 Java 类型为槽位设置正确的前缀字符 /* 4. 标记槽位数据类型(用于后续类型推断和 LOAD/STORE 指令选择) */
// 这样在后续类型检查/运行时可用常见前缀如 'I', 'L', 'F', 'D', 'S', 'B'
char prefix = switch (value) { char prefix = switch (value) {
case Integer _ -> 'I'; // 整型 case Integer _ -> 'I'; // 整型
case Long _ -> 'L'; // 长整型 case Long _ -> 'L'; // 长整型
case Short _ -> 'S'; // 短整型 case Short _ -> 'S'; // 短整型
case Byte _ -> 'B'; // 字节型 case Byte _ -> 'B'; // 字节型
case Double _ -> 'D'; // 双精度浮点型 case Double _ -> 'D'; // 双精度
case Float _ -> 'F'; // 单精度浮点型 case Float _ -> 'F'; // 单精度
case Boolean _ -> 'I'; // 布尔作为 0/1 整型存储 case Boolean _ -> 'I'; // 布尔类型用 I 处理
case null, default -> case String _ -> 'R'; // 字符串常量
throw new IllegalStateException("Unknown const type: " + (value != null ? value.getClass() : null)); case null, default -> // 其它类型异常
throw new IllegalStateException("未知的常量类型: "
+ (value != null ? value.getClass() : null));
}; };
// 写入槽位类型映射表
out.setSlotType(slot, prefix); out.setSlotType(slot, prefix);
/* 5. 如果是字符串常量,则登记到 CallGenerator 的常量池,便于 syscall 字符串降级使用 */
if (value instanceof String s) {
CallGenerator.registerStringConst(ins.dest().id(), s);
}
} }
} }

View File

@ -20,8 +20,8 @@ public final class IROpCodeMapper {
/** /**
* IR 操作码到 VM 指令名的静态映射表 * IR 操作码到 VM 指令名的静态映射表
* <ul> * <ul>
* <li>IR 操作码{@link IROpCode} 枚举项</li> * <li>: IR 操作码{@link IROpCode} 枚举项</li>
* <li>对应虚拟机指令名字符串</li> * <li>: 对应虚拟机指令名字符串</li>
* </ul> * </ul>
* 使用 {@link EnumMap}查找和存储高效 * 使用 {@link EnumMap}查找和存储高效
*/ */

View File

@ -167,6 +167,9 @@ public final class OpHelper {
map.put("D2I", Integer.toString(VMOpCode.D2I)); map.put("D2I", Integer.toString(VMOpCode.D2I));
map.put("D2L", Integer.toString(VMOpCode.D2L)); map.put("D2L", Integer.toString(VMOpCode.D2L));
map.put("D2F", Integer.toString(VMOpCode.D2F)); 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("POP", Integer.toString(VMOpCode.POP));
map.put("DUP", Integer.toString(VMOpCode.DUP)); map.put("DUP", Integer.toString(VMOpCode.DUP));
map.put("SWAP", Integer.toString(VMOpCode.SWAP)); map.put("SWAP", Integer.toString(VMOpCode.SWAP));
@ -176,11 +179,19 @@ public final class OpHelper {
map.put("MOV", Integer.toString(VMOpCode.MOV)); map.put("MOV", Integer.toString(VMOpCode.MOV));
map.put("HALT", Integer.toString(VMOpCode.HALT)); map.put("HALT", Integer.toString(VMOpCode.HALT));
map.put("SYSCALL", Integer.toString(VMOpCode.SYSCALL)); 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); OPCODE_MAP = Collections.unmodifiableMap(map);
Map<Integer, String> revmap = new HashMap<>(); // reverse map Map<Integer, String> 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); OPCODE_NAME_MAP = Collections.unmodifiableMap(revmap);
} }
@ -222,11 +233,13 @@ public final class OpHelper {
if (v instanceof Byte) return "B"; if (v instanceof Byte) return "B";
if (v instanceof Double) return "D"; if (v instanceof Double) return "D";
if (v instanceof Float) return "F"; if (v instanceof Float) return "F";
if (v instanceof String) return "R"; //引用类型
throw new IllegalStateException("Unknown const type: " + v.getClass()); throw new IllegalStateException("Unknown const type: " + v.getClass());
} }
/** /**
* 根据 opcode 数值的字符串形式获取指令名 * 根据 opcode 数值的字符串形式获取指令名
*
* @param code 字符串形式的 opcode 数值 * @param code 字符串形式的 opcode 数值
* @return opcode 对应的指令名 * @return opcode 对应的指令名
*/ */
@ -236,6 +249,7 @@ public final class OpHelper {
/** /**
* 根据 opcode 获取指令名 * 根据 opcode 获取指令名
*
* @param code opcode * @param code opcode
* @return opcode 对应的指令名 * @return opcode 对应的指令名
*/ */

View File

@ -1,25 +1,25 @@
package org.jcnc.snow.compiler.backend.utils; package org.jcnc.snow.compiler.backend.utils;
/** /**
* 工具类提供基本数值类型的提升与类型转换辅助功能 * 工具类: 提供基本数值类型的提升与类型转换辅助功能
* <p> * <p>
* 在进行数值类型运算比较等操作时低优先级的类型会被提升为高优先级类型参与运算 * 在进行数值类型运算比较等操作时低优先级的类型会被提升为高优先级类型参与运算
* 例如 int + long 运算int 会被提升为 long最终运算结果类型为 long * 例如 int + long 运算int 会被提升为 long最终运算结果类型为 long
* <p> * <p>
* 类型优先级从高到低依次为 * 类型优先级从高到低依次为:
* Ddouble6 * Ddouble: 6
* Ffloat 5 * Ffloat : 5
* Llong 4 * Llong : 4
* Iint 3 * Iint : 3
* Sshort 2 * Sshort : 2
* Bbyte 1 * Bbyte : 1
* 未识别类型 0 * 未识别类型 : 0
*/ */
public class TypePromoteUtils { public class TypePromoteUtils {
/** /**
* 返回数值类型的宽度优先级数值越大类型越宽 * 返回数值类型的宽度优先级数值越大类型越宽
* 类型及优先级映射如下 * 类型及优先级映射如下:
* Ddouble: 6 * Ddouble: 6
* Ffloat : 5 * Ffloat : 5
* Llong : 4 * Llong : 4
@ -69,8 +69,8 @@ public class TypePromoteUtils {
* 获取类型转换指令名例如 "I2L", "F2D"表示从源类型到目标类型的转换操作 * 获取类型转换指令名例如 "I2L", "F2D"表示从源类型到目标类型的转换操作
* 如果源类型和目标类型相同则返回 null表示无需转换 * 如果源类型和目标类型相同则返回 null表示无需转换
* <p> * <p>
* 支持的类型标记字符包括BbyteSshortIintLlongFfloatDdouble * 支持的类型标记字符包括: BbyteSshortIintLlongFfloatDdouble
* 所有可能的类型转换均已覆盖如下所示 * 所有可能的类型转换均已覆盖如下所示:
* B S/I/L/F/D * B S/I/L/F/D
* S B/I/L/F/D * S B/I/L/F/D
* I B/S/L/F/D * I B/S/L/F/D

View File

@ -5,121 +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.LoadConstInstruction;
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction; import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;
import org.jcnc.snow.compiler.ir.utils.ComparisonUtils; 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.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; 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.*;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import java.util.*; import java.util.*;
/** /**
* <b>表达式构建器</b> * <b>ExpressionBuilder - 表达式 IR 构建器</b>
*
* <p> * <p>
* 该类负责将抽象语法树AST的表达式节点转换为中间表示IR指令和虚拟寄存器 * 负责将 AST 表达式节点递归转换为 IR 虚拟寄存器操作并生成对应的 IR 指令序列
* 是编译器IR生成阶段的核心工具 * 支持字面量标识符二元表达式一元表达式函数调用等多种类型表达式
* <br/> * </p>
* 主要职责包括 *
* <p>
* 主要功能
* <ul> * <ul>
* <li>将数字字面量标识符二元表达式函数调用等AST表达式节点翻译为对应的IR指令序列</li> * <li>将表达式节点映射为虚拟寄存器</li>
* <li>管理并分配虚拟寄存器保证IR操作的数据流正确</li> * <li>为每种表达式类型生成对应 IR 指令</li>
* <li>支持表达式嵌套的递归构建</li>
* <li>支持写入指定目标寄存器避免冗余的 move 指令</li>
* </ul> * </ul>
* <p> * </p>
*/ */
public record ExpressionBuilder(IRContext ctx) { public record ExpressionBuilder(IRContext ctx) {
/** /* ───────────────── 顶层入口 ───────────────── */
* 构建并返回某个表达式节点对应的虚拟寄存器
*
* <p>会根据节点的实际类型分别处理
* <ul>
* <li>数字字面量新建常量寄存器</li>
* <li>布尔字面量生成值为 0 1 的常量寄存器</li>
* <li>标识符查找当前作用域中的寄存器</li>
* <li>二元表达式递归处理子表达式并进行相应运算</li>
* <li>一元运算符
* <ul>
* <li><code>-x</code>取负生成 <code>NEG_I32</code> 指令</li>
* <li>code>!x</code>逻辑非转换为 <code>x == 0</code> 比较指令</li>
* </ul>
* </li>
* <li>函数调用生成对应的Call指令</li>
* <li>其它类型不支持抛出异常</li>
* </ul>
*
* @param expr 要转换的表达式AST节点
* @return 该表达式的计算结果寄存器
* @throws IllegalStateException 如果遇到未定义的标识符或不支持的表达式类型
*/
/**
* 构建任意 AST 表达式节点自动为其分配一个新的虚拟寄存器并返回该寄存器
*
* <p>
* 这是表达式 IR 生成的核心入口它会根据不同的表达式类型进行分派递归构建 IR 指令
* </p>
*
* @param expr 任意 AST 表达式节点
* @return 存储该表达式结果的虚拟寄存器
* @throws IllegalStateException 遇到不支持的表达式类型或未定义标识符
*/
public IRVirtualRegister build(ExpressionNode expr) { public IRVirtualRegister build(ExpressionNode expr) {
return switch (expr) { return switch (expr) {
// 数字字面量 // 数字字面量例如 1233.14
case NumberLiteralNode n -> buildNumberLiteral(n.value()); case NumberLiteralNode n -> buildNumberLiteral(n.value());
// 布尔字面量 // 字符串字面量例如 "abc"
case StringLiteralNode s -> buildStringLiteral(s.value());
// 布尔字面量例如 true / false
case BoolLiteralNode b -> buildBoolLiteral(b.getValue()); case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
// 标识符 // 标识符变量名 ab
case IdentifierNode id -> { case IdentifierNode id -> {
// 查找当前作用域中的变量寄存器
IRVirtualRegister reg = ctx.getScope().lookup(id.name()); IRVirtualRegister reg = ctx.getScope().lookup(id.name());
if (reg == null) if (reg == null)
throw new IllegalStateException("未定义标识符: " + id.name()); throw new IllegalStateException("未定义标识符: " + id.name());
yield reg; yield reg;
} }
// 二元表达式 // 二元表达式 a+b, x==y
case BinaryExpressionNode bin -> buildBinary(bin); case BinaryExpressionNode bin -> buildBinary(bin);
// 函数调用 // 函数/方法调用表达式
case CallExpressionNode call -> buildCall(call); case CallExpressionNode call -> buildCall(call);
case UnaryExpressionNode u -> buildUnary(u); // 一元表达式 -a, !a
case UnaryExpressionNode un -> buildUnary(un);
// 默认分支遇到未知表达式类型则直接抛异常
default -> throw new IllegalStateException( default -> throw new IllegalStateException(
"不支持的表达式类型: " + expr.getClass().getSimpleName()); "不支持的表达式类型: " + 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 * 生成表达式并将其结果直接写入目标寄存器避免冗余的 move 操作
* <p>
* {@link #build(ExpressionNode)}类似但支持目标寄存器复用避免不必要的move
* *
* @param node 表达式AST节点 * <p>
* @param dest 目标寄存器 * 某些简单表达式如字面量变量名可以直接写入目标寄存器复杂表达式则会先 build 到新寄存器 move 到目标寄存器
* @throws IllegalStateException 未定义标识符/不支持的表达式类型时报错 * </p>
*
* @param node 要生成的表达式节点
* @param dest 目标虚拟寄存器用于存储结果
*/ */
public void buildInto(ExpressionNode node, IRVirtualRegister dest) { public void buildInto(ExpressionNode node, IRVirtualRegister dest) {
switch (node) { switch (node) {
// 数字字面量直接加载到目标寄存器 // 数字字面量生成 loadConst 指令写入目标寄存器
case NumberLiteralNode n -> case NumberLiteralNode n ->
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value())); InstructionFactory.loadConstInto(
// 标识符查找并move到目标寄存器 ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
// 字符串字面量生成 loadConst 指令写入目标寄存器
case StringLiteralNode s ->
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 到目标寄存器
case IdentifierNode id -> { case IdentifierNode id -> {
IRVirtualRegister src = ctx.getScope().lookup(id.name()); 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); InstructionFactory.move(ctx, src, dest);
} }
// 二元表达式直接写入目标寄存器
// 二元表达式递归生成并写入目标寄存器
case BinaryExpressionNode bin -> buildBinaryInto(bin, dest); case BinaryExpressionNode bin -> buildBinaryInto(bin, dest);
// 其他表达式先递归生成寄存器再move到目标寄存器
// 其它复杂情况 build 到新寄存器 move 到目标寄存器
default -> { default -> {
IRVirtualRegister tmp = build(node); IRVirtualRegister tmp = build(node);
InstructionFactory.move(ctx, tmp, dest); InstructionFactory.move(ctx, tmp, dest);
@ -127,41 +123,100 @@ public record ExpressionBuilder(IRContext ctx) {
} }
} }
/* ───────────────── 具体表达式类型 ───────────────── */
/** /**
* 构建二元表达式的IR生成新寄存器存储结果 * 一元表达式构建
*
* <p> * <p>
* 先递归构建左右操作数之后根据操作符类别算术或比较决定生成的IR操作码 * 支持算术取负-a逻辑非!a等一元运算符
* 并生成对应的二元运算指令 * </p>
*
* @param un 一元表达式节点
* @return 结果存储的新分配虚拟寄存器
*/
private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
// 递归生成操作数的寄存器
IRVirtualRegister src = build(un.operand());
// 分配目标寄存器
IRVirtualRegister dest = ctx.newRegister();
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());
}
return dest;
}
/**
* 构建函数或方法调用表达式
*
* @param call AST 调用表达式节点
* @return 存储调用结果的虚拟寄存器
*/
private IRVirtualRegister buildCall(CallExpressionNode call) {
// 递归生成所有参数实参对应的寄存器
List<IRVirtualRegister> 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;
}
/**
* 二元表达式构建结果存储到新寄存器
* <br>
* 支持算术位运算与比较==, !=, >, <, ...
* *
* @param bin 二元表达式节点 * @param bin 二元表达式节点
* @return 存放结果的虚拟寄存器 * @return 储表达式结果的虚拟寄存器
*/ */
private IRVirtualRegister buildBinary(BinaryExpressionNode bin) { private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
// 递归生成左右子表达式的寄存器
IRVirtualRegister a = build(bin.left());
IRVirtualRegister b = build(bin.right());
String op = bin.operator(); String op = bin.operator();
IRVirtualRegister left = build(bin.left());
IRVirtualRegister right = build(bin.right());
// 1. 比较运算 // 比较运算符==!=>< 需要生成条件跳转或布尔值寄存器
if (ComparisonUtils.isComparisonOperator(op)) { if (ComparisonUtils.isComparisonOperator(op)) {
return InstructionFactory.binOp( return InstructionFactory.binOp(
ctx, ctx,
// 通过比较工具获得合适的 IR 操作码
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()), ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
left, right); a, b);
} }
// 2. 其他算术 / 逻辑运算 // 其它算术/运算
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right()); IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
if (code == null) throw new IllegalStateException("不支持的运算符: " + op); if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
return InstructionFactory.binOp(ctx, code, left, right); return InstructionFactory.binOp(ctx, code, a, b);
} }
/** /**
* 将二元表达式的结果直接写入指定寄存器dest * 二元表达式构建结果直接写入目标寄存器用于赋值左值等优化场景
* <p>
* 结构与{@link #buildBinary(BinaryExpressionNode)}类似但不会新分配寄存器
* *
* @param bin 二元表达式节点 * @param bin 二元表达式节点
* @param dest 目标寄存器 * @param dest 目标虚拟寄存器
*/ */
private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) { private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) {
IRVirtualRegister a = build(bin.left()); IRVirtualRegister a = build(bin.left());
@ -180,54 +235,44 @@ public record ExpressionBuilder(IRContext ctx) {
} }
} }
/** /* ───────────────── 字面量辅助方法 ───────────────── */
* 处理函数调用表达式生成对应的Call指令和目标寄存器
* <p>
* 支持普通标识符调用和成员调用 mod.func会为每个参数依次生成子表达式的寄存器
*
* @param call 调用表达式AST节点
* @return 返回结果存放的寄存器
*/
private IRVirtualRegister buildCall(CallExpressionNode call) {
// 递归构建所有参数的寄存器
List<IRVirtualRegister> 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分配新寄存器并生成 LoadConst 指令
* <p>
* 会将字符串型字面量 "123", "1.0f"解析为具体的IRConstant
* 并分配一个新的虚拟寄存器来存放该常量
* *
* @param value 字面量字符串 * @param value 字面量文本字符串格式
* @return 放该常量的寄存器 * @return 存储该字面量的寄存器
*/ */
private IRVirtualRegister buildNumberLiteral(String value) { private IRVirtualRegister buildNumberLiteral(String value) {
IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value); IRConstant c = ExpressionUtils.buildNumberConstant(ctx, value);
IRVirtualRegister reg = ctx.newRegister(); IRVirtualRegister r = ctx.newRegister();
ctx.addInstruction(new LoadConstInstruction(reg, constant)); ctx.addInstruction(new LoadConstInstruction(r, c));
return reg; return r;
} }
/** 布尔字面量 → CONST true=1false=0*/ /**
private IRVirtualRegister buildBoolLiteral(boolean value) { * 构建字符串字面量表达式分配新寄存器并生成 LoadConst 指令
IRConstant constant = new IRConstant(value ? 1 : 0); *
IRVirtualRegister reg = ctx.newRegister(); * @param value 字符串内容
ctx.addInstruction(new LoadConstInstruction(reg, constant)); * @return 存储该字符串的寄存器
return reg; */
private IRVirtualRegister buildStringLiteral(String value) {
IRConstant c = new IRConstant(value);
IRVirtualRegister r = ctx.newRegister();
ctx.addInstruction(new LoadConstInstruction(r, c));
return r;
}
/**
* 构建布尔字面量表达式true/false分配新寄存器并生成 LoadConst 指令1 表示 true0 表示 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;
} }
} }

View File

@ -19,7 +19,7 @@ public class FunctionBuilder {
/** /**
* AST 中的 FunctionNode 构建为可执行的 IRFunction * AST 中的 FunctionNode 构建为可执行的 IRFunction
* <p> * <p>
* 构建过程包括 * 构建过程包括:
* <ol> * <ol>
* <li>初始化 IRFunction 实例和上下文</li> * <li>初始化 IRFunction 实例和上下文</li>
* <li>根据函数返回类型设置默认类型后缀便于表达式推断</li> * <li>根据函数返回类型设置默认类型后缀便于表达式推断</li>
@ -37,7 +37,7 @@ public class FunctionBuilder {
GlobalFunctionTable.register(functionNode.name(), functionNode.returnType()); GlobalFunctionTable.register(functionNode.name(), functionNode.returnType());
// 0) 基本初始化创建 IRFunction 实例与对应上下文 // 0) 基本初始化: 创建 IRFunction 实例与对应上下文
IRFunction irFunction = new IRFunction(functionNode.name()); IRFunction irFunction = new IRFunction(functionNode.name());
IRContext irContext = new IRContext(irFunction); IRContext irContext = new IRContext(irFunction);
@ -53,14 +53,14 @@ public class FunctionBuilder {
ExpressionUtils.setDefaultSuffix(_returnSuffix); ExpressionUtils.setDefaultSuffix(_returnSuffix);
try { try {
// 2) 声明形参为每个参数分配虚拟寄存器并声明到作用域 // 2) 声明形参: 为每个参数分配虚拟寄存器并声明到作用域
for (ParameterNode p : functionNode.parameters()) { for (ParameterNode p : functionNode.parameters()) {
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器 IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
irContext.getScope().declare(p.name(), p.type(), reg); // 变量名寄存器绑定 irContext.getScope().declare(p.name(), p.type(), reg); // 变量名寄存器绑定
irFunction.addParameter(reg); // 添加到函数参数列表 irFunction.addParameter(reg); // 添加到函数参数列表
} }
// 3) 生成函数体 IR遍历每条语句逐一转化 // 3) 生成函数体 IR: 遍历每条语句逐一转化
StatementBuilder stmtBuilder = new StatementBuilder(irContext); StatementBuilder stmtBuilder = new StatementBuilder(irContext);
for (StatementNode stmt : functionNode.body()) { for (StatementNode stmt : functionNode.body()) {
stmtBuilder.build(stmt); stmtBuilder.build(stmt);

View File

@ -9,7 +9,7 @@ import java.util.Map;
/** /**
* IRBuilderScope 用于管理单个函数内变量名与虚拟寄存器的映射关系 * IRBuilderScope 用于管理单个函数内变量名与虚拟寄存器的映射关系
* *
* <p>主要功能包括 * <p>主要功能包括:
* <ul> * <ul>
* <li>维护在当前作用域中已声明变量的寄存器分配信息</li> * <li>维护在当前作用域中已声明变量的寄存器分配信息</li>
* <li>支持将已有虚拟寄存器与变量名重新绑定</li> * <li>支持将已有虚拟寄存器与变量名重新绑定</li>

View File

@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
* 以及与之配套的作用域管理IRBuilderScope * 以及与之配套的作用域管理IRBuilderScope
* 并简化虚拟寄存器分配与 IR 指令添加操作 * 并简化虚拟寄存器分配与 IR 指令添加操作
* *
* <p>本类提供以下核心功能 * <p>本类提供以下核心功能:
* <ul> * <ul>
* <li>持有并操作当前 IRFunction 对象</li> * <li>持有并操作当前 IRFunction 对象</li>
* <li>管理变量名与虚拟寄存器的映射关系</li> * <li>管理变量名与虚拟寄存器的映射关系</li>
@ -62,7 +62,7 @@ public class IRContext {
/** /**
* 获取当前函数的变量与寄存器映射作用域 * 获取当前函数的变量与寄存器映射作用域
* *
* <p>包内可见仅限 builder 包内部使用 * <p>包内可见: 仅限 builder 包内部使用
* *
* @return IRBuilderScope 实例 * @return IRBuilderScope 实例
*/ */

View File

@ -13,7 +13,7 @@ import java.util.List;
/** /**
* 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram * 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram
* *
* <p>主要职责 * <p>主要职责:
* <ul> * <ul>
* <li>遍历输入的顶层节点识别 ModuleNodeFunctionNode 及脚本式顶层 StatementNode</li> * <li>遍历输入的顶层节点识别 ModuleNodeFunctionNode 及脚本式顶层 StatementNode</li>
* <li> ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram</li> * <li> ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram</li>
@ -36,13 +36,13 @@ public final class IRProgramBuilder {
for (Node node : roots) { for (Node node : roots) {
switch (node) { switch (node) {
case ModuleNode moduleNode -> case ModuleNode moduleNode ->
// 模块节点批量构建并添加模块内所有函数 // 模块节点: 批量构建并添加模块内所有函数
moduleNode.functions().forEach(f -> irProgram.add(buildFunction(f))); moduleNode.functions().forEach(f -> irProgram.add(buildFunction(f)));
case FunctionNode functionNode -> case FunctionNode functionNode ->
// 顶层函数节点直接构建并添加 // 顶层函数节点: 直接构建并添加
irProgram.add(buildFunction(functionNode)); irProgram.add(buildFunction(functionNode));
case StatementNode statementNode -> case StatementNode statementNode ->
// 脚本式顶层语句封装为_start函数后构建并添加 // 脚本式顶层语句: 封装为_start函数后构建并添加
irProgram.add(buildFunction(wrapTopLevel(statementNode))); irProgram.add(buildFunction(wrapTopLevel(statementNode)));
default -> default ->
// 严格校验节点类型遇不支持者立即失败 // 严格校验节点类型遇不支持者立即失败
@ -65,7 +65,7 @@ public final class IRProgramBuilder {
/** /**
* 将单个脚本式顶层 StatementNode 封装为名称固定的_start函数节点 * 将单个脚本式顶层 StatementNode 封装为名称固定的_start函数节点
* *
* <p>封装规则 * <p>封装规则:
* <ul> * <ul>
* <li>函数名固定为_start</li> * <li>函数名固定为_start</li>
* <li>返回类型设为 null由后续流程处理</li> * <li>返回类型设为 null由后续流程处理</li>

View File

@ -80,7 +80,7 @@ public class InstructionFactory {
/** /**
* Move 指令src dest若寄存器相同也安全 * Move 指令src dest若寄存器相同也安全
* <p> * <p>
* 实现方式dest = src + 0即加上常量 0 * 实现方式: dest = src + 0即加上常量 0
* </p> * </p>
* *
* @param ctx 当前 IR 上下文 * @param ctx 当前 IR 上下文
@ -92,7 +92,7 @@ public class InstructionFactory {
if (src == dest) { if (src == dest) {
return; return;
} }
// 回退实现dest = src + 0 // 回退实现: dest = src + 0
IRVirtualRegister zero = loadConst(ctx, 0); IRVirtualRegister zero = loadConst(ctx, 0);
ctx.addInstruction(new BinaryOperationInstruction(IROpCode.ADD_I32, dest, src, zero)); ctx.addInstruction(new BinaryOperationInstruction(IROpCode.ADD_I32, dest, src, zero));
} }

View File

@ -150,23 +150,23 @@ public class StatementBuilder {
/** /**
* 构建循环语句for/while * 构建循环语句for/while
* 处理流程初始语句 条件判断 循环体 更新语句 跳回条件 * 处理流程: 初始语句 条件判断 循环体 更新语句 跳回条件
* *
* @param loop 循环节点 * @param loop 循环节点
*/ */
private void buildLoop(LoopNode 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 lblStart = ctx.newLabel();
String lblEnd = ctx.newLabel(); String lblEnd = ctx.newLabel();
// 循环开始标签 // 循环开始标签
InstructionFactory.label(ctx, lblStart); InstructionFactory.label(ctx, lblStart);
// 条件不满足则跳出循环 // 条件不满足则跳出循环
emitConditionalJump(loop.condition(), lblEnd); emitConditionalJump(loop.cond(), lblEnd);
// 构建循环体 // 构建循环体
buildStatements(loop.body()); buildStatements(loop.body());
// 更新部分 for i++ // 更新部分 for i++
if (loop.update() != null) build(loop.update()); if (loop.step() != null) build(loop.step());
// 跳回循环起点 // 跳回循环起点
InstructionFactory.jmp(ctx, lblStart); InstructionFactory.jmp(ctx, lblStart);
@ -176,7 +176,7 @@ public class StatementBuilder {
/** /**
* 构建分支语句if/else * 构建分支语句if/else
* 处理流程条件判断 then 分支 else 分支可选 * 处理流程: 条件判断 then 分支 else 分支可选
* *
* @param ifNode if 语句节点 * @param ifNode if 语句节点
*/ */

View File

@ -22,8 +22,8 @@ public final class GlobalFunctionTable {
/** /**
* 存储全局函数返回类型映射表 * 存储全局函数返回类型映射表
* <ul> * <ul>
* <li>Key函数名不含模块限定</li> * <li>Key: 函数名不含模块限定</li>
* <li>Value返回类型统一转换为小写字符串若无返回值则为 {@code "void"}</li> * <li>Value: 返回类型统一转换为小写字符串若无返回值则为 {@code "void"}</li>
* </ul> * </ul>
*/ */
private static final Map<String, String> RETURN_TYPES = new ConcurrentHashMap<>(); private static final Map<String, String> RETURN_TYPES = new ConcurrentHashMap<>();

View File

@ -112,7 +112,7 @@ public class IRFunction {
} }
/** /**
* 以IR代码表示示例 * 以IR代码表示示例:
* <pre> * <pre>
* func 名称(%0, %1, ...) { * func 名称(%0, %1, ...) {
* 指令0 * 指令0

View File

@ -24,95 +24,95 @@ public enum IROpCode {
CONV_D64_TO_F32, CONV_D64_TO_F32,
/* ───── 算术运算8位整数byte───── */ /* ───── 算术运算8位整数: byte───── */
ADD_B8, // 8位整型加法a = b + c ADD_B8, // 8位整型加法: a = b + c
SUB_B8, // 8位整型减法a = b - c SUB_B8, // 8位整型减法: a = b - c
MUL_B8, // 8位整型乘法a = b * c MUL_B8, // 8位整型乘法: a = b * c
DIV_B8, // 8位整型除法a = b / c DIV_B8, // 8位整型除法: a = b / c
NEG_B8, // 8位整型取负a = -b NEG_B8, // 8位整型取负: a = -b
/* ───── 算术运算16位整数short───── */ /* ───── 算术运算16位整数: short───── */
ADD_S16, // 16位整型加法 ADD_S16, // 16位整型加法
SUB_S16, // 16位整型减法 SUB_S16, // 16位整型减法
MUL_S16, // 16位整型乘法 MUL_S16, // 16位整型乘法
DIV_S16, // 16位整型除法 DIV_S16, // 16位整型除法
NEG_S16, // 16位整型取负 NEG_S16, // 16位整型取负
/* ───── 算术运算32位整数int───── */ /* ───── 算术运算32位整数: int───── */
ADD_I32, // 32位整型加法 ADD_I32, // 32位整型加法
SUB_I32, // 32位整型减法 SUB_I32, // 32位整型减法
MUL_I32, // 32位整型乘法 MUL_I32, // 32位整型乘法
DIV_I32, // 32位整型除法 DIV_I32, // 32位整型除法
NEG_I32, // 32位整型取负 NEG_I32, // 32位整型取负
/* ───── 算术运算64位整数long───── */ /* ───── 算术运算64位整数: long───── */
ADD_L64, // 64位整型加法 ADD_L64, // 64位整型加法
SUB_L64, // 64位整型减法 SUB_L64, // 64位整型减法
MUL_L64, // 64位整型乘法 MUL_L64, // 64位整型乘法
DIV_L64, // 64位整型除法 DIV_L64, // 64位整型除法
NEG_L64, // 64位整型取负 NEG_L64, // 64位整型取负
/* ───── 算术运算32位浮点数float───── */ /* ───── 算术运算32位浮点数: float───── */
ADD_F32, // 32位浮点加法 ADD_F32, // 32位浮点加法
SUB_F32, // 32位浮点减法 SUB_F32, // 32位浮点减法
MUL_F32, // 32位浮点乘法 MUL_F32, // 32位浮点乘法
DIV_F32, // 32位浮点除法 DIV_F32, // 32位浮点除法
NEG_F32, // 32位浮点取负 NEG_F32, // 32位浮点取负
/* ───── 算术运算64位浮点数double───── */ /* ───── 算术运算64位浮点数: double───── */
ADD_D64, // 64位浮点加法 ADD_D64, // 64位浮点加法
SUB_D64, // 64位浮点减法 SUB_D64, // 64位浮点减法
MUL_D64, // 64位浮点乘法 MUL_D64, // 64位浮点乘法
DIV_D64, // 64位浮点除法 DIV_D64, // 64位浮点除法
NEG_D64, // 64位浮点取负 NEG_D64, // 64位浮点取负
/* ───── 逻辑与比较运算指令8位整数byte ───── */ /* ───── 逻辑与比较运算指令8位整数: byte ───── */
CMP_BEQ, // 8位整数相等比较a == b CMP_BEQ, // 8位整数相等比较: a == b
CMP_BNE, // 8位整数不等比较a != b CMP_BNE, // 8位整数不等比较: a != b
CMP_BLT, // 8位整数小于比较a < b CMP_BLT, // 8位整数小于比较: a < b
CMP_BGT, // 8位整数大于比较a > b CMP_BGT, // 8位整数大于比较: a > b
CMP_BLE, // 8位整数小于等于a <= b CMP_BLE, // 8位整数小于等于: a <= b
CMP_BGE, // 8位整数大于等于a >= b CMP_BGE, // 8位整数大于等于: a >= b
/* ───── 逻辑与比较运算指令16位整数int ───── */ /* ───── 逻辑与比较运算指令16位整数: int ───── */
CMP_SEQ, // 16位整数相等比较a == b CMP_SEQ, // 16位整数相等比较: a == b
CMP_SNE, // 16位整数不等比较a != b CMP_SNE, // 16位整数不等比较: a != b
CMP_SLT, // 16位整数小于比较a < b CMP_SLT, // 16位整数小于比较: a < b
CMP_SGT, // 16位整数大于比较a > b CMP_SGT, // 16位整数大于比较: a > b
CMP_SLE, // 16位整数小于等于a <= b CMP_SLE, // 16位整数小于等于: a <= b
CMP_SGE, // 16位整数大于等于a >= b CMP_SGE, // 16位整数大于等于: a >= b
/* ───── 逻辑与比较运算指令32位整数int ───── */ /* ───── 逻辑与比较运算指令32位整数: int ───── */
CMP_IEQ, // 32位整数相等比较a == b CMP_IEQ, // 32位整数相等比较: a == b
CMP_INE, // 32位整数不等比较a != b CMP_INE, // 32位整数不等比较: a != b
CMP_ILT, // 32位整数小于比较a < b CMP_ILT, // 32位整数小于比较: a < b
CMP_IGT, // 32位整数大于比较a > b CMP_IGT, // 32位整数大于比较: a > b
CMP_ILE, // 32位整数小于等于a <= b CMP_ILE, // 32位整数小于等于: a <= b
CMP_IGE, // 32位整数大于等于a >= b CMP_IGE, // 32位整数大于等于: a >= b
/* ───── 逻辑与比较运算指令64位整数long ───── */ /* ───── 逻辑与比较运算指令64位整数: long ───── */
CMP_LEQ, // 64位整数相等比较a == b CMP_LEQ, // 64位整数相等比较: a == b
CMP_LNE, // 64位整数不等比较a != b CMP_LNE, // 64位整数不等比较: a != b
CMP_LLT, // 64位整数小于比较a < b CMP_LLT, // 64位整数小于比较: a < b
CMP_LGT, // 64位整数大于比较a > b CMP_LGT, // 64位整数大于比较: a > b
CMP_LLE, // 64位整数小于等于a <= b CMP_LLE, // 64位整数小于等于: a <= b
CMP_LGE, // 64位整数大于等于a >= b CMP_LGE, // 64位整数大于等于: a >= b
/* ───── 逻辑与比较运算指令32位浮点数float ───── */ /* ───── 逻辑与比较运算指令32位浮点数: float ───── */
CMP_FEQ, // 32位浮点相等比较a == b CMP_FEQ, // 32位浮点相等比较: a == b
CMP_FNE, // 32位浮点不等比较a != b CMP_FNE, // 32位浮点不等比较: a != b
CMP_FLT, // 32位浮点小于比较a < b CMP_FLT, // 32位浮点小于比较: a < b
CMP_FGT, // 32位浮点大于比较a > b CMP_FGT, // 32位浮点大于比较: a > b
CMP_FLE, // 32位浮点小于等于a <= b CMP_FLE, // 32位浮点小于等于: a <= b
CMP_FGE, // 32位浮点大于等于a >= b CMP_FGE, // 32位浮点大于等于: a >= b
/* ───── 逻辑与比较运算指令64位浮点数double ───── */ /* ───── 逻辑与比较运算指令64位浮点数: double ───── */
CMP_DEQ, // 64位浮点相等比较a == b CMP_DEQ, // 64位浮点相等比较: a == b
CMP_DNE, // 64位浮点不等比较a != b CMP_DNE, // 64位浮点不等比较: a != b
CMP_DLT, // 64位浮点小于比较a < b CMP_DLT, // 64位浮点小于比较: a < b
CMP_DGT, // 64位浮点大于比较a > b CMP_DGT, // 64位浮点大于比较: a > b
CMP_DLE, // 64位浮点小于等于a <= b CMP_DLE, // 64位浮点小于等于: a <= b
CMP_DGE, // 64位浮点大于等于a >= b CMP_DGE, // 64位浮点大于等于: a >= b
/* ───── 数据访问与常量操作 ───── */ /* ───── 数据访问与常量操作 ───── */
LOAD, // 从内存加载数据至寄存器 LOAD, // 从内存加载数据至寄存器

View File

@ -11,11 +11,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
* 实现该接口的类型可以作为 {@link IRInstruction} 中的操作数出现 * 实现该接口的类型可以作为 {@link IRInstruction} 中的操作数出现
* </p> * </p>
* *
* <p>当前支持的 IR 值类型包括</p> * <p>当前支持的 IR 值类型包括: </p>
* <ul> * <ul>
* <li>{@link IRVirtualRegister}虚拟寄存器表示计算结果或中间变量</li> * <li>{@link IRVirtualRegister}: 虚拟寄存器表示计算结果或中间变量</li>
* <li>{@link IRConstant}常量值表示不可变的字面量或数值</li> * <li>{@link IRConstant}: 常量值表示不可变的字面量或数值</li>
* <li>{@link IRLabel}标签表示跳转指令的目标地址</li> * <li>{@link IRLabel}: 标签表示跳转指令的目标地址</li>
* </ul> * </ul>
* *
* <p> * <p>

View File

@ -7,12 +7,12 @@ import org.jcnc.snow.compiler.ir.instruction.*;
* <p> * <p>
* 它定义了访问者模式的核心机制通过对每种 {@link IRInstruction} 子类 * 它定义了访问者模式的核心机制通过对每种 {@link IRInstruction} 子类
* 提供独立的 {@code visit} 方法实现对指令的分发与处理 * 提供独立的 {@code visit} 方法实现对指令的分发与处理
* 不同的访问者实现可用于执行不同任务例如 * 不同的访问者实现可用于执行不同任务例如:
* </p> * </p>
* <ul> * <ul>
* <li>{@code IRPrinter}打印指令内容</li> * <li>{@code IRPrinter}: 打印指令内容</li>
* <li>{@code IROptimizer}分析与重写 IR 以优化性能</li> * <li>{@code IROptimizer}: 分析与重写 IR 以优化性能</li>
* <li>{@code IRCodeGenerator}生成平台相关的机器码或汇编代码</li> * <li>{@code IRCodeGenerator}: 生成平台相关的机器码或汇编代码</li>
* </ul> * </ul>
* *
* <p> * <p>

View File

@ -11,27 +11,27 @@ IR 模块以类 SSAStatic Single Assignment形式设计通过统一的
## 核心功能 ## 核心功能
* **统一的中间表示模型**表达控制流与数据流,支持函数、指令、值等核心结构 * **统一的中间表示模型**: 表达控制流与数据流,支持函数、指令、值等核心结构
* **IR 构建器体系**模块化构建函数、表达式与语句 IR简化前端对接 * **IR 构建器体系**: 模块化构建函数、表达式与语句 IR简化前端对接
* **灵活的指令层级结构**支持二元操作、跳转、返回等多种基本指令 * **灵活的指令层级结构**: 支持二元操作、跳转、返回等多种基本指令
* **寄存器与常量模型**统一管理虚拟寄存器、常量、标签等值类型 * **寄存器与常量模型**: 统一管理虚拟寄存器、常量、标签等值类型
* **IR 打印与调试支持**辅助输出 IR 文本格式,支持可视化与调试 * **IR 打印与调试支持**: 辅助输出 IR 文本格式,支持可视化与调试
## 模块结构 ## 模块结构
``` ```
ir/ ir/
├── builder/ // 构建器模块负责构造表达式、函数与语句的 IR ├── builder/ // 构建器模块: 负责构造表达式、函数与语句的 IR
├── core/ // 核心定义IR 基础结构,如函数、指令、程序、访问器等 ├── core/ // 核心定义: IR 基础结构,如函数、指令、程序、访问器等
├── instruction/ // 指令实现具体的 IR 指令类型(如加法、跳转、返回等) ├── instruction/ // 指令实现: 具体的 IR 指令类型(如加法、跳转、返回等)
├── utils/ // 工具模块提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等) ├── utils/ // 工具模块: 提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等)
└── value/ // 值模型常量、标签、虚拟寄存器等 └── value/ // 值模型: 常量、标签、虚拟寄存器等
``` ```
## 开发环境 ## 开发环境
* JDK 24 或更高版本 * JDK 24 或更高版本
* Maven 构建管理 * Maven 构建管理
* 推荐 IDEIntelliJ IDEA * 推荐 IDE: IntelliJ IDEA
--- ---

View File

@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List; import java.util.List;
/** /**
* BinaryOperationInstruction 表示一个二元运算指令格式为dest = lhs OP rhs * BinaryOperationInstruction 表示一个二元运算指令格式为: dest = lhs OP rhs
* <p> * <p>
* 该类用于描述形如 a = b + c a = x * y 的二元运算指令 * 该类用于描述形如 a = b + c a = x * y 的二元运算指令
* 运算类型OP {@link IROpCode} 指定包括加法减法乘法除法等 * 运算类型OP {@link IROpCode} 指定包括加法减法乘法除法等
@ -76,7 +76,7 @@ public final class BinaryOperationInstruction extends IRInstruction {
/** /**
* 转换为字符串格式便于调试与打印 * 转换为字符串格式便于调试与打印
* v1 = ADD_I32 v2, v3 * : v1 = ADD_I32 v2, v3
* *
* @return 指令的字符串表示形式 * @return 指令的字符串表示形式
*/ */

View File

@ -46,7 +46,7 @@ public class CallInstruction extends IRInstruction {
return isVoidReturn() ? null : dest; return isVoidReturn() ? null : dest;
} }
/** 操作数列表void 调用不包含 dest */ /** 操作数列表: void 调用不包含 dest */
@Override @Override
public List<IRValue> operands() { public List<IRValue> operands() {
List<IRValue> ops = new ArrayList<>(); List<IRValue> ops = new ArrayList<>();

View File

@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List; import java.util.List;
/** /**
* IRAddInstruction 表示一个加法指令形如dest = lhs + rhs * IRAddInstruction 表示一个加法指令形如: dest = lhs + rhs
* <p> * <p>
* 本类是一个具体的 IRInstruction 子类表示将两个值相加并将结果写入目标寄存器的操作 * 本类是一个具体的 IRInstruction 子类表示将两个值相加并将结果写入目标寄存器的操作
* 虽然功能与通用的 {@link BinaryOperationInstruction} 类似但它作为更简化明确的指令实现 * 虽然功能与通用的 {@link BinaryOperationInstruction} 类似但它作为更简化明确的指令实现
@ -40,7 +40,7 @@ public class IRAddInstruction extends IRInstruction {
} }
/** /**
* 返回该指令的操作码ADD_I32 * 返回该指令的操作码: ADD_I32
* *
* @return 加法操作码 * @return 加法操作码
*/ */
@ -81,7 +81,7 @@ public class IRAddInstruction extends IRInstruction {
/** /**
* 返回指令的字符串形式方便调试 * 返回指令的字符串形式方便调试
* 例如v1 = v2 + v3 * 例如: v1 = v2 + v3
* *
* @return 字符串表示形式 * @return 字符串表示形式
*/ */

View File

@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.ir.core.IRVisitor;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
/** /**
* 比较 + 条件跳转 复合指令 * 比较 + 条件跳转 复合指令:
* if ( left <cmpOp> right ) jump targetLabel; * if ( left <cmpOp> right ) jump targetLabel;
* <p> * <p>
* 其中 cmpOp 只能是 IROpCode.CMP_* 六种比较操作码 * 其中 cmpOp 只能是 IROpCode.CMP_* 六种比较操作码

View File

@ -25,7 +25,7 @@ public class IRJumpInstruction extends IRInstruction {
} }
/** /**
* 获取该指令对应的操作码JUMP * 获取该指令对应的操作码: JUMP
* *
* @return IROpCode.JUMP * @return IROpCode.JUMP
*/ */
@ -55,7 +55,7 @@ public class IRJumpInstruction extends IRInstruction {
/** /**
* 将指令转为字符串形式便于打印与调试 * 将指令转为字符串形式便于打印与调试
* 例如jump L1 * 例如: jump L1
* *
* @return 指令的字符串表示 * @return 指令的字符串表示
*/ */

View File

@ -29,7 +29,7 @@ public class IRReturnInstruction extends IRInstruction {
} }
/** /**
* 获取该指令的操作码RET * 获取该指令的操作码: RET
* *
* @return IROpCode.RET表示返回操作 * @return IROpCode.RET表示返回操作
*/ */
@ -60,7 +60,7 @@ public class IRReturnInstruction extends IRInstruction {
/** /**
* 转换为字符串形式便于调试与打印 * 转换为字符串形式便于调试与打印
* 示例ret v1 * 示例: ret v1
* *
* @return 字符串形式的返回指令 * @return 字符串形式的返回指令
*/ */

View File

@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List; import java.util.List;
/** /**
* LoadConstInstruction 表示一个常量加载指令格式为dest = CONST k * LoadConstInstruction 表示一个常量加载指令格式为: dest = CONST k
* <p> * <p>
* 该指令的功能是将一个常量字面量或编译期已知值加载到一个虚拟寄存器中 * 该指令的功能是将一个常量字面量或编译期已知值加载到一个虚拟寄存器中
* 供后续指令使用例如在表达式计算参数传递初始化等场景中常用 * 供后续指令使用例如在表达式计算参数传递初始化等场景中常用
@ -66,7 +66,7 @@ public final class LoadConstInstruction extends IRInstruction {
/** /**
* 返回该指令的字符串形式便于调试或打印 * 返回该指令的字符串形式便于调试或打印
* 例如v1 = CONST 42 * 例如: v1 = CONST 42
* *
* @return 指令的字符串表示 * @return 指令的字符串表示
*/ */

View File

@ -9,11 +9,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List; import java.util.List;
/** /**
* ReturnInstruction 表示函数返回指令格式RET RET <value> * ReturnInstruction 表示函数返回指令格式: RET RET <value>
* <p> * <p>
* 此类用于描述函数执行完毕后的返回操作支持两种返回形式 * 此类用于描述函数执行完毕后的返回操作支持两种返回形式:
* - 无返回值void生成无参的 RET 指令 * - 无返回值void: 生成无参的 RET 指令
* - 有返回值将指定虚拟寄存器中的值返回给调用者 * - 有返回值: 将指定虚拟寄存器中的值返回给调用者
* <p> * <p>
* {@link IRReturnInstruction} 类似但更通用适配多种函数返回风格 * {@link IRReturnInstruction} 类似但更通用适配多种函数返回风格
*/ */
@ -36,7 +36,7 @@ public final class ReturnInstruction extends IRInstruction {
} }
/** /**
* 返回该指令的操作码类型RET * 返回该指令的操作码类型: RET
* *
* @return IROpCode.RET * @return IROpCode.RET
*/ */
@ -68,8 +68,8 @@ public final class ReturnInstruction extends IRInstruction {
/** /**
* 转换为字符串形式便于调试与输出 * 转换为字符串形式便于调试与输出
* - 无返回值RET * - 无返回值: RET
* - 有返回值RET v1 * - 有返回值: RET v1
* *
* @return 字符串表示的返回指令 * @return 字符串表示的返回指令
*/ */

View File

@ -9,14 +9,14 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.List; import java.util.List;
/** /**
* UnaryOperationInstruction 表示一个一元运算指令格式dest = OP val * UnaryOperationInstruction 表示一个一元运算指令格式: dest = OP val
* <p> * <p>
* 用于对单个操作数 val 执行指定的一元运算 OP例如取负 NEG * 用于对单个操作数 val 执行指定的一元运算 OP例如取负 NEG
* 并将结果写入目标虚拟寄存器 dest * 并将结果写入目标虚拟寄存器 dest
* <p> * <p>
* 支持的操作由 {@link IROpCode} 定义目前常见的一元操作包括 * 支持的操作由 {@link IROpCode} 定义目前常见的一元操作包括:
* <ul> * <ul>
* <li>NEG_I32 整数取负dest = -val</li> * <li>NEG_I32 整数取负: dest = -val</li>
* <li>可扩展逻辑非按位非等</li> * <li>可扩展逻辑非按位非等</li>
* </ul> * </ul>
*/ */
@ -76,7 +76,7 @@ public final class UnaryOperationInstruction extends IRInstruction {
/** /**
* 将该指令格式化为字符串便于打印与调试 * 将该指令格式化为字符串便于打印与调试
* 形式dest = OP val例如v1 = NEG v2 * 形式: dest = OP val例如: v1 = NEG v2
* *
* @return 字符串形式的指令 * @return 字符串形式的指令
*/ */

View File

@ -16,11 +16,11 @@ import java.util.Map;
* 支持自动类型提升保证 intlongfloatdouble 等类型的比较均能得到正确的 IR 指令 * 支持自动类型提升保证 intlongfloatdouble 等类型的比较均能得到正确的 IR 指令
* </p> * </p>
* *
* 类型判定支持 * 类型判定支持:
* <ul> * <ul>
* <li>字面量后缀支持 B/S/I/L/F/D大小写均可</li> * <li>字面量后缀: 支持 B/S/I/L/F/D大小写均可</li>
* <li>浮点数支持如无后缀但有小数点视为 double</li> * <li>浮点数支持: 如无后缀但有小数点视为 double</li>
* <li>变量类型根据传入变量表推断类型未识别则默认 int</li> * <li>变量类型: 根据传入变量表推断类型未识别则默认 int</li>
* </ul> * </ul>
*/ */
public final class ComparisonUtils { public final class ComparisonUtils {
@ -39,7 +39,7 @@ public final class ComparisonUtils {
} }
/** /**
* 返回类型宽度优先级越大代表类型越宽类型对应的优先级 * 返回类型宽度优先级越大代表类型越宽类型对应的优先级:
* - D (double): 6 * - D (double): 6
* - F (float): 5 * - F (float): 5
* - L (long): 4 * - L (long): 4
@ -106,7 +106,7 @@ public final class ComparisonUtils {
} }
/** /**
* 内部工具方法根据表达式节点和变量表推断类型标记字符 * 内部工具方法: 根据表达式节点和变量表推断类型标记字符
* 字面量支持 B/S/I/L/F/D大小写均可浮点数默认 double * 字面量支持 B/S/I/L/F/D大小写均可浮点数默认 double
* 标识符类型按变量表映射未知则默认 int * 标识符类型按变量表映射未知则默认 int
* *

View File

@ -14,7 +14,7 @@ import java.util.Map;
/** /**
* 表达式分析与操作符选择工具类 * 表达式分析与操作符选择工具类
* <p> * <p>
* 主要功能 * 主要功能:
* - 解析字面量常量自动推断类型 * - 解析字面量常量自动推断类型
* - 自动匹配并选择适合的算术/比较操作码 * - 自动匹配并选择适合的算术/比较操作码
* - 表达式类型的合并与类型提升 * - 表达式类型的合并与类型提升
@ -138,7 +138,7 @@ public final class ExpressionUtils {
} }
/** /**
* 兼容旧逻辑仅凭操作符直接返回 int32 比较指令 * 兼容旧逻辑: 仅凭操作符直接返回 int32 比较指令
* *
* @param op 比较操作符 * @param op 比较操作符
* @return int32 类型的比较操作码 * @return int32 类型的比较操作码
@ -148,7 +148,7 @@ public final class ExpressionUtils {
} }
/** /**
* 推荐调用根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码 * 推荐调用: 根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码
* *
* @param variables 变量名到类型的映射 * @param variables 变量名到类型的映射
* @param op 比较符号 * @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 l 类型后缀1
* @param r 类型后缀2 * @param r 类型后缀2

View File

@ -9,18 +9,18 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
* {@link IRVirtualRegister} 不同常量不需要通过寄存器存储 * {@link IRVirtualRegister} 不同常量不需要通过寄存器存储
* 可直接作为 IR 指令的操作数使用 * 可直接作为 IR 指令的操作数使用
* <p> * <p>
* 典型应用 * 典型应用:
* - 加载常量指令v1 = CONST 42 * - 加载常量指令: v1 = CONST 42
* - 计算表达式v2 = ADD v1, 100 * - 计算表达式: v2 = ADD v1, 100
*/ */
public record IRConstant(Object value) implements IRValue { public record IRConstant(Object value) implements IRValue {
/** /**
* 将常量值转换为字符串用于打印 IR 指令或调试输出 * 将常量值转换为字符串用于打印 IR 指令或调试输出
* <p> * <p>
* 例如 * 例如:
* - 整数常量42 * - 整数常量: 42
* - 字符串常量"hello" * - 字符串常量: "hello"
* *
* @return 常量的字符串表示 * @return 常量的字符串表示
*/ */

View File

@ -8,11 +8,11 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
* IR 系统中虚拟寄存器用于存储每个中间计算结果 SSAStatic Single Assignment形式的核心 * IR 系统中虚拟寄存器用于存储每个中间计算结果 SSAStatic Single Assignment形式的核心
* 每个虚拟寄存器在程序中只被赋值一次其值来源于一条明确的指令输出 * 每个虚拟寄存器在程序中只被赋值一次其值来源于一条明确的指令输出
* <p> * <p>
* 特点 * 特点:
* <ul> * <ul>
* <li>每个寄存器有唯一编号 {@code id} {@code IRFunction.newRegister()} 自动生成</li> * <li>每个寄存器有唯一编号 {@code id} {@code IRFunction.newRegister()} 自动生成</li>
* <li>实现 {@link IRValue} 接口可作为 IRInstruction 的操作数</li> * <li>实现 {@link IRValue} 接口可作为 IRInstruction 的操作数</li>
* <li>具备良好的打印与调试格式%id</li> * <li>具备良好的打印与调试格式: %id</li>
* </ul> * </ul>
* *
* 适用于表达式求值参数传递函数返回值临时变量等所有中间值场景 * 适用于表达式求值参数传递函数返回值临时变量等所有中间值场景
@ -23,7 +23,7 @@ public record IRVirtualRegister(int id) implements IRValue {
/** /**
* 将虚拟寄存器转换为字符串格式方便输出和调试 * 将虚拟寄存器转换为字符串格式方便输出和调试
* 格式为%<id>例如 %3 表示编号为 3 的虚拟寄存器 * 格式为: %<id>例如 %3 表示编号为 3 的虚拟寄存器
* *
* @return 格式化的字符串表示 * @return 格式化的字符串表示
*/ */

View File

@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.lexer.base.TokenScanner;
* {@link TokenScanner} 实现进行词法识别的基础设施 * {@link TokenScanner} 实现进行词法识别的基础设施
* </p> * </p>
* <p> * <p>
* 设计要点 * 设计要点:
* <ul> * <ul>
* <li>构造时统一将 Windows 换行符 (<code>\r\n</code>) 转换为 Unix 风格 (<code>\n</code>)</li> * <li>构造时统一将 Windows 换行符 (<code>\r\n</code>) 转换为 Unix 风格 (<code>\n</code>)</li>
* <li>所有坐标均以 <strong>1</strong> 为起始行列号更贴合人类直觉</li> * <li>所有坐标均以 <strong>1</strong> 为起始行列号更贴合人类直觉</li>

View File

@ -1,5 +1,6 @@
package org.jcnc.snow.compiler.lexer.core; 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.base.TokenScanner;
import org.jcnc.snow.compiler.lexer.scanners.*; import org.jcnc.snow.compiler.lexer.scanners.*;
import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.lexer.token.Token;
@ -10,9 +11,11 @@ import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jcnc.snow.common.SnowConfig.print;
/** /**
* Snow 语言词法分析器核心实现 * Snow 语言词法分析器核心实现
* <p>采用<b>先扫描 后批量校验 统一报告</b>策略 * <p>采用<b>先扫描 后批量校验 统一报告</b>策略:
* <ol> * <ol>
* <li>{@link #scanAllTokens()} 用扫描器链把字符流拆成 {@link Token}</li> * <li>{@link #scanAllTokens()} 用扫描器链把字符流拆成 {@link Token}</li>
* <li>{@link #validateTokens()} 基于 token 序列做轻量上下文校验</li> * <li>{@link #validateTokens()} 基于 token 序列做轻量上下文校验</li>
@ -29,6 +32,7 @@ public class LexerEngine {
/** /**
* 创建并立即执行扫描-校验-报告流程 * 创建并立即执行扫描-校验-报告流程
*
* @param source 源代码文本 * @param source 源代码文本
* @param sourceName 文件名诊断用 * @param sourceName 文件名诊断用
*/ */
@ -52,31 +56,33 @@ public class LexerEngine {
/* 2. 后置整体校验 */ /* 2. 后置整体校验 */
validateTokens(); validateTokens();
/* 3. 打印 token */ /* 3. 打印 token */
if (SnowConfig.isDebug()) {
TokenPrinter.print(tokens); TokenPrinter.print(tokens);
}
/* 4. 统一报告错误 */ /* 4. 统一报告错误 */
report(errors); report(errors);
if (!errors.isEmpty()) {
throw new LexicalException(
"Lexing failed with " + errors.size() + " error(s).",
context.getLine(), context.getCol()
);
}
} }
public static void report(List<LexicalError> errors) { public static void report(List<LexicalError> errors) {
if (errors == null || errors.isEmpty()) { if (errors == null || errors.isEmpty()) {
System.out.println("\n## 词法分析通过,没有发现错误\n"); print("\n## 词法分析通过,没有发现错误\n");
return; return;
} }
System.err.println("\n词法分析发现 " + errors.size() + " 个错误"); System.err.println("\n词法分析发现 " + errors.size() + " 个错误: ");
errors.forEach(e -> System.err.println(" " + e)); errors.forEach(e -> System.err.println("\t" + e));
} }
public List<Token> getAllTokens() { return List.copyOf(tokens); } public List<Token> getAllTokens() {
public List<LexicalError> getErrors() { return List.copyOf(errors); } return List.copyOf(tokens);
}
public List<LexicalError> getErrors() {
return List.copyOf(errors);
}
/** /**
* 逐字符扫描依次尝试各扫描器扫描器抛出的 * 逐字符扫描: 依次尝试各扫描器扫描器抛出的
* {@link LexicalException} 被捕获并转为 {@link LexicalError} * {@link LexicalException} 被捕获并转为 {@link LexicalError}
*/ */
private void scanAllTokens() { private void scanAllTokens() {
@ -93,7 +99,7 @@ public class LexerEngine {
errors.add(new LexicalError( errors.add(new LexicalError(
absPath, le.getLine(), le.getColumn(), le.getReason() absPath, le.getLine(), le.getColumn(), le.getReason()
)); ));
context.advance(); // 跳过问题字符 skipInvalidLexeme();
} }
handled = true; handled = true;
break; break;
@ -105,10 +111,24 @@ public class LexerEngine {
} }
/** /**
* 目前包含三条规则<br> * 跳过当前位置起连续的标识符 / 数字 / 下划线 / 字符
* 1. Dot-Prefix'.' 不能作标识符前缀<br> * <p>这样可以把诸如 {@code 1abc} 的残余 {@code abc}{@code _}
* 2. Declare-Ident declare 后必须紧跟合法标识符并且只能一个<br> * {@code .999} 等一次性忽略避免后续被误识别为新的 token</p>
* 3. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余<br> */
private void skipInvalidLexeme() {
while (!context.isAtEnd()) {
char c = context.peek();
if (Character.isWhitespace(c)) break; // 空白 / 换行
if (!Character.isLetterOrDigit(c)
&& c != '_' && c != '.') break; // 符号分隔
context.advance(); // 否则继续吞掉
}
}
/**
* 目前包含2条规则: <br>
* 1. Declare-Ident declare 后必须紧跟合法标识符并且只能一个<br>
* 2. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余<br>
* <p>发现问题仅写入 {@link #errors}不抛异常</p> * <p>发现问题仅写入 {@link #errors}不抛异常</p>
*/ */
private void validateTokens() { private void validateTokens() {
@ -138,7 +158,9 @@ public class LexerEngine {
} }
} }
/** index 右侧最近非 NEWLINE token无则 null */ /**
* index 右侧最近非 NEWLINE token无则 null
*/
private Token findNextNonNewline(int index) { private Token findNextNonNewline(int index) {
for (int j = index + 1; j < tokens.size(); j++) { for (int j = index + 1; j < tokens.size(); j++) {
Token t = tokens.get(j); Token t = tokens.get(j);
@ -147,8 +169,10 @@ public class LexerEngine {
return null; return null;
} }
/** 构造统一的 LexicalError */ /**
* 构造统一的 LexicalError
*/
private LexicalError err(Token t, String msg) { 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);
} }
} }

View File

@ -1,11 +1,41 @@
package org.jcnc.snow.compiler.lexer.core; package org.jcnc.snow.compiler.lexer.core;
/**
* 表示词法分析过程中发生的错误信息
* <p>
* 该类用于封装词法分析lexical analysis阶段发现的错误包括错误位置文件名行号列号
* 以及错误描述信息便于定位和调试
* </p>
*/
public class LexicalError { public class LexicalError {
/**
* 出错所在的源文件名
*/
private final String file; private final String file;
/**
* 出错所在的行号从1开始
*/
private final int line; private final int line;
/**
* 出错所在的列号从1开始
*/
private final int column; private final int column;
/**
* 错误的详细描述信息
*/
private final String message; 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) { public LexicalError(String file, int line, int column, String message) {
this.file = file; this.file = file;
this.line = line; this.line = line;
@ -13,6 +43,11 @@ public class LexicalError {
this.message = message; this.message = message;
} }
/**
* 以易于阅读的字符串形式返回错误信息
*
* @return 格式化的错误信息字符串包含文件名行号列号和错误描述
*/
@Override @Override
public String toString() { public String toString() {
return file + ": 行 " + line + ", 列 " + column + ": " + message; return file + ": 行 " + line + ", 列 " + column + ": " + message;

Some files were not shown because too many files have changed in this diff Show More