!43 release: 合并 v0.5.0 版本至 main 分支
Merge pull request !43 from Luke/release/v0.5.0
This commit is contained in:
commit
9a4ebaadce
@ -69,7 +69,7 @@ body:
|
||||
attributes:
|
||||
label: 软件版本/分支
|
||||
options:
|
||||
- v0.4.2
|
||||
- v0.5.0
|
||||
- main
|
||||
- dev
|
||||
- 其他
|
||||
|
||||
@ -11,7 +11,7 @@ body:
|
||||
attributes:
|
||||
label: 任务标题
|
||||
description: 简要描述维护内容
|
||||
placeholder: "如:升级 JDK 版本"
|
||||
placeholder: "如: 升级 JDK 版本"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -20,6 +20,6 @@ body:
|
||||
attributes:
|
||||
label: 任务详情
|
||||
description: 描述执行步骤或相关脚本命令
|
||||
placeholder: "如:修改 pom.xml…"
|
||||
placeholder: "如: 修改 pom.xml…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -20,7 +20,7 @@ body:
|
||||
attributes:
|
||||
label: 优化方案
|
||||
description: 详细描述改进思路与实现方式
|
||||
placeholder: "如:缓存机制、算法优化…"
|
||||
placeholder: "如: 缓存机制、算法优化…"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -29,6 +29,6 @@ body:
|
||||
attributes:
|
||||
label: 预期收益
|
||||
description: 描述优化后带来的效益或体验提升
|
||||
placeholder: "如:响应时间缩短 30%…"
|
||||
placeholder: "如: 响应时间缩短 30%…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -32,6 +32,6 @@ body:
|
||||
attributes:
|
||||
label: 修复截止日期
|
||||
description: 填写计划完成的日期 (YYYY-MM-DD)
|
||||
placeholder: "例如:2025-06-20"
|
||||
placeholder: "例如: 2025-06-20"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -20,7 +20,7 @@ body:
|
||||
attributes:
|
||||
label: 已尝试方法
|
||||
description: 列出已尝试过的解决方案或思路
|
||||
placeholder: "如:查阅文档、尝试示例代码…"
|
||||
placeholder: "如: 查阅文档、尝试示例代码…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -29,6 +29,6 @@ body:
|
||||
attributes:
|
||||
label: 期望答案
|
||||
description: 描述希望获得的解答或帮助方向
|
||||
placeholder: "如:最佳实践、配置示例…"
|
||||
placeholder: "如: 最佳实践、配置示例…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -20,7 +20,7 @@ body:
|
||||
attributes:
|
||||
label: 重构原因
|
||||
description: 说明当前存在的痛点或待改进之处
|
||||
placeholder: "如:变量命名不规范、函数职责过多…"
|
||||
placeholder: "如: 变量命名不规范、函数职责过多…"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -29,6 +29,6 @@ body:
|
||||
attributes:
|
||||
label: 预期效果
|
||||
description: 说明重构后带来的好处或验证方式
|
||||
placeholder: "如:提高性能、增强可读性…"
|
||||
placeholder: "如: 提高性能、增强可读性…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
https://gitee.com/jcnc-org/snow/blob/main/doc/Git-Management/Git-Management.md
|
||||
提交 PR 后,请根据实际情况删除不适用的项。
|
||||
|
||||
1. 请在右侧面板中:
|
||||
1. 请在右侧面板中:
|
||||
- 关联 Issue
|
||||
- 选择 PR 类型(bug 修复 / 新功能 / 文档 / 优化 等)
|
||||
- 添加必要的标签和审查人
|
||||
- 请添加里程碑
|
||||
- 如必要请设置优先级
|
||||
|
||||
2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如:
|
||||
2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如:
|
||||
- [x] 已阅读并遵守项目规范
|
||||
- [ ] 本地通过所有测试
|
||||
- [ ] 文档已更新(如有必要)
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,3 +40,4 @@ target/
|
||||
|
||||
### Snow 虚拟机指令 ###
|
||||
*.water
|
||||
/.lingma/
|
||||
|
||||
@ -4,12 +4,6 @@
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<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">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo1 -o target/Demo1" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo1 -o target/Demo1 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo10 -o target/Demo10" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo10 -o target/Demo10 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo11 -o target/Demo11 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo12 -o target/Demo12" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo12 -o target/Demo12 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Demo13" 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/Demo13 -o target/Demo13" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo13 -o target/Demo13 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
10
.run/Demo14.run.xml
Normal file
10
.run/Demo14.run.xml
Normal 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>
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo2 -o target/Demo2" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo2 -o target/Demo2 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo3 -o target/Demo3" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo3 -o target/Demo3 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo4 -o target/Demo4" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo4 -o target/Demo4 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo5 -o target/Demo5" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo5 -o target/Demo5 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo6 -o target/Demo6" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo6 -o target/Demo6 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo7 -o target/Demo7" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo7 -o target/Demo7 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo8 -o target/Demo8" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo8 -o target/Demo8 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,13 +3,7 @@
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo9 -o target/Demo9" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo9 -o target/Demo9 -debug" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,12 +3,6 @@
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<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">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
15
.run/Snow.run.xml
Normal file
15
.run/Snow.run.xml
Normal 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>
|
||||
@ -3,12 +3,6 @@
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<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">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
<toRun name="Demo1" type="Application" />
|
||||
<toRun name="Demo10" type="Application" />
|
||||
<toRun name="Demo11" type="Application" />
|
||||
<toRun name="Demo11" type="Application" />
|
||||
<toRun name="Demo12" type="Application" />
|
||||
<toRun name="Demo13" type="Application" />
|
||||
<toRun name="Demo2" type="Application" />
|
||||
|
||||
400
README.md
400
README.md
@ -11,8 +11,8 @@
|
||||
<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="">
|
||||
</a>
|
||||
<a href="https://gitee.com/jcnc-org/snow/tree/v0.4.2/">
|
||||
<img src="https://img.shields.io/badge/version-v0.4.2-blue" alt="">
|
||||
<a href="https://gitee.com/jcnc-org/snow/tree/v0.5.0/">
|
||||
<img src="https://img.shields.io/badge/version-v0.5.0-blue" alt="">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -53,12 +53,12 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
| 类别 | 关键特性 |
|
||||
|----------|---------------------------------------------------------------------------------------------------|
|
||||
| 语言层 | `module` / `import` / `function` / `loop` / `if–else` / Pratt 表达式解析<br>静态类型检查 & 作用域分析 |
|
||||
| 编译器前端 | **Lexer / Parser / Semantic Analyzer** 全栈自研,生成 JSON-AST |
|
||||
| 语言层 | module / import / function / loop / if–else / Pratt 表达式解析<br>静态类型检查 & 作用域分析 |
|
||||
| 编译器前端 | Lexer / Parser / Semantic Analyzer 全栈自研,生成 JSON-AST |
|
||||
| IR & 后端 | 三地址式 IR ➜ 线性扫描寄存器分配 ➜ SnowVM 指令 |
|
||||
| 虚拟机 | 栈 + 寄存器混合架构、GUI 局部变量监视 |
|
||||
| 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 官网
|
||||
|
||||
@ -69,7 +69,10 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
[https://gitee.com/jcnc-org/snow/releases](https://gitee.com/jcnc-org/snow/releases)
|
||||
|
||||
## 相关文档
|
||||
[Snow-Lang 语法](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
|
||||
[Snow-Lang 指南](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
|
||||
|
||||
[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md)
|
||||
|
||||
|
||||
[Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
|
||||
|
||||
@ -83,11 +86,11 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
## 开发环境安装
|
||||
|
||||
1. **开发环境准备**:
|
||||
1. **开发环境准备**:
|
||||
1. 安装集成开发环境 [IntelliJ IDEA](https://www.jetbrains.com/idea/download)
|
||||
2. 安装 Java 开发工具 [Graalvm-jdk-24](https://www.graalvm.org/downloads/)
|
||||
|
||||
2. **获取源码**:
|
||||
2. **获取源码**:
|
||||
将项目源码下载或克隆到本地目录。
|
||||
```bash
|
||||
git clone https://gitee.com/jcnc-org/snow.git
|
||||
@ -101,7 +104,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
4. **运行成功**
|
||||
|
||||
`````snow
|
||||
`````snow
|
||||
## 编译器输出
|
||||
### Snow 源代码
|
||||
#### Main.snow
|
||||
@ -115,6 +118,59 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
end body
|
||||
end function
|
||||
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
|
||||
module: Math
|
||||
function: add
|
||||
@ -123,121 +179,179 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
declare n2: int
|
||||
return_type: int
|
||||
body:
|
||||
return n1 + n2
|
||||
return n1 + n2
|
||||
end body
|
||||
end function
|
||||
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
|
||||
[
|
||||
{
|
||||
{
|
||||
"type": "Module",
|
||||
"name": "Main",
|
||||
"imports": [
|
||||
{
|
||||
"module": "Math",
|
||||
"type": "Import"
|
||||
}
|
||||
{
|
||||
"type": "Import",
|
||||
"module": "Math"
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
{
|
||||
"type": "Function",
|
||||
"name": "main",
|
||||
"parameters": [
|
||||
|
||||
|
||||
],
|
||||
"returnType": "int",
|
||||
"body": [
|
||||
{
|
||||
{
|
||||
"type": "ExpressionStatement",
|
||||
"expression": {
|
||||
"type": "CallExpression",
|
||||
"callee": {
|
||||
"type": "CallExpression",
|
||||
"callee": {
|
||||
"type": "MemberExpression",
|
||||
"object": {
|
||||
"type": "Identifier",
|
||||
"name": "Math"
|
||||
"type": "Identifier",
|
||||
"name": "Math"
|
||||
},
|
||||
"member": "add"
|
||||
},
|
||||
"arguments": [
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "NumberLiteral",
|
||||
"value": "6"
|
||||
"type": "NumberLiteral",
|
||||
"value": "6"
|
||||
},
|
||||
{
|
||||
"type": "NumberLiteral",
|
||||
"value": "1"
|
||||
"type": "NumberLiteral",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
"type": "Return",
|
||||
"value": {
|
||||
"type": "NumberLiteral",
|
||||
"value": "0"
|
||||
"type": "NumberLiteral",
|
||||
"value": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
"type": "Module",
|
||||
"name": "Math",
|
||||
"imports": [
|
||||
|
||||
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
{
|
||||
"type": "Function",
|
||||
"name": "add",
|
||||
"parameters": [
|
||||
{
|
||||
{
|
||||
"name": "n1",
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
"name": "n2",
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
],
|
||||
"returnType": "int",
|
||||
"body": [
|
||||
{
|
||||
{
|
||||
"type": "Return",
|
||||
"value": {
|
||||
"type": "BinaryExpression",
|
||||
"left": {
|
||||
"type": "BinaryExpression",
|
||||
"left": {
|
||||
"type": "Identifier",
|
||||
"name": "n1"
|
||||
},
|
||||
"operator": "+",
|
||||
"right": {
|
||||
},
|
||||
"operator": "+",
|
||||
"right": {
|
||||
"type": "Identifier",
|
||||
"name": "n2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
### IR
|
||||
func main() {
|
||||
%0 = CONST 6
|
||||
%1 = CONST 1
|
||||
%2 = CALL Math.add, %0, %1
|
||||
%3 = CONST 0
|
||||
RET %3
|
||||
%0 = CONST 6
|
||||
%1 = CONST 1
|
||||
%2 = CALL Math.add, %0, %1
|
||||
%3 = CONST 0
|
||||
RET %3
|
||||
}
|
||||
func add(%0, %1) {
|
||||
%2 = ADD_I32 %0, %1
|
||||
RET %2
|
||||
%2 = ADD_I32 %0, %1
|
||||
RET %2
|
||||
}
|
||||
|
||||
|
||||
|
||||
### VM code
|
||||
0000: I_PUSH 6
|
||||
0001: I_STORE 0
|
||||
@ -245,35 +359,41 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
0003: I_STORE 1
|
||||
0004: I_LOAD 0
|
||||
0005: I_LOAD 1
|
||||
0006: CALL 12 2
|
||||
0006: CALL 13 2
|
||||
0007: I_STORE 2
|
||||
0008: I_PUSH 0
|
||||
0009: I_STORE 3
|
||||
0010: I_LOAD 3
|
||||
0011: HALT
|
||||
0012: I_LOAD 0
|
||||
0013: I_LOAD 1
|
||||
0014: I_ADD
|
||||
0015: I_STORE 2
|
||||
0016: I_LOAD 2
|
||||
0017: RET
|
||||
0012: HALT
|
||||
0013: I_LOAD 0
|
||||
0014: I_LOAD 1
|
||||
0015: I_ADD
|
||||
0016: I_STORE 2
|
||||
0017: I_LOAD 2
|
||||
0018: RET
|
||||
0019: RET
|
||||
Written to D:\Devs\IdeaProjects\Snow\target\Demo1.water
|
||||
|
||||
|
||||
=== Launching VM ===
|
||||
Calling function at address: 12
|
||||
|
||||
Calling function at address: 13
|
||||
|
||||
Return 7
|
||||
|
||||
Process has ended
|
||||
|
||||
Operand Stack state:[0]
|
||||
|
||||
|
||||
--- Call Stack State ---
|
||||
|
||||
|
||||
|
||||
### VM Local Variable Table:
|
||||
0: 6
|
||||
1: 1
|
||||
2: 7
|
||||
3: 0
|
||||
|
||||
=== VM exited ===
|
||||
`````
|
||||
|
||||
## 编译 Snow 源代码
|
||||
@ -282,38 +402,38 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
独立编译不依赖 `.cloud` 文件,而是直接使用 `Snow` 编译器进行 `.snow` 文件的编译和执行。
|
||||
|
||||
#### 独立编译步骤:
|
||||
#### 独立编译步骤:
|
||||
|
||||
1. **运行编译器:**
|
||||
1. **运行编译器:**
|
||||
你可以通过以下命令来编译单个或多个 `.snow` 文件,或者递归编译一个目录中的所有 `.snow` 源文件为`.water`虚拟机指令。
|
||||
|
||||
* **单个文件编译:**
|
||||
* **单个文件编译:**
|
||||
|
||||
```bash
|
||||
Snow complete [SnowCode].snow
|
||||
```
|
||||
|
||||
* **多个文件编译:**
|
||||
* **多个文件编译:**
|
||||
|
||||
```bash
|
||||
Snow complete [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow -o [Name]
|
||||
```
|
||||
|
||||
* **目录递归编译:**
|
||||
* **目录递归编译:**
|
||||
|
||||
```bash
|
||||
Snow -d path/to/source_dir
|
||||
```
|
||||
|
||||
2. **查看编译输出:**
|
||||
编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出:
|
||||
2. **查看编译输出:**
|
||||
编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出:
|
||||
|
||||
* **AST**(抽象语法树)部分以 JSON 格式输出。
|
||||
* **IR**(中间表示)部分会列出逐行的中间代码。
|
||||
* **VM code**(虚拟机指令)会展示虚拟机的字节码指令。
|
||||
|
||||
3. **默认执行模式:**
|
||||
编译器会在 **DEBUG 模式** 下运行,显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。
|
||||
3. **默认执行模式:**
|
||||
编译器会在 **RUN 模式** 下运行,**DEBUG 模式**显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。
|
||||
|
||||
---
|
||||
|
||||
@ -321,30 +441,30 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
集成编译需要使用 `.cloud` 文件来指定项目的配置和结构,适用于项目标准化、依赖管理、构建管理和项目分发等场景。
|
||||
|
||||
#### 集成编译命令:
|
||||
#### 集成编译命令:
|
||||
|
||||
1. **基本用法:**
|
||||
1. **基本用法:**
|
||||
|
||||
```bash
|
||||
snow [OPTIONS] <command>
|
||||
```
|
||||
|
||||
2. **命令选项:**
|
||||
2. **命令选项:**
|
||||
|
||||
* `-h, --help`:显示帮助信息并退出。
|
||||
* `-v, --version`:打印 Snow 编程语言的版本并退出。
|
||||
* `-h, --help`: 显示帮助信息并退出。
|
||||
* `-v, --version`: 打印 Snow 编程语言的版本并退出。
|
||||
|
||||
3. **可用命令:**
|
||||
3. **可用命令:**
|
||||
|
||||
* `compile`:将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。
|
||||
* `clean`:清理构建输出和本地缓存,移除中间产物,释放磁盘空间。
|
||||
* `version`:打印 Snow 的版本。
|
||||
* `run`:运行已编译的虚拟机字节码文件(`.water`)。
|
||||
* `init`:初始化一个新项目,生成 `project.cloud` 文件。
|
||||
* `generate`:根据 `project.cloud` 生成项目目录结构。
|
||||
* `build`:构建当前项目,按顺序解析依赖、编译和打包。
|
||||
* `compile`: 将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。
|
||||
* `clean`: 清理构建输出和本地缓存,移除中间产物,释放磁盘空间。
|
||||
* `version`: 打印 Snow 的版本。
|
||||
* `run`: 运行已编译的虚拟机字节码文件(`.water`)。
|
||||
* `init`: 初始化一个新项目,生成 `project.cloud` 文件。
|
||||
* `generate`: 根据 `project.cloud` 生成项目目录结构。
|
||||
* `build`: 构建当前项目,按顺序解析依赖、编译和打包。
|
||||
|
||||
4. **例如,执行集成编译命令:**
|
||||
4. **例如,执行集成编译命令:**
|
||||
|
||||
```bash
|
||||
snow compile [SnowCode].snow
|
||||
@ -352,14 +472,14 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
* 此命令会使用 `.cloud` 文件中的配置信息来指导编译过程,并生成 `.water`。
|
||||
|
||||
5. **使用帮助:**
|
||||
如果你需要了解某个命令的详细选项,可以使用:
|
||||
5. **使用帮助:**
|
||||
如果你需要了解某个命令的详细选项,可以使用:
|
||||
|
||||
```bash
|
||||
snow <command> --help
|
||||
```
|
||||
|
||||
例如,查看 `compile` 命令的具体选项:
|
||||
例如,查看 `compile` 命令的具体选项:
|
||||
|
||||
```bash
|
||||
snow compile --help
|
||||
@ -369,7 +489,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
## 示例代码片段
|
||||
|
||||
以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法:
|
||||
以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法:
|
||||
|
||||
```snow
|
||||
module: Math
|
||||
@ -388,11 +508,11 @@ module: Math
|
||||
body:
|
||||
declare num1:int = 1
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
declare counter:int = 1
|
||||
condition:
|
||||
cond:
|
||||
counter <= n
|
||||
update:
|
||||
step:
|
||||
counter = counter + 1
|
||||
body:
|
||||
num1 = num1 * counter
|
||||
@ -404,10 +524,10 @@ module: Math
|
||||
end module
|
||||
```
|
||||
|
||||
上述代码定义了一个名为 `Math` 的模块,其中包含两个函数:
|
||||
上述代码定义了一个名为 `Math` 的模块,其中包含两个函数:
|
||||
|
||||
* `main`:不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。
|
||||
* `factorial`:接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个
|
||||
* `main`: 不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。
|
||||
* `factorial`: 接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个
|
||||
`loop` 循环(从 `counter = 1` 到 `counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。
|
||||
|
||||
|
||||
@ -415,53 +535,59 @@ end module
|
||||
|
||||
## 项目结构说明
|
||||
|
||||
* `compiler/`:Snow 编译器源代码目录
|
||||
* `compiler/`: Snow 编译器源代码目录
|
||||
|
||||
* `lexer/`:词法分析模块,负责将源码切分为 Token
|
||||
* `parser/`:语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析)
|
||||
* `semantic/`:语义分析模块,负责符号表管理、类型检查等
|
||||
* `ir/`:中间表示(IR)模块,生成并管理三地址码形式的中间代码
|
||||
* `backend/`:编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
|
||||
* `lexer/`: 词法分析模块,负责将源码切分为 Token
|
||||
* `parser/`: 语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析)
|
||||
* `semantic/`: 语义分析模块,负责符号表管理、类型检查等
|
||||
* `ir/`: 中间表示(IR)模块,生成并管理三地址码形式的中间代码
|
||||
* `backend/`: 编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
|
||||
|
||||
* `vm/`:虚拟机相关源代码目录
|
||||
* `vm/`: 虚拟机相关源代码目录
|
||||
|
||||
* `commands/`:定义 SnowVM 指令集的具体实现
|
||||
* `engine/`:核心执行引擎,提供指令执行和寄存器/栈管理
|
||||
* `execution/`:执行流程控制(按指令顺序执行、分支跳转等)
|
||||
* `io/`:输入输出辅助类(加载指令、文件解析等)
|
||||
* `gui/`:Swing 可视化调试面板,实时展示局部变量表
|
||||
* `factories/`、`utils/`:指令创建、日志调试等公共工具
|
||||
* `commands/`: 定义 SnowVM 指令集的具体实现
|
||||
* `engine/`: 核心执行引擎,提供指令执行和寄存器/栈管理
|
||||
* `execution/`: 执行流程控制(按指令顺序执行、分支跳转等)
|
||||
* `io/`: 输入输出辅助类(加载指令、文件解析等)
|
||||
* `gui/`: Swing 可视化调试面板,实时展示局部变量表
|
||||
* `factories/`、`utils/`: 指令创建、日志调试等公共工具
|
||||
|
||||
* `pkg/`:内置构建与包管理器 **snow pkg**
|
||||
* `pkg/`: 内置构建与包管理器 **snow pkg**
|
||||
|
||||
* `dsl/`:`.cloud` 描述文件解析器
|
||||
* `tasks/`:预设任务实现(`clean · compile · run · package · publish` 等)
|
||||
* `resolver/`:本地/远程仓库解析与缓存
|
||||
* `lifecycle/`:任务生命周期钩子(pre/post 脚本等)
|
||||
* `model/`:项目、依赖、版本等模型
|
||||
* `utils/`:文件、日志、校验和等通用工具
|
||||
* `doc/`:开发者文档与示例 `.cloud` 配置
|
||||
* `dsl/`: `.cloud` 描述文件解析器
|
||||
* `tasks/`: 预设任务实现(`clean · compile · run · package · publish` 等)
|
||||
* `resolver/`: 本地/远程仓库解析与缓存
|
||||
* `lifecycle/`: 任务生命周期钩子(pre/post 脚本等)
|
||||
* `model/`: 项目、依赖、版本等模型
|
||||
* `utils/`: 文件、日志、校验和等通用工具
|
||||
* `doc/`: 开发者文档与示例 `.cloud` 配置
|
||||
|
||||
* `cli/`:独立的命令行前端
|
||||
* `cli/`: 独立的命令行前端
|
||||
|
||||
* `commands/`:`compile` / `run` / `pkg` 等子命令实现
|
||||
* `api/`:公共选项解析、终端交互抽象
|
||||
* `utils/`:终端颜色、进度条、异常格式化等
|
||||
* `SnowCLI.java`:CLI 主入口
|
||||
* `commands/`: `compile` / `run` / `pkg` 等子命令实现
|
||||
* `api/`: 公共选项解析、终端交互抽象
|
||||
* `utils/`: 终端颜色、进度条、异常格式化等
|
||||
* `SnowCLI.java`: CLI 主入口
|
||||
|
||||
|
||||
## 版权声明
|
||||
|
||||
版权所有 © 2025 许轲(Luke),代表 SnowLang 项目。
|
||||
仓库地址:<https://gitee.com/jcnc-org/snow>
|
||||
仓库地址: <https://gitee.com/jcnc-org/snow>
|
||||
本项目依据 [Apache 2.0 许可证](LICENSE) 进行许可和发布。
|
||||
|
||||
“SnowLang 项目”为由许轲(Luke)发起的独立开源项目。
|
||||
未来,项目可能会成立正式的组织或实体,以进一步负责本项目的开发和管理。
|
||||
|
||||
## 支持我们
|
||||
|
||||
如果你喜欢我们的项目,欢迎给我们一个 Star!
|
||||
你们的关注和支持,是我们团队持续进步的动力源泉!谢谢大家!
|
||||
|
||||
|
||||
## 加入我们
|
||||
|
||||
- 微信:`xuxiaolankaka`
|
||||
- QQ:`1399528359`
|
||||
- 邮箱:`luke.k.xu [at] hotmail.com`
|
||||
- 微信: `xuxiaolankaka`
|
||||
- QQ: `1399528359`
|
||||
- 邮箱: `luke.k.xu [at] hotmail.com`
|
||||
|
||||
|
||||
@ -2,27 +2,27 @@
|
||||
|
||||
在执行 `build-project2tar.ps1` 脚本之前,您需要确保 PowerShell 的执行策略允许运行脚本。默认情况下,PowerShell 可能阻止未签名的脚本执行。因此,您需要设置适当的执行策略。
|
||||
|
||||
#### 步骤 1:以管理员身份打开 PowerShell
|
||||
#### 步骤 1: 以管理员身份打开 PowerShell
|
||||
|
||||
* 在 Windows 系统中,搜索 **PowerShell**,右键点击 **Windows PowerShell**,并选择 **以管理员身份运行**。
|
||||
|
||||
#### 步骤 2:设置 PowerShell 执行策略
|
||||
#### 步骤 2: 设置 PowerShell 执行策略
|
||||
|
||||
为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter:
|
||||
为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter:
|
||||
|
||||
```powershell
|
||||
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
|
||||
```
|
||||
|
||||
#### 解释:
|
||||
#### 解释:
|
||||
|
||||
* `-Scope CurrentUser`:此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。
|
||||
* `-ExecutionPolicy RemoteSigned`:此策略表示:
|
||||
* `-Scope CurrentUser`: 此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。
|
||||
* `-ExecutionPolicy RemoteSigned`: 此策略表示:
|
||||
|
||||
* 本地创建的脚本可以直接运行。
|
||||
* 从互联网下载的脚本必须具备有效的数字签名才能运行。没有签名的脚本将无法执行,除非您先解除阻止该脚本。
|
||||
|
||||
#### 步骤 3:运行 `build-project2tar.ps1` 脚本
|
||||
#### 步骤 3: 运行 `build-project2tar.ps1` 脚本
|
||||
|
||||
设置完成后,您可以在 PowerShell 中运行 `build-project2tar.ps1` 脚本。确保您已经切换到包含该脚本的目录,或提供完整的文件路径来执行它。
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ $parentDir = Split-Path -Parent $scriptDir
|
||||
$tarPath = Join-Path $parentDir $tarName
|
||||
|
||||
# 输出开始创建 tar 包的消息
|
||||
Write-Output "开始创建 tar 包:$tarName 到 $parentDir ..."
|
||||
Write-Output "开始创建 tar 包: $tarName 到 $parentDir ..."
|
||||
|
||||
# 如果存在旧 tar 包,先删除它
|
||||
if (Test-Path $tarPath) {
|
||||
@ -26,7 +26,7 @@ if (-not (Get-Command $tarCommand -ErrorAction SilentlyContinue)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 执行打包操作:切换到 org\jcnc 目录下再压缩 snow 文件夹
|
||||
# 执行打包操作: 切换到 org\jcnc 目录下再压缩 snow 文件夹
|
||||
try {
|
||||
# 构建命令并执行
|
||||
$tarCommandArgs = "-cf", $tarPath, "-C", "$scriptDir\..\src\main\java\org\jcnc", "snow"
|
||||
@ -34,7 +34,7 @@ try {
|
||||
|
||||
& $tarCommand @tarCommandArgs
|
||||
} catch {
|
||||
Write-Error "❌ 创建 tar 包失败。错误信息:$_"
|
||||
Write-Error "❌ 创建 tar 包失败。错误信息: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
## 1. 版本控制基础
|
||||
|
||||
本项目使用 Git 进行版本控制,并遵循以下基本原则:
|
||||
本项目使用 Git 进行版本控制,并遵循以下基本原则:
|
||||
|
||||
* 所有代码更改必须通过 Git 提交,并推送至远程仓库。
|
||||
* 每次提交必须包括清晰、简洁且具描述性的提交信息,确保团队成员能够轻松理解变更的目的和内容。
|
||||
@ -10,23 +10,23 @@
|
||||
|
||||
## 2. 分支管理
|
||||
|
||||
本项目采用以下分支策略进行代码管理:
|
||||
本项目采用以下分支策略进行代码管理:
|
||||
|
||||
### 2.1 主分支 (`main`)
|
||||
|
||||
* **用途**:`main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。
|
||||
* **更新规则**:仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev` 或 `release` 分支合并到 `main` 时,必须打上版本标签。
|
||||
* **用途**: `main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。
|
||||
* **更新规则**: 仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev` 或 `release` 分支合并到 `main` 时,必须打上版本标签。
|
||||
|
||||
### 2.2 开发分支 (`dev`)
|
||||
|
||||
* **用途**:`dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`。
|
||||
* **更新规则**:所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`。
|
||||
* **用途**: `dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`。
|
||||
* **更新规则**: 所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`。
|
||||
|
||||
### 2.3 功能分支 (`feature/*`)
|
||||
|
||||
* **用途**:每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。
|
||||
* **命名规范**:`feature/功能描述`,例如:`feature/ast-folding`、`feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。
|
||||
* **开发流程**:
|
||||
* **用途**: 每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。
|
||||
* **命名规范**: `feature/功能描述`,例如: `feature/ast-folding`、`feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `dev` 分支拉取最新代码。
|
||||
2. 完成功能开发后,在本地提交代码并推送至远程仓库。
|
||||
@ -34,9 +34,9 @@
|
||||
|
||||
### 2.4 修复分支 (`bugfix/*`)
|
||||
|
||||
* **用途**:用于修复 Bug,修复分支可以从 `dev` 或 `main` 分支创建。
|
||||
* **命名规范**:`bugfix/bug描述`,例如:`bugfix/fix-ast-error`。
|
||||
* **开发流程**:
|
||||
* **用途**: 用于修复 Bug,修复分支可以从 `dev` 或 `main` 分支创建。
|
||||
* **命名规范**: `bugfix/bug描述`,例如: `bugfix/fix-ast-error`。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `dev` 或 `main` 分支拉取最新代码。
|
||||
2. 完成修复后,提交修改并推送至远程仓库。
|
||||
@ -44,9 +44,9 @@
|
||||
|
||||
### 2.5 发布分支 (`release/*`)
|
||||
|
||||
* **用途**:当 `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。
|
||||
* **命名规范**:`release/vX.X.X`,例如:`release/v1.0.0`。
|
||||
* **开发流程**:
|
||||
* **用途**: 当 `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。
|
||||
* **命名规范**: `release/vX.X.X`,例如: `release/v1.0.0`。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `dev` 分支创建 `release` 分支。
|
||||
2. 在 `release` 分支上进行版本发布的最终准备工作,如文档更新、版本号调整等。
|
||||
@ -54,24 +54,24 @@
|
||||
|
||||
### 2.6 热修复分支 (`hotfix/*`)
|
||||
|
||||
* **用途**:当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。
|
||||
* **命名规范**:`hotfix/bug描述`,例如:`hotfix/fix-production-crash`。
|
||||
* **开发流程**:
|
||||
* **用途**: 当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。
|
||||
* **命名规范**: `hotfix/bug描述`,例如: `hotfix/fix-production-crash`。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `main` 分支创建 `hotfix` 分支,确保该分支包含生产环境中最新的稳定版本。
|
||||
2. 在 `hotfix` 分支上进行问题修复和相关调整。
|
||||
3. 完成修复后,提交修改并推送至远程仓库。
|
||||
4. 创建拉取请求(PR),将 `hotfix` 分支合并至 `main` 分支并打上版本标签,确保生产环境修复生效。
|
||||
5. 将修复后的变更合并回 `dev` 分支,确保所有的修复和调整同步到开发分支,防止后续开发中出现同样的问题。
|
||||
6. **回滚策略**:如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。
|
||||
6. **回滚策略**: 如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。
|
||||
|
||||
## 3. 提交规范
|
||||
|
||||
为确保提交信息清晰且易于理解,遵循以下提交规范:
|
||||
为确保提交信息清晰且易于理解,遵循以下提交规范:
|
||||
|
||||
### 3.1 提交信息格式
|
||||
|
||||
提交信息应简洁且具有描述性,格式如下:
|
||||
提交信息应简洁且具有描述性,格式如下:
|
||||
|
||||
```
|
||||
[类型] 描述
|
||||
@ -81,20 +81,20 @@
|
||||
|
||||
#### 提交类型
|
||||
|
||||
* `feat`:新增功能
|
||||
* `fix`:修复 Bug
|
||||
* `docs`:文档更新
|
||||
* `style`:代码格式调整(不影响功能)
|
||||
* `refactor`:代码重构
|
||||
* `test`:增加/修改测试
|
||||
* `chore`:工具配置等其他杂项任务
|
||||
* `ci`:持续集成相关改动
|
||||
* `perf`:性能优化
|
||||
* `feat`: 新增功能
|
||||
* `fix`: 修复 Bug
|
||||
* `docs`: 文档更新
|
||||
* `style`: 代码格式调整(不影响功能)
|
||||
* `refactor`: 代码重构
|
||||
* `test`: 增加/修改测试
|
||||
* `chore`: 工具配置等其他杂项任务
|
||||
* `ci`: 持续集成相关改动
|
||||
* `perf`: 性能优化
|
||||
|
||||
#### 示例
|
||||
|
||||
* `feat: 添加 IR 折叠功能`
|
||||
* `fix: 修复问题 Y(原因:X bug,解决方案:Z)`
|
||||
* `fix: 修复问题 Y(原因: X bug,解决方案: Z)`
|
||||
* `docs: 更新 API 文档`
|
||||
* `refactor: 优化 AST 逻辑`
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
### 4.2 代码审查
|
||||
|
||||
* 所有 PR 必须经过至少一名开发者的代码审查。
|
||||
* 审查时应关注以下方面:
|
||||
* 审查时应关注以下方面:
|
||||
|
||||
* 代码是否符合项目的编码规范。
|
||||
* 是否提供了足够的单元测试覆盖。
|
||||
@ -124,14 +124,14 @@
|
||||
|
||||
## 5. 版本发布
|
||||
|
||||
版本发布基于 Git 标签,发布流程如下:
|
||||
版本发布基于 Git 标签,发布流程如下:
|
||||
|
||||
### 5.1 打标签
|
||||
|
||||
每当版本准备发布时,应在 `main` 分支上打上版本标签:
|
||||
每当版本准备发布时,应在 `main` 分支上打上版本标签:
|
||||
|
||||
* **版本号规则**:采用语义化版本控制(SemVer)格式,版本号由三部分组成:`主版本号.次版本号.修订号`(例如:`v1.0.0`)。
|
||||
* **标签命令**:
|
||||
* **版本号规则**: 采用语义化版本控制(SemVer)格式,版本号由三部分组成: `主版本号.次版本号.修订号`(例如: `v1.0.0`)。
|
||||
* **标签命令**:
|
||||
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
## 2. 前置条件
|
||||
|
||||
1. 操作系统:Linux/macOS/Windows
|
||||
1. 操作系统: Linux/macOS/Windows
|
||||
2. Java 项目(Maven)
|
||||
3. GraalVM(建议 24+ 版本)
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
### 3.1 安装 GraalVM
|
||||
|
||||
1. 下载对应平台的 GraalVM Community 版本:[https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/)
|
||||
2. 解压并配置环境变量:
|
||||
1. 下载对应平台的 GraalVM Community 版本: [https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/)
|
||||
2. 解压并配置环境变量:
|
||||
|
||||
3. 验证安装:
|
||||
3. 验证安装:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
@ -44,12 +44,12 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc
|
||||
|
||||
## 4. Maven 项目配置文件
|
||||
|
||||
通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件:
|
||||
通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件:
|
||||
|
||||
```xml
|
||||
<profiles>
|
||||
<!--
|
||||
原生镜像构建:Linux 平台
|
||||
原生镜像构建: Linux 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
|
||||
- 依赖 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>
|
||||
|
||||
<!--
|
||||
原生镜像构建:Windows 平台
|
||||
原生镜像构建: Windows 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
|
||||
- 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
|
||||
|
||||

|
||||
|
||||
3. 等待 Native Image 构建完成:这个过程可能较慢(数分钟)。
|
||||
3. 等待 Native Image 构建完成: 这个过程可能较慢(数分钟)。
|
||||
4. 可执行文件即可直接运行,无需 JVM。
|
||||
> 生成的可执行文件位于 target/ 目录。
|
||||
|
||||
@ -7,22 +7,22 @@
|
||||
|
||||
## 1.2 背景与目标读者
|
||||
|
||||
自 ChatGPT 3.5 诞生以来,越来越多的个人和企业将 LLM 生成的代码融入日常开发与自动化。然而,实践证明:LLM 生成的代码虽然“看起来没问题”,却常因对底层语言细节把握不准导致微妙 Bug——比如运算符优先级混淆、作用域处理错误、甚至基础库调用都无法编译通过。
|
||||
自 ChatGPT 3.5 诞生以来,越来越多的个人和企业将 LLM 生成的代码融入日常开发与自动化。然而,实践证明: LLM 生成的代码虽然“看起来没问题”,却常因对底层语言细节把握不准导致微妙 Bug——比如运算符优先级混淆、作用域处理错误、甚至基础库调用都无法编译通过。
|
||||
|
||||
于是,我萌生了这样一个想法:**能否设计一门编程语言,让 LLM 在“语法层面”能够更精准、高效地理解和生成代码?**
|
||||
于是,我萌生了这样一个想法: **能否设计一门编程语言,让 LLM 在“语法层面”能够更精准、高效地理解和生成代码?**
|
||||
|
||||
传统编程语言的设计多偏重“计算机”的执行效率,程序员往往在抽象表达和底层性能之间不断权衡。Ruby 之父松本行弘提出“为人而不是为机器编程”的理念。而在 LLM 日益普及的今天,我们应当承认:大型模型正成为“超级程序员”,它们不仅是助手,更是“代码生产的中介”。如果一门语言的语法和设计能最大化发挥 LLM 的推理与生成能力,人机协作的效率将被极大提升。
|
||||
传统编程语言的设计多偏重“计算机”的执行效率,程序员往往在抽象表达和底层性能之间不断权衡。Ruby 之父松本行弘提出“为人而不是为机器编程”的理念。而在 LLM 日益普及的今天,我们应当承认: 大型模型正成为“超级程序员”,它们不仅是助手,更是“代码生产的中介”。如果一门语言的语法和设计能最大化发挥 LLM 的推理与生成能力,人机协作的效率将被极大提升。
|
||||
|
||||
因此,**Snow** 的使命是:让编程语言不再“让人头疼”,而是“让 LLM 更加从容地书写”。目标受众涵盖 LLM 爱好者、开发者、对编译原理感兴趣的学生,以及对性能有追求的工程师甚至是初学者——每个人都能在 Snow 中找到乐趣与成长。
|
||||
因此,**Snow** 的使命是: 让编程语言不再“让人头疼”,而是“让 LLM 更加从容地书写”。目标受众涵盖 LLM 爱好者、开发者、对编译原理感兴趣的学生,以及对性能有追求的工程师甚至是初学者——每个人都能在 Snow 中找到乐趣与成长。
|
||||
|
||||
## 1.3 文章目的
|
||||
|
||||
本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标:
|
||||
本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标:
|
||||
|
||||
* **兴趣驱动的坚持**:用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。
|
||||
* **从规划到实践的拆解**:详解在有限资源下,如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。
|
||||
* **经验与反思**:不仅有“成功输出 1+1=2”的成就感,也有调试死循环、运算符冲突等踩坑经历,全方位展示编程语言设计的挑战与思考。
|
||||
* **激励与号召**:希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。
|
||||
* **兴趣驱动的坚持**: 用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。
|
||||
* **从规划到实践的拆解**: 详解在有限资源下,如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。
|
||||
* **经验与反思**: 不仅有“成功输出 1+1=2”的成就感,也有调试死循环、运算符冲突等踩坑经历,全方位展示编程语言设计的挑战与思考。
|
||||
* **激励与号召**: 希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。
|
||||
|
||||
---
|
||||
|
||||
@ -31,18 +31,18 @@
|
||||
## 2.1 现有工具的痛点
|
||||
|
||||
* **编程语言过于灵活,缺乏规范**
|
||||
常见的编程语言如 Python、PHP、Ruby,虽然语法简洁、上手快,但“灵活性”本身也带来了不少隐患:变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考:如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶?
|
||||
常见的编程语言如 Python、PHP、Ruby,虽然语法简洁、上手快,但“灵活性”本身也带来了不少隐患: 变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考: 如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶?
|
||||
|
||||
* **缺乏专为 LLM 设计的编程语言**
|
||||
当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如:部分语法容易混淆,作用域和可见性规则不直观,LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。
|
||||
当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如: 部分语法容易混淆,作用域和可见性规则不直观,LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。
|
||||
|
||||
## 2.2 触发想法的场景
|
||||
|
||||
* **对高效与规范的需求日益突出**
|
||||
在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论:能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。
|
||||
在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论: 能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。
|
||||
|
||||
* **自研编程语言的大胆设想**
|
||||
随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP,总要写很多提示,还要人工修正各种细节。由此引发思考:如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率?
|
||||
随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP,总要写很多提示,还要人工修正各种细节。由此引发思考: 如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率?
|
||||
|
||||
|
||||
## 2.3 项目愿景
|
||||
@ -62,12 +62,12 @@
|
||||
|
||||
## 3.1 为什么开源
|
||||
|
||||
* **获得社区反馈,检验设计思路**:闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。
|
||||
* **边开源边完善,更吸引贡献者**:功能精简但可用时就发布,容易吸引早期用户参与共建。
|
||||
* **获得社区反馈,检验设计思路**: 闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。
|
||||
* **边开源边完善,更吸引贡献者**: 功能精简但可用时就发布,容易吸引早期用户参与共建。
|
||||
|
||||
## 3.2 开源准备工作
|
||||
|
||||
* **许可证选择**:
|
||||
* **许可证选择**:
|
||||
采用 [Apache-2.0](https://gitee.com/jcnc-org/snow/blob/main/LICENSE),最大程度降低贡献门槛。
|
||||
|
||||
## 3.3 项目运行输出
|
||||
@ -248,11 +248,11 @@ Process has ended
|
||||
|
||||
## 4.1 v0.2 初步目标
|
||||
|
||||
1. **完善变量作用域与高级函数调用**:
|
||||
1. **完善变量作用域与高级函数调用**:
|
||||
支持函数参数、返回值、本地与全局变量隔离,以及闭包基础,为并发/异步打基础。
|
||||
2. **完善错误提示与调试信息**:
|
||||
2. **完善错误提示与调试信息**:
|
||||
报错更精准,方便新手调试。
|
||||
3. **预计发布日期:2025 年 7 月 30 日**
|
||||
3. **预计发布日期: 2025 年 7 月 30 日**
|
||||
|
||||
## 4.2 v0.3 目标
|
||||
1. **IDE的支持**
|
||||
@ -262,11 +262,11 @@ Process has ended
|
||||
|
||||
## 4.3 v1.0 长期规划
|
||||
|
||||
1. **初步标准库**:
|
||||
1. **初步标准库**:
|
||||
I/O、字符串、JSON、文件系统,满足日常脚本需求。
|
||||
2. **包管理与模块加载**:
|
||||
2. **包管理与模块加载**:
|
||||
设计 `snowpkg`,支持一键安装依赖、自动模块导入。
|
||||
3. **社区协作与贡献**:
|
||||
3. **社区协作与贡献**:
|
||||
开设设计讨论区、每月线上分享,鼓励贡献代码与案例,让更多人参与 Snow 的成长。
|
||||
|
||||
---
|
||||
@ -275,15 +275,15 @@ Process has ended
|
||||
|
||||
## 5.1 学习收获与成就感
|
||||
|
||||
回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是:让一个想法变成可运行的代码,哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。
|
||||
回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是: 让一个想法变成可运行的代码,哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。
|
||||
|
||||
## 5.2 技术敬畏与情感共鸣
|
||||
|
||||
也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节:多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。
|
||||
也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节: 多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。
|
||||
|
||||
## 5.3 欢迎你的加入
|
||||
|
||||
真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴:
|
||||
真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴:
|
||||
|
||||
1. 在 Gitee 提交 Issue,反馈使用体验和建议;
|
||||
2. Fork 仓库、贡献 PR,参与语法和功能共建;
|
||||
@ -294,7 +294,7 @@ Process has ended
|
||||
> 微信: xuxiaolankaka
|
||||
> QQ: 1399528359
|
||||
|
||||
对于从未写过语言的初学者,我想说:**不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。
|
||||
对于从未写过语言的初学者,我想说: **不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Snow 语言现状和下一阶段开发路线图
|
||||
|
||||
> 日期:2025-06-11
|
||||
> 日期: 2025-06-11
|
||||
|
||||
## 1. 代码结构与职责
|
||||
| 层次 | 主要包/目录 | 说明 |
|
||||
@ -30,7 +30,7 @@
|
||||
6. **VM**
|
||||
|
||||
* 栈-基 / 寄存器混合架构
|
||||
* 96 条已实现指令(按数据宽度泛化:B/S/I/L/F/D)
|
||||
* 96 条已实现指令(按数据宽度泛化: B/S/I/L/F/D)
|
||||
* 运行时启动器 `VMLauncher`
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
|
||||
## 4. 下一阶段开发路线图
|
||||
|
||||
> 优先级:P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期
|
||||
> 优先级: P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期
|
||||
|
||||
| 优先级 | 功能 | 关键任务 |
|
||||
|--------|------------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
@ -58,18 +58,18 @@
|
||||
| **P0** | **一元表达式解析** | \* 实现 `UnaryOperatorParselet`(`-`, `+`, `!`)<br>\* 对应 `UnaryOpGenerator` 注册 |
|
||||
| **P1** | **数组与切片** | \* 设计 `ArrayType`(元素类型 + 维度)<br>\* 新增 `IndexExpressionNode`、`NewArrayNode`<br>\* VM 扩充 `ALOAD/ASTORE` 指令 |
|
||||
| **P1** | **基础标准库** | \* `print/println`, 文件读写<br>\* 编译期内置绑定到 VM calls |
|
||||
| **P1** | **测试与 CI** | \* JUnit5 单测:Lexer / Parser / Semantic / VM<br>\* CI/CD 自动构建、示例编译运行 |
|
||||
| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局<br>\* 方法调度:静态 or 虚表 |
|
||||
| **P1** | **测试与 CI** | \* JUnit5 单测: Lexer / Parser / Semantic / VM<br>\* CI/CD 自动构建、示例编译运行 |
|
||||
| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局<br>\* 方法调度: 静态 or 虚表 |
|
||||
| **P2** | **优化管线** | \* 常量折叠、公共子表达式消除<br>\* 简易死代码清除 |
|
||||
| **P2** | **错误与异常系统** | \* 语法:`try … catch … end`<br>\* VM:展开-收缩栈,异常表 |
|
||||
| **P2** | **包管理 & CLI** | \* `snowc` 命令:`build`, `run`, `test`<br>\* 本地缓存 `.snowpkg`与包版本语义 |
|
||||
| **P2** | **错误与异常系统** | \* 语法: `try … catch … end`<br>\* VM: 展开-收缩栈,异常表 |
|
||||
| **P2** | **包管理 & CLI** | \* `snowc` 命令: `build`, `run`, `test`<br>\* 本地缓存 `.snowpkg`与包版本语义 |
|
||||
|
||||
|
||||
## 5.1 里程碑排期
|
||||
|
||||
| 时间 | 目标 |
|
||||
|---------|----------------------------------------|
|
||||
| 2025-07 | 发布 **v0.2.0**:布尔类型 + 一元运算、20+ 单元测试 |
|
||||
| 2025-08 | 发布 **v0.3.0**:数组/切片 & 基础标准库;引入 CLI |
|
||||
| 2025-10 | 发布 **v0.4.0**:结构体支持、首批优化 Pass、>80% 覆盖率 |
|
||||
| 2026-11 | 发布 **v1.0.0**:异常系统、稳定包管理、文档完善 |
|
||||
| 2025-07 | 发布 **v0.2.0**: 布尔类型 + 一元运算、20+ 单元测试 |
|
||||
| 2025-08 | 发布 **v0.3.0**: 数组/切片 & 基础标准库;引入 CLI |
|
||||
| 2025-10 | 发布 **v0.4.0**: 结构体支持、首批优化 Pass、>80% 覆盖率 |
|
||||
| 2026-11 | 发布 **v1.0.0**: 异常系统、稳定包管理、文档完善 |
|
||||
|
||||
581
docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
Normal file
581
docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md
Normal file
@ -0,0 +1,581 @@
|
||||
# Snow‑Lang 语法规范
|
||||
|
||||
---
|
||||
|
||||
## 0 · 符号约定
|
||||
|
||||
* ⟦ … ⟧: 可选项(0 或 1 次)
|
||||
* { … }\*: 可重复项(0 次或多次)
|
||||
|
||||
---
|
||||
|
||||
## 1 · 词汇结构
|
||||
|
||||
### 1.1 编码与字符集
|
||||
|
||||
源文件采用 UTF‑8 编码。除注释外,标识符只允许英文大小写字母 (A‑Z a‑z)、数字 (0‑9) 与下划线 _;首字符不能为数字。
|
||||
|
||||
```ebnf
|
||||
identifier ::= [A-Za-z_][A-Za-z0-9_]* ;
|
||||
```
|
||||
|
||||
* **区分大小写**: Foo 与 foo 为不同标识符。
|
||||
* 保留字 (见 §1.3) **禁止** 用作标识符。
|
||||
|
||||
### 1.2 分隔符与强制空白
|
||||
|
||||
相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例:
|
||||
|
||||
```snow
|
||||
module: Foo // 推荐
|
||||
module:Foo // 不推荐
|
||||
```
|
||||
|
||||
### 1.3 保留关键字
|
||||
|
||||
```
|
||||
module import end module globals struct end struct
|
||||
function end function params returns body end body
|
||||
declare if then else end if loop init cond step
|
||||
end loop break continue self
|
||||
```
|
||||
|
||||
以上列表 **均为关键词**,大小写固定,不能作为标识符。
|
||||
|
||||
### 1.4 文字量 (Literal)
|
||||
|
||||
* **整型**: 123 0 -42
|
||||
* **浮点**: 3.14 0.0
|
||||
* **布尔**: true false
|
||||
* **字符串**: 未来版本保留;当前规范未定义。
|
||||
|
||||
### 1.5 注释
|
||||
|
||||
* **单行注释**: 以 // 起,至当行行尾。
|
||||
* **多行注释**: /* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。
|
||||
|
||||
---
|
||||
|
||||
### 1.6 换行与缩进
|
||||
|
||||
* **只有换行有语义**: 以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。
|
||||
* **缩进没有语义**: 缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。
|
||||
* 块体通过显式关闭关键字(如 end module、end function 等)结束。
|
||||
* 若关闭关键字与开始关键字之间的缩进不一致,不会报错,仍以关闭关键字为准。
|
||||
|
||||
> 块体结构完全由行分隔和显式关闭关键字决定,缩进仅为美观,不影响代码执行。
|
||||
|
||||
---
|
||||
|
||||
## 2 · 模块与导入
|
||||
|
||||
### 2.1 模块声明
|
||||
|
||||
```snow
|
||||
module: <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) // 匹配第二个构造函数
|
||||
````
|
||||
@ -31,14 +31,14 @@ end module
|
||||
|
||||
### 数据类型
|
||||
|
||||
bool 类型:
|
||||
bool 类型:
|
||||
|
||||
两种值:`true` 和 `false`
|
||||
两种值: `true` 和 `false`
|
||||
|
||||
|
||||
|
||||
|
||||
数值类型:
|
||||
数值类型:
|
||||
|
||||
| Number | keyword |
|
||||
|----------|---------|
|
||||
@ -51,7 +51,7 @@ bool 类型:
|
||||
|
||||
默认整数的类型为 int,浮点数的类型为 double。
|
||||
|
||||
数值字面量后缀:
|
||||
数值字面量后缀:
|
||||
|
||||
| 数值字面量后缀 | 例子 |
|
||||
|---------|----|
|
||||
@ -64,7 +64,7 @@ bool 类型:
|
||||
|
||||
|
||||
### 变量
|
||||
定义变量的形式如下,中括号表示可选:
|
||||
定义变量的形式如下,中括号表示可选:
|
||||
|
||||
```snow
|
||||
declare name: type [= initial_value]
|
||||
@ -72,24 +72,24 @@ declare name: type [= initial_value]
|
||||
|
||||
其中 `name` 是变量名,`type` 是变量类型,`initial_value` 是初始值
|
||||
|
||||
例:
|
||||
例:
|
||||
|
||||
```snow
|
||||
declare x: int
|
||||
declare y: long = 123456789
|
||||
```
|
||||
|
||||
读取变量值的方法,直接写变量的名字即可:
|
||||
读取变量值的方法,直接写变量的名字即可:
|
||||
```snow
|
||||
x
|
||||
```
|
||||
|
||||
设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可:
|
||||
设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可:
|
||||
```snow
|
||||
x = 10
|
||||
```
|
||||
|
||||
于是可以通过这种方式让变量参与计算并保存结果:
|
||||
于是可以通过这种方式让变量参与计算并保存结果:
|
||||
```snow
|
||||
x = y + 1
|
||||
```
|
||||
@ -99,19 +99,19 @@ x = y + 1
|
||||
|
||||
## 流程控制
|
||||
### if
|
||||
if 语句的形式如下,else 是可选的:
|
||||
if 语句的形式如下,else 是可选的:
|
||||
|
||||
```snow
|
||||
if condition then
|
||||
if cond then
|
||||
// 条件成立执行的代码
|
||||
else
|
||||
// 以上条件不成立执行的代码
|
||||
end if
|
||||
```
|
||||
|
||||
condition 可以是表达式(结果为 bool 类型)或者 bool 字面量
|
||||
cond 可以是表达式(结果为 bool 类型)或者 bool 字面量
|
||||
|
||||
例:
|
||||
例:
|
||||
|
||||
```snow
|
||||
module: Main
|
||||
@ -131,17 +131,17 @@ end module
|
||||
```
|
||||
|
||||
### loop
|
||||
loop 语句的形式如下:
|
||||
loop 语句的形式如下:
|
||||
```snow
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
// 循环开始前可声明循环变量,有且只能声明一个
|
||||
declare i: int = 1
|
||||
condition:
|
||||
cond:
|
||||
// 循环条件,成立则执行 body 的代码,
|
||||
// 不成立则退出循环,有且只能写一条
|
||||
i <= 100
|
||||
update:
|
||||
step:
|
||||
// 循环体执行完后执行的代码,有且只能写一条
|
||||
i = i + 1
|
||||
body:
|
||||
@ -150,7 +150,7 @@ loop:
|
||||
end loop
|
||||
```
|
||||
|
||||
例子(求 1 ~ 100 的和):
|
||||
例子(求 1 ~ 100 的和):
|
||||
```snow
|
||||
module: Main
|
||||
function: main
|
||||
@ -158,11 +158,11 @@ module: Main
|
||||
body:
|
||||
declare sum: int = 0
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
declare i: int = 1
|
||||
condition:
|
||||
cond:
|
||||
i <= 100
|
||||
update:
|
||||
step:
|
||||
i = i + 1
|
||||
body:
|
||||
sum = sum + i
|
||||
@ -176,7 +176,7 @@ end module
|
||||
```
|
||||
|
||||
## 函数
|
||||
函数的形式如下:
|
||||
函数的形式如下:
|
||||
```snow
|
||||
function: add
|
||||
parameter:
|
||||
@ -197,7 +197,7 @@ end function
|
||||
通过 import 语句导入模块,
|
||||
snow 会自动将同名模块的函数合并。
|
||||
|
||||
在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下:
|
||||
在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下:
|
||||
|
||||
```snow
|
||||
module: Main
|
||||
@ -213,7 +213,7 @@ end module
|
||||
|
||||
可以看到模块名是 Main,里面有函数 main。
|
||||
|
||||
假如现在有一个模块 Math,代码如下:
|
||||
假如现在有一个模块 Math,代码如下:
|
||||
```snow
|
||||
// Math.snow
|
||||
module: Math
|
||||
@ -229,7 +229,7 @@ module: Math
|
||||
end module
|
||||
```
|
||||
|
||||
可以使用 import 来导入 Math 模块:
|
||||
可以使用 import 来导入 Math 模块:
|
||||
```snow
|
||||
// main.snow
|
||||
module: Main
|
||||
@ -244,7 +244,7 @@ module: Main
|
||||
end module
|
||||
```
|
||||
|
||||
可以同时导入多个模块,用逗号(半角)分隔模块名即可:
|
||||
可以同时导入多个模块,用逗号(半角)分隔模块名即可:
|
||||
```snow
|
||||
// main.snow
|
||||
module: Main
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
# SnowVM-OpCode
|
||||
|
||||
## 1. Byte8 区域(0x0000-0x001F)
|
||||
## Type Control (0x0000-0x00BF)
|
||||
|
||||
### Byte8 (0x0000-0x001F)
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|----------------|
|
||||
| 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 |
|
||||
| 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)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|-------------|--------|------|
|
||||
|
||||
@ -15,11 +15,11 @@ module: Math
|
||||
body:
|
||||
declare num1:int = 1
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
declare counter:int = 1
|
||||
condition:
|
||||
cond:
|
||||
counter <= n
|
||||
update:
|
||||
step:
|
||||
counter = counter + 1
|
||||
body:
|
||||
num1 = num1 * counter
|
||||
|
||||
11
lib/os/OS.snow
Normal file
11
lib/os/OS.snow
Normal 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
|
||||
@ -3,11 +3,11 @@ function: main
|
||||
return_type: int
|
||||
body:
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
declare i:int = 0
|
||||
condition:
|
||||
cond:
|
||||
1 == 1
|
||||
update:
|
||||
step:
|
||||
i = i + 1
|
||||
body:
|
||||
|
||||
|
||||
@ -1,17 +1,8 @@
|
||||
module: Main
|
||||
function: main
|
||||
return_type: int
|
||||
body:
|
||||
foo()
|
||||
|
||||
return 0
|
||||
end body
|
||||
end function
|
||||
|
||||
function: foo
|
||||
return_type: void
|
||||
body:
|
||||
|
||||
declare abc:int =1
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
end module
|
||||
|
||||
@ -7,34 +7,34 @@ module: Main
|
||||
5 == 7b
|
||||
5 == 7l
|
||||
5 == 7f
|
||||
5 == 7d
|
||||
5 == 7.0
|
||||
|
||||
5b == 5b
|
||||
5b == 5s
|
||||
5b == 5l
|
||||
5b == 5f
|
||||
5b == 5d
|
||||
5b == 5.0
|
||||
|
||||
5s == 5s
|
||||
5s == 5l
|
||||
5s == 5f
|
||||
5s == 5d
|
||||
5s == 5.0
|
||||
|
||||
5l == 5l
|
||||
5l == 5f
|
||||
5l == 5d
|
||||
5l == 5.0
|
||||
|
||||
5f == 5f
|
||||
5f == 5d
|
||||
5f == 5.0
|
||||
|
||||
5d == 5d
|
||||
5.0 == 5.0
|
||||
|
||||
declare b: byte = 8b
|
||||
declare s: short = 8s
|
||||
declare i: int = 8
|
||||
declare l: long = 8l
|
||||
declare f: float = 8f
|
||||
declare d: double = 8d
|
||||
declare d: double = 8
|
||||
|
||||
b == b
|
||||
b == s
|
||||
|
||||
9
playground/Demo/Demo14/Main.snow
Normal file
9
playground/Demo/Demo14/Main.snow
Normal file
@ -0,0 +1,9 @@
|
||||
module: Main
|
||||
import: os
|
||||
function: main
|
||||
return_type: void
|
||||
body:
|
||||
print(222)
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
11
playground/Demo/Demo14/OS.snow
Normal file
11
playground/Demo/Demo14/OS.snow
Normal 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
|
||||
@ -5,11 +5,11 @@ module: Main
|
||||
body:
|
||||
declare b1: boolean = true
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
declare i:int = 0
|
||||
condition:
|
||||
cond:
|
||||
b1
|
||||
update:
|
||||
step:
|
||||
i = i + 1
|
||||
body:
|
||||
|
||||
|
||||
@ -15,11 +15,11 @@ module: Math
|
||||
body:
|
||||
declare num1:int = 1
|
||||
loop:
|
||||
initializer:
|
||||
init:
|
||||
declare counter:int = 1
|
||||
condition:
|
||||
cond:
|
||||
counter <= n
|
||||
update:
|
||||
step:
|
||||
counter = counter + 1
|
||||
body:
|
||||
num1 = num1 * counter
|
||||
|
||||
10
pom.xml
10
pom.xml
@ -7,7 +7,7 @@
|
||||
|
||||
<groupId>org.jcnc.snow</groupId>
|
||||
<artifactId>Snow</artifactId>
|
||||
<version>0.4.2</version>
|
||||
<version>0.5.0</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<plugins>
|
||||
<!--
|
||||
Java 编译插件:
|
||||
Java 编译插件:
|
||||
- 使用 Maven 自带的 maven-compiler-plugin 进行源码编译
|
||||
- <fork>true</fork> 表示在单独的进程中执行 javac,提高兼容性
|
||||
-->
|
||||
@ -45,7 +45,7 @@
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
Jar 打包插件:
|
||||
Jar 打包插件:
|
||||
- 使用 maven-jar-plugin 将编译产物打包成可执行 JAR
|
||||
- 在 MANIFEST 中指定主类,支持命令行直接 java -jar 调用
|
||||
-->
|
||||
@ -71,7 +71,7 @@
|
||||
|
||||
<profiles>
|
||||
<!--
|
||||
原生镜像构建:Linux 平台
|
||||
原生镜像构建: Linux 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
|
||||
- 依赖 musl libc,需提前安装并配置 musl-gcc 工具链
|
||||
-->
|
||||
@ -133,7 +133,7 @@
|
||||
</profile>
|
||||
|
||||
<!--
|
||||
原生镜像构建:Windows 平台
|
||||
原生镜像构建: Windows 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
|
||||
- Windows 上不使用 musl,因此不配置静态链接
|
||||
-->
|
||||
|
||||
@ -4,6 +4,8 @@ import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.cli.commands.*;
|
||||
import org.jcnc.snow.cli.utils.CLIUtils;
|
||||
import org.jcnc.snow.cli.utils.VersionUtils;
|
||||
import org.jcnc.snow.common.Mode;
|
||||
import org.jcnc.snow.common.SnowConfig;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@ -13,13 +13,13 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:构建当前项目(包含依赖解析、编译、打包)。
|
||||
* CLI 命令: 构建当前项目(包含依赖解析、编译、打包)。
|
||||
* <p>
|
||||
* 该命令会依次执行依赖解析、源码编译和产物打包阶段。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow build
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -6,13 +6,13 @@ import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
|
||||
import org.jcnc.snow.pkg.tasks.CleanTask;
|
||||
|
||||
/**
|
||||
* CLI 命令:清理构建输出和本地缓存目录。
|
||||
* CLI 命令: 清理构建输出和本地缓存目录。
|
||||
* <p>
|
||||
* 用于清除项目生成的 build、dist 等中间产物,保持工作区整洁。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow clean
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -13,17 +13,17 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CLI 命令:编译当前项目。
|
||||
* CLI 命令: 编译当前项目。
|
||||
*
|
||||
* <p>工作模式说明:</p>
|
||||
* <p>工作模式说明: </p>
|
||||
* <ul>
|
||||
* <li><strong>Cloud 模式</strong>
|
||||
* - 项目根目录存在 {@code project.cloud} 时触发;
|
||||
* - 解析 build 区块,自动推导源码目录与输出文件名;
|
||||
* - 用法:{@code snow compile [run]}</li>
|
||||
* - 用法: {@code snow compile [run]}</li>
|
||||
* <li><strong>Local 模式</strong>
|
||||
* - 未检测到 {@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>
|
||||
*
|
||||
* <p>两种模式均将最终参数交由 {@link CompileTask} 处理。</p>
|
||||
@ -60,19 +60,19 @@ public final class CompileCommand implements CLICommand {
|
||||
|
||||
List<String> argList = new ArrayList<>();
|
||||
|
||||
// 保留用户在 cloud 模式下传入的 “run” 标志
|
||||
// 保留用户在 cloud 模式下传入的 “run” / “-debug” 标志
|
||||
for (String a : args) {
|
||||
if ("run".equals(a)) {
|
||||
argList.add("run");
|
||||
if ("run".equals(a) || "-debug".equals(a)) {
|
||||
argList.add(a);
|
||||
}
|
||||
}
|
||||
|
||||
/* 源码目录:build.srcDir -> 默认 src */
|
||||
/* 源码目录: build.srcDir -> 默认 src */
|
||||
String srcDir = project.getBuild().get("srcDir", "src");
|
||||
argList.add("-d");
|
||||
argList.add(srcDir);
|
||||
|
||||
/* 输出名称:build.output -> fallback to artifact */
|
||||
/* 输出名称: build.output -> fallback to artifact */
|
||||
String output = project.getBuild().get("output", project.getArtifact());
|
||||
argList.add("-o");
|
||||
argList.add(output);
|
||||
|
||||
@ -12,19 +12,19 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:根据 project.cloud 生成项目目录结构。
|
||||
* CLI 命令: 根据 project.cloud 生成项目目录结构。
|
||||
* <p>
|
||||
* 负责解析云项目描述文件,并通过 {@link GenerateTask}
|
||||
* 在 INIT 生命周期阶段内生成基础目录结构。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow generate
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 注意事项:
|
||||
* 注意事项:
|
||||
* - 若当前目录不存在 project.cloud,则提示用户先执行 `snow init`。
|
||||
* - 执行成功后,会输出已创建的目录/文件。
|
||||
* </p>
|
||||
|
||||
@ -8,13 +8,13 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:初始化项目配置文件。
|
||||
* CLI 命令: 初始化项目配置文件。
|
||||
* <p>
|
||||
* 用于快速生成 DSL 配置文件(project.cloud)。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow init
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -8,13 +8,13 @@ import org.jcnc.snow.pkg.resolver.DependencyResolver;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:解析并下载项目依赖到本地缓存。
|
||||
* CLI 命令: 解析并下载项目依赖到本地缓存。
|
||||
* <p>
|
||||
* 适用于离线使用和依赖预热场景,会自动读取项目描述文件并处理依赖缓存。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow install
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -10,14 +10,14 @@ import org.jcnc.snow.pkg.tasks.PublishTask;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:将已构建的项目包发布到远程仓库。
|
||||
* CLI 命令: 将已构建的项目包发布到远程仓库。
|
||||
* <p>
|
||||
* 用于持续集成、交付或分发场景。
|
||||
* 支持自动读取 DSL 项目描述文件,并注册和执行发布生命周期阶段的任务。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow publish
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -4,14 +4,14 @@ import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.tasks.RunTask;
|
||||
|
||||
/**
|
||||
* CLI 命令:运行已编译的 VM 字节码文件(.water)。
|
||||
* CLI 命令: 运行已编译的 VM 字节码文件(.water)。
|
||||
* <p>
|
||||
* 仅解析参数并委托给 {@link RunTask},
|
||||
* 将 VM 运行逻辑下沉至 pkg 层,保持 CLI 无状态、薄封装。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow run main.water
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -4,13 +4,13 @@ import org.jcnc.snow.cli.SnowCLI;
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
|
||||
/**
|
||||
* CLI 子命令:输出当前 Snow 工具的版本号。
|
||||
* CLI 子命令: 输出当前 Snow 工具的版本号。
|
||||
* <p>
|
||||
* 用于显示当前 CLI 工具版本,便于诊断、升级、兼容性确认等场景。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow version
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -26,12 +26,21 @@ public class CLIUtils {
|
||||
"-v", "--version"
|
||||
);
|
||||
|
||||
/**
|
||||
* 全局调试标志集合,支持 "-debug"、"--debug"。
|
||||
*/
|
||||
public static final Set<String> GLOBAL_DEBUG_FLAGS = Set.of(
|
||||
"--debug"
|
||||
);
|
||||
|
||||
/**
|
||||
* 全局选项列表,包括帮助和版本选项的描述。
|
||||
*/
|
||||
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("-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")
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
20
src/main/java/org/jcnc/snow/common/Mode.java
Normal file
20
src/main/java/org/jcnc/snow/common/Mode.java
Normal file
@ -0,0 +1,20 @@
|
||||
package org.jcnc.snow.common;
|
||||
|
||||
/**
|
||||
* 程序的运行/调试模式枚举。
|
||||
* <ul>
|
||||
* <li>RUN:运行模式</li>
|
||||
* <li>DEBUG:调试模式</li>
|
||||
* </ul>
|
||||
*/
|
||||
public enum Mode {
|
||||
/**
|
||||
* 运行模式。
|
||||
*/
|
||||
RUN,
|
||||
|
||||
/**
|
||||
* 调试模式。
|
||||
*/
|
||||
DEBUG
|
||||
}
|
||||
58
src/main/java/org/jcnc/snow/common/SnowConfig.java
Normal file
58
src/main/java/org/jcnc/snow/common/SnowConfig.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@ import java.util.Map;
|
||||
* 各虚拟寄存器实际对应的物理寄存器或栈槽号。采用简单的线性扫描分配策略。
|
||||
* </p>
|
||||
* <p>
|
||||
* 分配过程如下:
|
||||
* 分配过程如下:
|
||||
* <ol>
|
||||
* <li>优先为函数参数分配槽号,从 0 开始,按参数顺序递增。</li>
|
||||
* <li>遍历函数体的每条指令,为尚未分配的目标寄存器及其操作数分配新的槽号。</li>
|
||||
@ -28,8 +28,8 @@ public final class RegisterAllocator {
|
||||
/**
|
||||
* 虚拟寄存器到槽号的分配映射表。
|
||||
* <p>
|
||||
* 键:虚拟寄存器 {@link IRVirtualRegister};
|
||||
* 值:对应分配的槽编号 {@link Integer}。
|
||||
* 键: 虚拟寄存器 {@link IRVirtualRegister};
|
||||
* 值: 对应分配的槽编号 {@link Integer}。
|
||||
* </p>
|
||||
*/
|
||||
private final Map<IRVirtualRegister, Integer> map = new HashMap<>();
|
||||
@ -37,7 +37,7 @@ public final class RegisterAllocator {
|
||||
/**
|
||||
* 为指定 IR 函数分配所有虚拟寄存器的槽号。
|
||||
* <p>
|
||||
* 分配顺序说明:
|
||||
* 分配顺序说明:
|
||||
* <ol>
|
||||
* <li>首先为所有参数分配槽号。</li>
|
||||
* <li>然后线性遍历函数体,为每个指令涉及的虚拟寄存器(目标或操作数)分配槽号,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package org.jcnc.snow.compiler.backend.builder;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.ir.core.IRFunction;
|
||||
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
@ -16,7 +17,7 @@ import java.util.stream.Collectors;
|
||||
* 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。
|
||||
* </p>
|
||||
* <p>
|
||||
* 工作流程简述:
|
||||
* 工作流程简述:
|
||||
* <ol>
|
||||
* <li>接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。</li>
|
||||
* <li>遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。</li>
|
||||
@ -28,8 +29,8 @@ public final class VMCodeGenerator {
|
||||
/**
|
||||
* 指令类型到生成器的注册表(调度表)。
|
||||
* <p>
|
||||
* 键:IR 指令类型(Class对象),
|
||||
* 值:对应的指令生成器实例。
|
||||
* 键: IR 指令类型(Class对象),
|
||||
* 值: 对应的指令生成器实例。
|
||||
* </p>
|
||||
*/
|
||||
private final Map<Class<? extends IRInstruction>, InstructionGenerator<? extends IRInstruction>> registry;
|
||||
@ -74,18 +75,26 @@ public final class VMCodeGenerator {
|
||||
*/
|
||||
public void generate(IRFunction fn) {
|
||||
this.currentFn = fn.name();
|
||||
out.beginFunction(currentFn); // 输出函数起始
|
||||
|
||||
/* 登记函数入口地址 —— 解决 CALL 未解析符号问题 */
|
||||
out.beginFunction(currentFn);
|
||||
|
||||
/* 逐条分发 IR 指令给对应的生成器 */
|
||||
for (IRInstruction ins : fn.body()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
// 取得与当前 IR 指令类型匹配的生成器(泛型强转消除类型警告)
|
||||
InstructionGenerator<IRInstruction> gen =
|
||||
(InstructionGenerator<IRInstruction>) registry.get(ins.getClass());
|
||||
if (gen == null) {
|
||||
throw new IllegalStateException("Unsupported IR: " + ins);
|
||||
}
|
||||
// 通过多态分发到实际生成器
|
||||
gen.generate(ins, out, slotMap, currentFn);
|
||||
}
|
||||
out.endFunction(); // 输出函数结束
|
||||
|
||||
/* 强制补上函数结尾的返回/终止指令 */
|
||||
String retOpcode = "main".equals(currentFn) ? "HALT" : "RET";
|
||||
out.emit(OpHelper.opcode(retOpcode));
|
||||
|
||||
/* 结束函数 */
|
||||
out.endFunction();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import org.jcnc.snow.vm.engine.VMOpCode;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* VMProgramBuilder:构建线性 VM 程序(即按顺序存放所有 VM 指令)。
|
||||
* VMProgramBuilder: 构建线性 VM 程序(即按顺序存放所有 VM 指令)。
|
||||
* <p>
|
||||
* 本类用于编译器后端,将所有生成的 VM 指令(包括分支和调用指令)统一存储、管理。
|
||||
* 支持符号(如函数入口、标签地址)的延迟解析与回填(fix-up)机制,
|
||||
@ -22,7 +22,7 @@ public final class VMProgramBuilder {
|
||||
/** 未解析目标的分支指令(JUMP/IC_* 等待修补) */
|
||||
private record BranchFix(int index, String label) {}
|
||||
|
||||
/** 占位符:用于表示尚未确定的符号地址 */
|
||||
/** 占位符: 用于表示尚未确定的符号地址 */
|
||||
private static final String PLACEHOLDER = "-1";
|
||||
|
||||
/** 按顺序存放的 VM 指令文本 */
|
||||
@ -102,7 +102,7 @@ public final class VMProgramBuilder {
|
||||
|
||||
/**
|
||||
* 生成 CALL 指令。
|
||||
* 支持延迟修补:若目标已知,直接写入地址;否则写入占位并登记 fix-up。
|
||||
* 支持延迟修补: 若目标已知,直接写入地址;否则写入占位并登记 fix-up。
|
||||
* @param target 目标函数名
|
||||
* @param nArgs 参数个数
|
||||
*/
|
||||
|
||||
@ -5,22 +5,22 @@
|
||||
## 项目简介
|
||||
|
||||
**后端模块(Backend)** 是 [Snow 编译器]() 的核心组成部分之一,承接中间表示(IR)与运行时虚拟机(VM)之间的桥梁。
|
||||
它主要完成以下工作:
|
||||
它主要完成以下工作:
|
||||
|
||||
1. **寄存器分配**:将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
|
||||
2. **指令生成与调度**:为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
|
||||
3. **程序构建**:管理函数入口、标签定义、延迟修补(fix-up)CALL/JUMP 等控制流指令地址;
|
||||
4. **操作码与常量映射**:提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
|
||||
1. **寄存器分配**: 将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
|
||||
2. **指令生成与调度**: 为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
|
||||
3. **程序构建**: 管理函数入口、标签定义、延迟修补(fix-up)CALL/JUMP 等控制流指令地址;
|
||||
4. **操作码与常量映射**: 提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
|
||||
|
||||
后端模块设计注重可扩展性:各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
|
||||
后端模块设计注重可扩展性: 各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
|
||||
|
||||
## 核心功能
|
||||
|
||||
* **线性扫描寄存器分配**:`RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。
|
||||
* **指令生成器体系**:`InstructionGenerator<T>` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。
|
||||
* **生成器调度**:`VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。
|
||||
* **程序构建与延迟修补**:`VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。
|
||||
* **操作码与常量映射**:`IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量,并根据值类型(I/L/F…)选择合适的 PUSH/STORE 操作码。
|
||||
* **线性扫描寄存器分配**: `RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。
|
||||
* **指令生成器体系**: `InstructionGenerator<T>` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。
|
||||
* **生成器调度**: `VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。
|
||||
* **程序构建与延迟修补**: `VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。
|
||||
* **操作码与常量映射**: `IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量,并根据值类型(I/L/F…)选择合适的 PUSH/STORE 操作码。
|
||||
|
||||
## 模块结构
|
||||
|
||||
@ -51,6 +51,6 @@ backend/
|
||||
|
||||
* JDK 24 或更高版本
|
||||
* Maven 构建管理
|
||||
* 推荐 IDE:IntelliJ IDEA
|
||||
* 推荐 IDE: IntelliJ IDEA
|
||||
|
||||
---
|
||||
|
||||
@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* 并自动进行类型提升。
|
||||
* 同时实现 "+0 → MOV" 的 Peephole 优化,避免多余的 PUSH/ADD 序列。
|
||||
* </p>
|
||||
* <p>类型提升优先级:D > F > L > I > S > B</p>
|
||||
* <p>类型提升优先级: D > F > L > I > S > B</p>
|
||||
*/
|
||||
public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationInstruction> {
|
||||
|
||||
@ -143,11 +143,11 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
|
||||
// ① 条件跳转;成立 → lblTrue
|
||||
out.emitBranch(branchOp, lblTrue);
|
||||
|
||||
// ② 不成立:压 0
|
||||
// ② 不成立: 压 0
|
||||
out.emit(OpHelper.opcode("I_PUSH") + " 0");
|
||||
out.emitBranch(OpHelper.opcode("JUMP"), lblEnd);
|
||||
|
||||
// ③ 成立分支:压 1
|
||||
// ③ 成立分支: 压 1
|
||||
out.emit(lblTrue + ":");
|
||||
out.emit(OpHelper.opcode("I_PUSH") + " 1");
|
||||
|
||||
|
||||
@ -4,53 +4,142 @@ import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.ir.common.GlobalFunctionTable;
|
||||
import org.jcnc.snow.compiler.ir.core.IRValue;
|
||||
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import org.jcnc.snow.vm.engine.VMOpCode;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 将 IR CallInstruction 生成 VM 指令
|
||||
* <b>CallGenerator - 将 IR {@code CallInstruction} 生成 VM 指令</b>
|
||||
*
|
||||
* <p>
|
||||
* 本类负责将中间表示(IR)中的函数调用指令 {@link CallInstruction} 转换为虚拟机(VM)指令。
|
||||
* 支持普通函数调用和特殊的 syscall 指令转换。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>能力说明:</b>
|
||||
* <ul>
|
||||
* <li>支持识别 {@code IRConstant} 直接字面量或已绑定到虚拟寄存器的字符串常量,直接降级为 {@code SYSCALL <SUBCMD>} 指令。</li>
|
||||
* <li>对普通函数,完成参数加载、调用、返回值保存等指令生成。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
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
|
||||
public Class<CallInstruction> supportedClass() {
|
||||
return CallInstruction.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 VM 指令的主逻辑
|
||||
*
|
||||
* @param ins 当前 IR 指令(函数调用)
|
||||
* @param out 指令输出构建器
|
||||
* @param slotMap IR 虚拟寄存器与物理槽位映射
|
||||
* @param currentFn 当前函数名
|
||||
*/
|
||||
@Override
|
||||
public void generate(CallInstruction ins,
|
||||
VMProgramBuilder out,
|
||||
Map<IRVirtualRegister, Integer> slotMap,
|
||||
String currentFn) {
|
||||
|
||||
/* 1. 推断返回值类型(用于非 void 情况下的 I/F/D/L_STORE) */
|
||||
char retType = 'I';
|
||||
/* ========== 特殊处理 syscall 调用 ========== */
|
||||
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()) {
|
||||
int firstSlot = slotMap.get((IRVirtualRegister) ins.getArguments().getFirst());
|
||||
retType = out.getSlotType(firstSlot);
|
||||
if (retType == '\0') retType = 'I';
|
||||
}
|
||||
|
||||
/* 2. 依次加载实参 */
|
||||
// ---------- 2. 加载全部实参 ----------
|
||||
for (var arg : ins.getArguments()) {
|
||||
int slotId = slotMap.get((IRVirtualRegister) arg);
|
||||
char t = out.getSlotType(slotId);
|
||||
if (t == '\0') t = 'I';
|
||||
if (t == '\0') t = 'I'; // 默认整型
|
||||
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
|
||||
}
|
||||
|
||||
/* 3. 发出 CALL 指令 */
|
||||
// ---------- 3. 发出 CALL 指令 ----------
|
||||
out.emitCall(ins.getFunctionName(), ins.getArguments().size());
|
||||
|
||||
/* 3.5 若被调用函数返回 void,则无需保存返回值 */
|
||||
String rt = GlobalFunctionTable.getReturnType(ins.getFunctionName());
|
||||
if ("void".equals(rt)) {
|
||||
return; // 直接结束,无 _STORE
|
||||
// ---------- 3.5 如果为 void 返回直接结束 ----------
|
||||
if ("void".equals(GlobalFunctionTable.getReturnType(ins.getFunctionName()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 4. 保存返回值到目标槽 */
|
||||
// ---------- 4. 保存返回值 ----------
|
||||
int destSlot = slotMap.get(ins.getDest());
|
||||
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
|
||||
out.setSlotType(destSlot, retType);
|
||||
|
||||
@ -47,7 +47,7 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
|
||||
* </ol>
|
||||
*
|
||||
* @param ins IR 条件比较跳转指令
|
||||
* @param out VMProgramBuilder:用于发出 VM 指令
|
||||
* @param out VMProgramBuilder: 用于发出 VM 指令
|
||||
* @param slotMap 虚拟寄存器到 VM 槽位的映射表
|
||||
* @param currentFn 当前处理的函数名(调试用,当前未使用)
|
||||
*/
|
||||
|
||||
@ -10,16 +10,18 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 常量加载指令生成器
|
||||
* 该类用于生成将常量加载到虚拟机寄存器的指令,包括 PUSH 常量值和 STORE 到指定槽位,
|
||||
* 并为每个槽位设置正确的类型前缀(如 'I', 'L', 'F' 等)。
|
||||
* <b>LoadConstGenerator - 将 IR {@code LoadConstInstruction} 生成 VM 指令</b>
|
||||
*
|
||||
* <p>
|
||||
* 本类负责将 IR 层的常量加载指令 {@link LoadConstInstruction} 转换为对应的虚拟机指令。
|
||||
* 额外支持:如果常量类型为 {@code String},会同步登记到
|
||||
* {@link CallGenerator} 的字符串常量池,方便 syscall 降级场景使用。
|
||||
* </p>
|
||||
*/
|
||||
public class LoadConstGenerator implements InstructionGenerator<LoadConstInstruction> {
|
||||
|
||||
/**
|
||||
* 返回本生成器支持的指令类型,即 LoadConstInstruction。
|
||||
*
|
||||
* @return 支持的指令类型的 Class 对象
|
||||
* 指定本生成器支持的 IR 指令类型(LoadConstInstruction)
|
||||
*/
|
||||
@Override
|
||||
public Class<LoadConstInstruction> supportedClass() {
|
||||
@ -27,49 +29,49 @@ public class LoadConstGenerator implements InstructionGenerator<LoadConstInstruc
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成一条常量加载指令的目标虚拟机代码。
|
||||
* 生成 VM 指令主流程
|
||||
*
|
||||
* @param ins 当前要生成的 LoadConstInstruction 指令
|
||||
* @param out VMProgramBuilder,用于输出生成的虚拟机指令
|
||||
* @param slotMap IR 虚拟寄存器到实际槽位编号的映射表
|
||||
* @param currentFn 当前函数名(如有需要可使用)
|
||||
* @param ins 当前常量加载指令
|
||||
* @param out 指令输出构建器
|
||||
* @param slotMap 虚拟寄存器与物理槽位映射
|
||||
* @param currentFn 当前函数名
|
||||
*/
|
||||
@Override
|
||||
public void generate(LoadConstInstruction ins,
|
||||
VMProgramBuilder out,
|
||||
Map<IRVirtualRegister, Integer> slotMap,
|
||||
String currentFn) {
|
||||
// 1. 获取常量值(第一个操作数必为常量)
|
||||
|
||||
/* 1. 获取常量值 */
|
||||
IRConstant constant = (IRConstant) ins.operands().getFirst();
|
||||
Object value = constant.value();
|
||||
|
||||
// 2. 生成 PUSH 指令,将常量值推入操作数栈
|
||||
// 通过 OpHelper 辅助方法获取合适的数据类型前缀
|
||||
String pushOp = OpHelper.pushOpcodeFor(value);
|
||||
out.emit(pushOp + " " + value);
|
||||
/* 2. 生成 PUSH 指令,将常量值入栈 */
|
||||
out.emit(OpHelper.pushOpcodeFor(value) + " " + value);
|
||||
|
||||
// 3. 生成 STORE 指令,将栈顶的值存入对应槽位(寄存器)
|
||||
// 同样通过 OpHelper 获取对应类型的 STORE 指令
|
||||
String storeOp = OpHelper.storeOpcodeFor(value);
|
||||
// 获取目标虚拟寄存器对应的槽位编号
|
||||
/* 3. STORE 到目标槽位 */
|
||||
int slot = slotMap.get(ins.dest());
|
||||
out.emit(storeOp + " " + slot);
|
||||
out.emit(OpHelper.storeOpcodeFor(value) + " " + slot);
|
||||
|
||||
// 4. 根据常量的 Java 类型,为槽位设置正确的前缀字符
|
||||
// 这样在后续类型检查/运行时可用,常见前缀如 'I', 'L', 'F', 'D', 'S', 'B'
|
||||
/* 4. 标记槽位数据类型(用于后续类型推断和 LOAD/STORE 指令选择) */
|
||||
char prefix = switch (value) {
|
||||
case Integer _ -> 'I'; // 整型
|
||||
case Long _ -> 'L'; // 长整型
|
||||
case Short _ -> 'S'; // 短整型
|
||||
case Byte _ -> 'B'; // 字节型
|
||||
case Double _ -> 'D'; // 双精度浮点型
|
||||
case Float _ -> 'F'; // 单精度浮点型
|
||||
case Boolean _ -> 'I'; // 布尔(作为 0/1 整型存储)
|
||||
case null, default ->
|
||||
throw new IllegalStateException("Unknown const type: " + (value != null ? value.getClass() : null));
|
||||
case Integer _ -> 'I'; // 整型
|
||||
case Long _ -> 'L'; // 长整型
|
||||
case Short _ -> 'S'; // 短整型
|
||||
case Byte _ -> 'B'; // 字节型
|
||||
case Double _ -> 'D'; // 双精度
|
||||
case Float _ -> 'F'; // 单精度
|
||||
case Boolean _ -> 'I'; // 布尔类型用 I 处理
|
||||
case String _ -> 'R'; // 字符串常量
|
||||
case null, default -> // 其它类型异常
|
||||
throw new IllegalStateException("未知的常量类型: "
|
||||
+ (value != null ? value.getClass() : null));
|
||||
};
|
||||
|
||||
// 写入槽位类型映射表
|
||||
out.setSlotType(slot, prefix);
|
||||
|
||||
/* 5. 如果是字符串常量,则登记到 CallGenerator 的常量池,便于 syscall 字符串降级使用 */
|
||||
if (value instanceof String s) {
|
||||
CallGenerator.registerStringConst(ins.dest().id(), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,8 +20,8 @@ public final class IROpCodeMapper {
|
||||
/**
|
||||
* IR 操作码到 VM 指令名的静态映射表。
|
||||
* <ul>
|
||||
* <li>键:IR 操作码({@link IROpCode} 枚举项)</li>
|
||||
* <li>值:对应虚拟机指令名(字符串)</li>
|
||||
* <li>键: IR 操作码({@link IROpCode} 枚举项)</li>
|
||||
* <li>值: 对应虚拟机指令名(字符串)</li>
|
||||
* </ul>
|
||||
* 使用 {@link EnumMap},查找和存储高效。
|
||||
*/
|
||||
|
||||
@ -167,6 +167,9 @@ public final class OpHelper {
|
||||
map.put("D2I", Integer.toString(VMOpCode.D2I));
|
||||
map.put("D2L", Integer.toString(VMOpCode.D2L));
|
||||
map.put("D2F", Integer.toString(VMOpCode.D2F));
|
||||
map.put("R_PUSH", Integer.toString(VMOpCode.R_PUSH));
|
||||
map.put("R_LOAD", Integer.toString(VMOpCode.R_LOAD));
|
||||
map.put("R_STORE", Integer.toString(VMOpCode.R_STORE));
|
||||
map.put("POP", Integer.toString(VMOpCode.POP));
|
||||
map.put("DUP", Integer.toString(VMOpCode.DUP));
|
||||
map.put("SWAP", Integer.toString(VMOpCode.SWAP));
|
||||
@ -176,11 +179,19 @@ public final class OpHelper {
|
||||
map.put("MOV", Integer.toString(VMOpCode.MOV));
|
||||
map.put("HALT", Integer.toString(VMOpCode.HALT));
|
||||
map.put("SYSCALL", Integer.toString(VMOpCode.SYSCALL));
|
||||
map.put("DEBUG_TRAP", Integer.toString(VMOpCode.DEBUG_TRAP));
|
||||
// map.put("DEBUG_TRAP", Integer.toString(VMOpCode.DEBUG_TRAP));
|
||||
OPCODE_MAP = Collections.unmodifiableMap(map);
|
||||
|
||||
Map<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);
|
||||
}
|
||||
|
||||
@ -222,11 +233,13 @@ public final class OpHelper {
|
||||
if (v instanceof Byte) return "B";
|
||||
if (v instanceof Double) return "D";
|
||||
if (v instanceof Float) return "F";
|
||||
if (v instanceof String) return "R"; //引用类型
|
||||
throw new IllegalStateException("Unknown const type: " + v.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 opcode 数值的字符串形式获取指令名
|
||||
*
|
||||
* @param code 字符串形式的 opcode 数值
|
||||
* @return opcode 对应的指令名
|
||||
*/
|
||||
@ -236,6 +249,7 @@ public final class OpHelper {
|
||||
|
||||
/**
|
||||
* 根据 opcode 获取指令名
|
||||
*
|
||||
* @param code opcode
|
||||
* @return opcode 对应的指令名
|
||||
*/
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
package org.jcnc.snow.compiler.backend.utils;
|
||||
|
||||
/**
|
||||
* 工具类:提供基本数值类型的提升与类型转换辅助功能。
|
||||
* 工具类: 提供基本数值类型的提升与类型转换辅助功能。
|
||||
* <p>
|
||||
* 在进行数值类型运算、比较等操作时,低优先级的类型会被提升为高优先级类型参与运算。
|
||||
* 例如 int + long 运算,int 会被提升为 long,最终运算结果类型为 long。
|
||||
* <p>
|
||||
* 类型优先级从高到低依次为:
|
||||
* D(double):6
|
||||
* F(float) :5
|
||||
* L(long) :4
|
||||
* I(int) :3
|
||||
* S(short) :2
|
||||
* B(byte) :1
|
||||
* 未识别类型 :0
|
||||
* 类型优先级从高到低依次为:
|
||||
* D(double): 6
|
||||
* F(float) : 5
|
||||
* L(long) : 4
|
||||
* I(int) : 3
|
||||
* S(short) : 2
|
||||
* B(byte) : 1
|
||||
* 未识别类型 : 0
|
||||
*/
|
||||
public class TypePromoteUtils {
|
||||
|
||||
/**
|
||||
* 返回数值类型的宽度优先级,数值越大类型越宽。
|
||||
* 类型及优先级映射如下:
|
||||
* 类型及优先级映射如下:
|
||||
* D(double): 6
|
||||
* F(float) : 5
|
||||
* L(long) : 4
|
||||
@ -69,8 +69,8 @@ public class TypePromoteUtils {
|
||||
* 获取类型转换指令名(例如 "I2L", "F2D"),表示从源类型到目标类型的转换操作。
|
||||
* 如果源类型和目标类型相同,则返回 null,表示无需转换。
|
||||
* <p>
|
||||
* 支持的类型标记字符包括:B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
|
||||
* 所有可能的类型转换均已覆盖,如下所示:
|
||||
* 支持的类型标记字符包括: B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
|
||||
* 所有可能的类型转换均已覆盖,如下所示:
|
||||
* B → S/I/L/F/D
|
||||
* S → B/I/L/F/D
|
||||
* I → B/S/L/F/D
|
||||
|
||||
@ -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.UnaryOperationInstruction;
|
||||
import org.jcnc.snow.compiler.ir.utils.ComparisonUtils;
|
||||
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
||||
import org.jcnc.snow.compiler.parser.ast.*;
|
||||
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <b>表达式构建器</b>
|
||||
* <b>ExpressionBuilder - 表达式 → IR 构建器</b>
|
||||
*
|
||||
* <p>
|
||||
* 该类负责将抽象语法树(AST)的表达式节点转换为中间表示(IR)指令和虚拟寄存器,
|
||||
* 是编译器IR生成阶段的核心工具。
|
||||
* <br/>
|
||||
* 主要职责包括:
|
||||
* 负责将 AST 表达式节点递归转换为 IR 虚拟寄存器操作,并生成对应的 IR 指令序列。
|
||||
* 支持字面量、标识符、二元表达式、一元表达式、函数调用等多种类型表达式。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 主要功能:
|
||||
* <ul>
|
||||
* <li>将数字字面量、标识符、二元表达式、函数调用等AST表达式节点,翻译为对应的IR指令序列</li>
|
||||
* <li>管理并分配虚拟寄存器,保证IR操作的数据流正确</li>
|
||||
* <li>将表达式节点映射为虚拟寄存器</li>
|
||||
* <li>为每种表达式类型生成对应 IR 指令</li>
|
||||
* <li>支持表达式嵌套的递归构建</li>
|
||||
* <li>支持写入指定目标寄存器,避免冗余的 move 指令</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* </p>
|
||||
*/
|
||||
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) {
|
||||
return switch (expr) {
|
||||
// 数字字面量
|
||||
// 数字字面量,例如 123、3.14
|
||||
case NumberLiteralNode n -> buildNumberLiteral(n.value());
|
||||
// 布尔字面量
|
||||
// 字符串字面量,例如 "abc"
|
||||
case StringLiteralNode s -> buildStringLiteral(s.value());
|
||||
// 布尔字面量,例如 true / false
|
||||
case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
|
||||
// 标识符
|
||||
// 标识符(变量名),如 a、b
|
||||
case IdentifierNode id -> {
|
||||
// 查找当前作用域中的变量寄存器
|
||||
IRVirtualRegister reg = ctx.getScope().lookup(id.name());
|
||||
if (reg == null)
|
||||
throw new IllegalStateException("未定义标识符: " + id.name());
|
||||
yield reg;
|
||||
}
|
||||
// 二元表达式
|
||||
// 二元表达式(如 a+b, x==y)
|
||||
case BinaryExpressionNode bin -> buildBinary(bin);
|
||||
// 函数调用
|
||||
case CallExpressionNode call -> buildCall(call);
|
||||
case UnaryExpressionNode u -> buildUnary(u);
|
||||
// 函数/方法调用表达式
|
||||
case CallExpressionNode call -> buildCall(call);
|
||||
// 一元表达式(如 -a, !a)
|
||||
case UnaryExpressionNode un -> buildUnary(un);
|
||||
|
||||
// 默认分支:遇到未知表达式类型则直接抛异常
|
||||
default -> throw new IllegalStateException(
|
||||
"不支持的表达式类型: " + expr.getClass().getSimpleName());
|
||||
};
|
||||
}
|
||||
|
||||
/** 处理一元表达式 */
|
||||
private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
|
||||
String op = un.operator();
|
||||
IRVirtualRegister val = build(un.operand());
|
||||
|
||||
// -x → NEG_*(根据类型自动选择位宽)
|
||||
if (op.equals("-")) {
|
||||
IRVirtualRegister dest = ctx.newRegister();
|
||||
IROpCode code = ExpressionUtils.negOp(un.operand());
|
||||
ctx.addInstruction(new UnaryOperationInstruction(code, dest, val));
|
||||
return dest;
|
||||
}
|
||||
|
||||
// !x → (x == 0)
|
||||
if (op.equals("!")) {
|
||||
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
|
||||
return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, val, zero);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("未知一元运算符: " + op);
|
||||
}
|
||||
/* ───────────────── 写入指定寄存器 ───────────────── */
|
||||
|
||||
/**
|
||||
* 直接将表达式计算结果写入指定的目标寄存器(dest)。
|
||||
* <p>
|
||||
* 与{@link #build(ExpressionNode)}类似,但支持目标寄存器复用(避免不必要的move)。
|
||||
* 生成表达式,并将其结果直接写入目标寄存器,避免冗余的 move 操作。
|
||||
*
|
||||
* @param node 表达式AST节点
|
||||
* @param dest 目标寄存器
|
||||
* @throws IllegalStateException 未定义标识符/不支持的表达式类型时报错
|
||||
* <p>
|
||||
* 某些简单表达式(如字面量、变量名)可以直接写入目标寄存器;复杂表达式则会先 build 到新寄存器,再 move 到目标寄存器。
|
||||
* </p>
|
||||
*
|
||||
* @param node 要生成的表达式节点
|
||||
* @param dest 目标虚拟寄存器(用于存储结果)
|
||||
*/
|
||||
public void buildInto(ExpressionNode node, IRVirtualRegister dest) {
|
||||
switch (node) {
|
||||
// 数字字面量,直接加载到目标寄存器
|
||||
// 数字字面量:生成 loadConst 指令写入目标寄存器
|
||||
case NumberLiteralNode n ->
|
||||
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
|
||||
// 标识符,查找并move到目标寄存器
|
||||
InstructionFactory.loadConstInto(
|
||||
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 -> {
|
||||
IRVirtualRegister src = ctx.getScope().lookup(id.name());
|
||||
if (src == null) throw new IllegalStateException("未定义标识符: " + id.name());
|
||||
if (src == null)
|
||||
throw new IllegalStateException("未定义标识符: " + id.name());
|
||||
InstructionFactory.move(ctx, src, dest);
|
||||
}
|
||||
// 二元表达式,直接写入目标寄存器
|
||||
|
||||
// 二元表达式:递归生成并写入目标寄存器
|
||||
case BinaryExpressionNode bin -> buildBinaryInto(bin, dest);
|
||||
// 其他表达式,先递归生成寄存器,再move到目标寄存器
|
||||
|
||||
// 其它复杂情况:先 build 到新寄存器,再 move 到目标寄存器
|
||||
default -> {
|
||||
IRVirtualRegister tmp = build(node);
|
||||
InstructionFactory.move(ctx, tmp, dest);
|
||||
@ -127,41 +123,100 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ───────────────── 具体表达式类型 ───────────────── */
|
||||
|
||||
/**
|
||||
* 构建二元表达式的IR,生成新寄存器存储结果。
|
||||
* <p>
|
||||
* 先递归构建左右操作数,之后根据操作符类别(算术或比较)决定生成的IR操作码,
|
||||
* 并生成对应的二元运算指令。
|
||||
* 一元表达式构建
|
||||
*
|
||||
* @param bin 二元表达式节点
|
||||
* @return 存放结果的虚拟寄存器
|
||||
* <p>
|
||||
* 支持算术取负(-a)、逻辑非(!a)等一元运算符。
|
||||
* </p>
|
||||
*
|
||||
* @param un 一元表达式节点
|
||||
* @return 结果存储的新分配虚拟寄存器
|
||||
*/
|
||||
private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
|
||||
String op = bin.operator();
|
||||
IRVirtualRegister left = build(bin.left());
|
||||
IRVirtualRegister right = build(bin.right());
|
||||
private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
|
||||
// 递归生成操作数的寄存器
|
||||
IRVirtualRegister src = build(un.operand());
|
||||
// 分配目标寄存器
|
||||
IRVirtualRegister dest = ctx.newRegister();
|
||||
|
||||
// 1. 比较运算
|
||||
if (ComparisonUtils.isComparisonOperator(op)) {
|
||||
return InstructionFactory.binOp(
|
||||
ctx,
|
||||
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
|
||||
left, right);
|
||||
switch (un.operator()) {
|
||||
// 算术负号:生成取负指令
|
||||
case "-" -> ctx.addInstruction(
|
||||
new UnaryOperationInstruction(ExpressionUtils.negOp(un.operand()), dest, src));
|
||||
// 逻辑非:等价于 a == 0,生成比较指令
|
||||
case "!" -> {
|
||||
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
|
||||
return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, src, zero);
|
||||
}
|
||||
// 其它一元运算符不支持,抛异常
|
||||
default -> throw new IllegalStateException("未知一元运算符: " + un.operator());
|
||||
}
|
||||
|
||||
// 2. 其他算术 / 逻辑运算
|
||||
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
||||
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
||||
return InstructionFactory.binOp(ctx, code, left, right);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将二元表达式的结果直接写入指定寄存器dest。
|
||||
* <p>
|
||||
* 结构与{@link #buildBinary(BinaryExpressionNode)}类似,但不会新分配寄存器。
|
||||
* 构建函数或方法调用表达式。
|
||||
*
|
||||
* @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 dest 目标寄存器
|
||||
* @return 存储表达式结果的虚拟寄存器
|
||||
*/
|
||||
private IRVirtualRegister buildBinary(BinaryExpressionNode bin) {
|
||||
// 递归生成左、右子表达式的寄存器
|
||||
IRVirtualRegister a = build(bin.left());
|
||||
IRVirtualRegister b = build(bin.right());
|
||||
String op = bin.operator();
|
||||
|
||||
// 比较运算符(==、!=、>、< 等),需要生成条件跳转或布尔值寄存器
|
||||
if (ComparisonUtils.isComparisonOperator(op)) {
|
||||
return InstructionFactory.binOp(
|
||||
ctx,
|
||||
// 通过比较工具获得合适的 IR 操作码
|
||||
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
|
||||
a, b);
|
||||
}
|
||||
|
||||
// 其它算术/位运算
|
||||
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
||||
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
||||
return InstructionFactory.binOp(ctx, code, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 二元表达式构建,结果直接写入目标寄存器(用于赋值左值等优化场景)。
|
||||
*
|
||||
* @param bin 二元表达式节点
|
||||
* @param dest 目标虚拟寄存器
|
||||
*/
|
||||
private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) {
|
||||
IRVirtualRegister a = build(bin.left());
|
||||
@ -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;
|
||||
}
|
||||
/* ───────────────── 字面量辅助方法 ───────────────── */
|
||||
|
||||
/**
|
||||
* 处理数字字面量,生成常量寄存器和加载指令。
|
||||
* <p>
|
||||
* 会将字符串型字面量(如 "123", "1.0f")解析为具体的IRConstant,
|
||||
* 并分配一个新的虚拟寄存器来存放该常量。
|
||||
* 构建数字字面量表达式(如 123),分配新寄存器并生成 LoadConst 指令。
|
||||
*
|
||||
* @param value 字面量字符串
|
||||
* @return 存放该常量的寄存器
|
||||
* @param value 字面量文本(字符串格式)
|
||||
* @return 存储该字面量的寄存器
|
||||
*/
|
||||
private IRVirtualRegister buildNumberLiteral(String value) {
|
||||
IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value);
|
||||
IRVirtualRegister reg = ctx.newRegister();
|
||||
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
||||
return reg;
|
||||
IRConstant c = ExpressionUtils.buildNumberConstant(ctx, value);
|
||||
IRVirtualRegister r = ctx.newRegister();
|
||||
ctx.addInstruction(new LoadConstInstruction(r, c));
|
||||
return r;
|
||||
}
|
||||
|
||||
/** 布尔字面量 → CONST (true=1,false=0)*/
|
||||
private IRVirtualRegister buildBoolLiteral(boolean value) {
|
||||
IRConstant constant = new IRConstant(value ? 1 : 0);
|
||||
IRVirtualRegister reg = ctx.newRegister();
|
||||
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
||||
return reg;
|
||||
/**
|
||||
* 构建字符串字面量表达式,分配新寄存器并生成 LoadConst 指令。
|
||||
*
|
||||
* @param value 字符串内容
|
||||
* @return 存储该字符串的寄存器
|
||||
*/
|
||||
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 表示 true,0 表示 false)。
|
||||
*
|
||||
* @param v 布尔值
|
||||
* @return 存储 1/0 的寄存器
|
||||
*/
|
||||
private IRVirtualRegister buildBoolLiteral(boolean v) {
|
||||
IRConstant c = new IRConstant(v ? 1 : 0);
|
||||
IRVirtualRegister r = ctx.newRegister();
|
||||
ctx.addInstruction(new LoadConstInstruction(r, c));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ public class FunctionBuilder {
|
||||
/**
|
||||
* 将 AST 中的 FunctionNode 构建为可执行的 IRFunction。
|
||||
* <p>
|
||||
* 构建过程包括:
|
||||
* 构建过程包括:
|
||||
* <ol>
|
||||
* <li>初始化 IRFunction 实例和上下文</li>
|
||||
* <li>根据函数返回类型,设置默认类型后缀,便于表达式推断</li>
|
||||
@ -37,7 +37,7 @@ public class FunctionBuilder {
|
||||
GlobalFunctionTable.register(functionNode.name(), functionNode.returnType());
|
||||
|
||||
|
||||
// 0) 基本初始化:创建 IRFunction 实例与对应上下文
|
||||
// 0) 基本初始化: 创建 IRFunction 实例与对应上下文
|
||||
IRFunction irFunction = new IRFunction(functionNode.name());
|
||||
IRContext irContext = new IRContext(irFunction);
|
||||
|
||||
@ -53,14 +53,14 @@ public class FunctionBuilder {
|
||||
ExpressionUtils.setDefaultSuffix(_returnSuffix);
|
||||
|
||||
try {
|
||||
// 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域
|
||||
// 2) 声明形参: 为每个参数分配虚拟寄存器并声明到作用域
|
||||
for (ParameterNode p : functionNode.parameters()) {
|
||||
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
|
||||
irContext.getScope().declare(p.name(), p.type(), reg); // 变量名→寄存器绑定
|
||||
irFunction.addParameter(reg); // 添加到函数参数列表
|
||||
}
|
||||
|
||||
// 3) 生成函数体 IR:遍历每条语句,逐一转化
|
||||
// 3) 生成函数体 IR: 遍历每条语句,逐一转化
|
||||
StatementBuilder stmtBuilder = new StatementBuilder(irContext);
|
||||
for (StatementNode stmt : functionNode.body()) {
|
||||
stmtBuilder.build(stmt);
|
||||
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
/**
|
||||
* IRBuilderScope 用于管理单个函数内变量名与虚拟寄存器的映射关系。
|
||||
*
|
||||
* <p>主要功能包括:
|
||||
* <p>主要功能包括:
|
||||
* <ul>
|
||||
* <li>维护在当前作用域中已声明变量的寄存器分配信息;</li>
|
||||
* <li>支持将已有虚拟寄存器与变量名重新绑定;</li>
|
||||
|
||||
@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
* 以及与之配套的作用域管理(IRBuilderScope),
|
||||
* 并简化虚拟寄存器分配与 IR 指令添加操作。
|
||||
*
|
||||
* <p>本类提供以下核心功能:
|
||||
* <p>本类提供以下核心功能:
|
||||
* <ul>
|
||||
* <li>持有并操作当前 IRFunction 对象;</li>
|
||||
* <li>管理变量名与虚拟寄存器的映射关系;</li>
|
||||
@ -62,7 +62,7 @@ public class IRContext {
|
||||
/**
|
||||
* 获取当前函数的变量与寄存器映射作用域。
|
||||
*
|
||||
* <p>包内可见:仅限 builder 包内部使用。
|
||||
* <p>包内可见: 仅限 builder 包内部使用。
|
||||
*
|
||||
* @return IRBuilderScope 实例
|
||||
*/
|
||||
|
||||
@ -13,7 +13,7 @@ import java.util.List;
|
||||
/**
|
||||
* 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram。
|
||||
*
|
||||
* <p>主要职责:
|
||||
* <p>主要职责:
|
||||
* <ul>
|
||||
* <li>遍历输入的顶层节点,识别 ModuleNode、FunctionNode 及脚本式顶层 StatementNode;</li>
|
||||
* <li>对 ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram;</li>
|
||||
@ -36,13 +36,13 @@ public final class IRProgramBuilder {
|
||||
for (Node node : roots) {
|
||||
switch (node) {
|
||||
case ModuleNode moduleNode ->
|
||||
// 模块节点:批量构建并添加模块内所有函数
|
||||
// 模块节点: 批量构建并添加模块内所有函数
|
||||
moduleNode.functions().forEach(f -> irProgram.add(buildFunction(f)));
|
||||
case FunctionNode functionNode ->
|
||||
// 顶层函数节点:直接构建并添加
|
||||
// 顶层函数节点: 直接构建并添加
|
||||
irProgram.add(buildFunction(functionNode));
|
||||
case StatementNode statementNode ->
|
||||
// 脚本式顶层语句:封装为“_start”函数后构建并添加
|
||||
// 脚本式顶层语句: 封装为“_start”函数后构建并添加
|
||||
irProgram.add(buildFunction(wrapTopLevel(statementNode)));
|
||||
default ->
|
||||
// 严格校验节点类型,遇不支持者立即失败
|
||||
@ -65,7 +65,7 @@ public final class IRProgramBuilder {
|
||||
/**
|
||||
* 将单个脚本式顶层 StatementNode 封装为名称固定的“_start”函数节点。
|
||||
*
|
||||
* <p>封装规则:
|
||||
* <p>封装规则:
|
||||
* <ul>
|
||||
* <li>函数名固定为“_start”;</li>
|
||||
* <li>返回类型设为 null,由后续流程处理;</li>
|
||||
|
||||
@ -80,7 +80,7 @@ public class InstructionFactory {
|
||||
/**
|
||||
* Move 指令(src → dest)。若寄存器相同也安全。
|
||||
* <p>
|
||||
* 实现方式:dest = src + 0(即加上常量 0)。
|
||||
* 实现方式: dest = src + 0(即加上常量 0)。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 当前 IR 上下文
|
||||
@ -92,7 +92,7 @@ public class InstructionFactory {
|
||||
if (src == dest) {
|
||||
return;
|
||||
}
|
||||
// 回退实现:dest = src + 0
|
||||
// 回退实现: dest = src + 0
|
||||
IRVirtualRegister zero = loadConst(ctx, 0);
|
||||
ctx.addInstruction(new BinaryOperationInstruction(IROpCode.ADD_I32, dest, src, zero));
|
||||
}
|
||||
|
||||
@ -150,23 +150,23 @@ public class StatementBuilder {
|
||||
|
||||
/**
|
||||
* 构建循环语句(for/while)。
|
||||
* 处理流程:初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
||||
* 处理流程: 初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
||||
*
|
||||
* @param loop 循环节点
|
||||
*/
|
||||
private void buildLoop(LoopNode loop) {
|
||||
if (loop.initializer() != null) build(loop.initializer());
|
||||
if (loop.init() != null) build(loop.init());
|
||||
String lblStart = ctx.newLabel();
|
||||
String lblEnd = ctx.newLabel();
|
||||
// 循环开始标签
|
||||
InstructionFactory.label(ctx, lblStart);
|
||||
|
||||
// 条件不满足则跳出循环
|
||||
emitConditionalJump(loop.condition(), lblEnd);
|
||||
emitConditionalJump(loop.cond(), lblEnd);
|
||||
// 构建循环体
|
||||
buildStatements(loop.body());
|
||||
// 更新部分(如 for 的 i++)
|
||||
if (loop.update() != null) build(loop.update());
|
||||
if (loop.step() != null) build(loop.step());
|
||||
|
||||
// 跳回循环起点
|
||||
InstructionFactory.jmp(ctx, lblStart);
|
||||
@ -176,7 +176,7 @@ public class StatementBuilder {
|
||||
|
||||
/**
|
||||
* 构建分支语句(if/else)。
|
||||
* 处理流程:条件判断 → then 分支 → else 分支(可选)。
|
||||
* 处理流程: 条件判断 → then 分支 → else 分支(可选)。
|
||||
*
|
||||
* @param ifNode if 语句节点
|
||||
*/
|
||||
|
||||
@ -22,8 +22,8 @@ public final class GlobalFunctionTable {
|
||||
/**
|
||||
* 存储全局函数返回类型映射表。
|
||||
* <ul>
|
||||
* <li>Key:函数名(不含模块限定)</li>
|
||||
* <li>Value:返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}</li>
|
||||
* <li>Key: 函数名(不含模块限定)</li>
|
||||
* <li>Value: 返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}</li>
|
||||
* </ul>
|
||||
*/
|
||||
private static final Map<String, String> RETURN_TYPES = new ConcurrentHashMap<>();
|
||||
|
||||
@ -112,7 +112,7 @@ public class IRFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 以IR代码表示,示例:
|
||||
* 以IR代码表示,示例:
|
||||
* <pre>
|
||||
* func 名称(%0, %1, ...) {
|
||||
* 指令0
|
||||
|
||||
@ -24,95 +24,95 @@ public enum IROpCode {
|
||||
CONV_D64_TO_F32,
|
||||
|
||||
|
||||
/* ───── 算术运算(8位整数:byte)───── */
|
||||
ADD_B8, // 8位整型加法:a = b + c
|
||||
SUB_B8, // 8位整型减法:a = b - c
|
||||
MUL_B8, // 8位整型乘法:a = b * c
|
||||
DIV_B8, // 8位整型除法:a = b / c
|
||||
NEG_B8, // 8位整型取负:a = -b
|
||||
/* ───── 算术运算(8位整数: byte)───── */
|
||||
ADD_B8, // 8位整型加法: a = b + c
|
||||
SUB_B8, // 8位整型减法: a = b - c
|
||||
MUL_B8, // 8位整型乘法: a = b * c
|
||||
DIV_B8, // 8位整型除法: a = b / c
|
||||
NEG_B8, // 8位整型取负: a = -b
|
||||
|
||||
/* ───── 算术运算(16位整数:short)───── */
|
||||
/* ───── 算术运算(16位整数: short)───── */
|
||||
ADD_S16, // 16位整型加法
|
||||
SUB_S16, // 16位整型减法
|
||||
MUL_S16, // 16位整型乘法
|
||||
DIV_S16, // 16位整型除法
|
||||
NEG_S16, // 16位整型取负
|
||||
|
||||
/* ───── 算术运算(32位整数:int)───── */
|
||||
/* ───── 算术运算(32位整数: int)───── */
|
||||
ADD_I32, // 32位整型加法
|
||||
SUB_I32, // 32位整型减法
|
||||
MUL_I32, // 32位整型乘法
|
||||
DIV_I32, // 32位整型除法
|
||||
NEG_I32, // 32位整型取负
|
||||
|
||||
/* ───── 算术运算(64位整数:long)───── */
|
||||
/* ───── 算术运算(64位整数: long)───── */
|
||||
ADD_L64, // 64位整型加法
|
||||
SUB_L64, // 64位整型减法
|
||||
MUL_L64, // 64位整型乘法
|
||||
DIV_L64, // 64位整型除法
|
||||
NEG_L64, // 64位整型取负
|
||||
|
||||
/* ───── 算术运算(32位浮点数:float)───── */
|
||||
/* ───── 算术运算(32位浮点数: float)───── */
|
||||
ADD_F32, // 32位浮点加法
|
||||
SUB_F32, // 32位浮点减法
|
||||
MUL_F32, // 32位浮点乘法
|
||||
DIV_F32, // 32位浮点除法
|
||||
NEG_F32, // 32位浮点取负
|
||||
|
||||
/* ───── 算术运算(64位浮点数:double)───── */
|
||||
/* ───── 算术运算(64位浮点数: double)───── */
|
||||
ADD_D64, // 64位浮点加法
|
||||
SUB_D64, // 64位浮点减法
|
||||
MUL_D64, // 64位浮点乘法
|
||||
DIV_D64, // 64位浮点除法
|
||||
NEG_D64, // 64位浮点取负
|
||||
|
||||
/* ───── 逻辑与比较运算指令(8位整数:byte) ───── */
|
||||
CMP_BEQ, // 8位整数相等比较:a == b
|
||||
CMP_BNE, // 8位整数不等比较:a != b
|
||||
CMP_BLT, // 8位整数小于比较:a < b
|
||||
CMP_BGT, // 8位整数大于比较:a > b
|
||||
CMP_BLE, // 8位整数小于等于:a <= b
|
||||
CMP_BGE, // 8位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(8位整数: byte) ───── */
|
||||
CMP_BEQ, // 8位整数相等比较: a == b
|
||||
CMP_BNE, // 8位整数不等比较: a != b
|
||||
CMP_BLT, // 8位整数小于比较: a < b
|
||||
CMP_BGT, // 8位整数大于比较: a > b
|
||||
CMP_BLE, // 8位整数小于等于: a <= b
|
||||
CMP_BGE, // 8位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(16位整数:int) ───── */
|
||||
CMP_SEQ, // 16位整数相等比较:a == b
|
||||
CMP_SNE, // 16位整数不等比较:a != b
|
||||
CMP_SLT, // 16位整数小于比较:a < b
|
||||
CMP_SGT, // 16位整数大于比较:a > b
|
||||
CMP_SLE, // 16位整数小于等于:a <= b
|
||||
CMP_SGE, // 16位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(16位整数: int) ───── */
|
||||
CMP_SEQ, // 16位整数相等比较: a == b
|
||||
CMP_SNE, // 16位整数不等比较: a != b
|
||||
CMP_SLT, // 16位整数小于比较: a < b
|
||||
CMP_SGT, // 16位整数大于比较: a > b
|
||||
CMP_SLE, // 16位整数小于等于: a <= b
|
||||
CMP_SGE, // 16位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(32位整数:int) ───── */
|
||||
CMP_IEQ, // 32位整数相等比较:a == b
|
||||
CMP_INE, // 32位整数不等比较:a != b
|
||||
CMP_ILT, // 32位整数小于比较:a < b
|
||||
CMP_IGT, // 32位整数大于比较:a > b
|
||||
CMP_ILE, // 32位整数小于等于:a <= b
|
||||
CMP_IGE, // 32位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(32位整数: int) ───── */
|
||||
CMP_IEQ, // 32位整数相等比较: a == b
|
||||
CMP_INE, // 32位整数不等比较: a != b
|
||||
CMP_ILT, // 32位整数小于比较: a < b
|
||||
CMP_IGT, // 32位整数大于比较: a > b
|
||||
CMP_ILE, // 32位整数小于等于: a <= b
|
||||
CMP_IGE, // 32位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(64位整数:long) ───── */
|
||||
CMP_LEQ, // 64位整数相等比较:a == b
|
||||
CMP_LNE, // 64位整数不等比较:a != b
|
||||
CMP_LLT, // 64位整数小于比较:a < b
|
||||
CMP_LGT, // 64位整数大于比较:a > b
|
||||
CMP_LLE, // 64位整数小于等于:a <= b
|
||||
CMP_LGE, // 64位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(64位整数: long) ───── */
|
||||
CMP_LEQ, // 64位整数相等比较: a == b
|
||||
CMP_LNE, // 64位整数不等比较: a != b
|
||||
CMP_LLT, // 64位整数小于比较: a < b
|
||||
CMP_LGT, // 64位整数大于比较: a > b
|
||||
CMP_LLE, // 64位整数小于等于: a <= b
|
||||
CMP_LGE, // 64位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(32位浮点数:float) ───── */
|
||||
CMP_FEQ, // 32位浮点相等比较:a == b
|
||||
CMP_FNE, // 32位浮点不等比较:a != b
|
||||
CMP_FLT, // 32位浮点小于比较:a < b
|
||||
CMP_FGT, // 32位浮点大于比较:a > b
|
||||
CMP_FLE, // 32位浮点小于等于:a <= b
|
||||
CMP_FGE, // 32位浮点大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(32位浮点数: float) ───── */
|
||||
CMP_FEQ, // 32位浮点相等比较: a == b
|
||||
CMP_FNE, // 32位浮点不等比较: a != b
|
||||
CMP_FLT, // 32位浮点小于比较: a < b
|
||||
CMP_FGT, // 32位浮点大于比较: a > b
|
||||
CMP_FLE, // 32位浮点小于等于: a <= b
|
||||
CMP_FGE, // 32位浮点大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(64位浮点数:double) ───── */
|
||||
CMP_DEQ, // 64位浮点相等比较:a == b
|
||||
CMP_DNE, // 64位浮点不等比较:a != b
|
||||
CMP_DLT, // 64位浮点小于比较:a < b
|
||||
CMP_DGT, // 64位浮点大于比较:a > b
|
||||
CMP_DLE, // 64位浮点小于等于:a <= b
|
||||
CMP_DGE, // 64位浮点大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(64位浮点数: double) ───── */
|
||||
CMP_DEQ, // 64位浮点相等比较: a == b
|
||||
CMP_DNE, // 64位浮点不等比较: a != b
|
||||
CMP_DLT, // 64位浮点小于比较: a < b
|
||||
CMP_DGT, // 64位浮点大于比较: a > b
|
||||
CMP_DLE, // 64位浮点小于等于: a <= b
|
||||
CMP_DGE, // 64位浮点大于等于: a >= b
|
||||
|
||||
/* ───── 数据访问与常量操作 ───── */
|
||||
LOAD, // 从内存加载数据至寄存器
|
||||
|
||||
@ -11,11 +11,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
* 实现该接口的类型可以作为 {@link IRInstruction} 中的操作数出现。
|
||||
* </p>
|
||||
*
|
||||
* <p>当前支持的 IR 值类型包括:</p>
|
||||
* <p>当前支持的 IR 值类型包括: </p>
|
||||
* <ul>
|
||||
* <li>{@link IRVirtualRegister}:虚拟寄存器,表示计算结果或中间变量</li>
|
||||
* <li>{@link IRConstant}:常量值,表示不可变的字面量或数值</li>
|
||||
* <li>{@link IRLabel}:标签,表示跳转指令的目标地址</li>
|
||||
* <li>{@link IRVirtualRegister}: 虚拟寄存器,表示计算结果或中间变量</li>
|
||||
* <li>{@link IRConstant}: 常量值,表示不可变的字面量或数值</li>
|
||||
* <li>{@link IRLabel}: 标签,表示跳转指令的目标地址</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
|
||||
@ -7,12 +7,12 @@ import org.jcnc.snow.compiler.ir.instruction.*;
|
||||
* <p>
|
||||
* 它定义了访问者模式的核心机制,通过对每种 {@link IRInstruction} 子类
|
||||
* 提供独立的 {@code visit} 方法,实现对指令的分发与处理。
|
||||
* 不同的访问者实现可用于执行不同任务,例如:
|
||||
* 不同的访问者实现可用于执行不同任务,例如:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@code IRPrinter}:打印指令内容</li>
|
||||
* <li>{@code IROptimizer}:分析与重写 IR 以优化性能</li>
|
||||
* <li>{@code IRCodeGenerator}:生成平台相关的机器码或汇编代码</li>
|
||||
* <li>{@code IRPrinter}: 打印指令内容</li>
|
||||
* <li>{@code IROptimizer}: 分析与重写 IR 以优化性能</li>
|
||||
* <li>{@code IRCodeGenerator}: 生成平台相关的机器码或汇编代码</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
|
||||
@ -11,27 +11,27 @@ IR 模块以类 SSA(Static Single Assignment)形式设计,通过统一的
|
||||
|
||||
## 核心功能
|
||||
|
||||
* **统一的中间表示模型**:表达控制流与数据流,支持函数、指令、值等核心结构
|
||||
* **IR 构建器体系**:模块化构建函数、表达式与语句 IR,简化前端对接
|
||||
* **灵活的指令层级结构**:支持二元操作、跳转、返回等多种基本指令
|
||||
* **寄存器与常量模型**:统一管理虚拟寄存器、常量、标签等值类型
|
||||
* **IR 打印与调试支持**:辅助输出 IR 文本格式,支持可视化与调试
|
||||
* **统一的中间表示模型**: 表达控制流与数据流,支持函数、指令、值等核心结构
|
||||
* **IR 构建器体系**: 模块化构建函数、表达式与语句 IR,简化前端对接
|
||||
* **灵活的指令层级结构**: 支持二元操作、跳转、返回等多种基本指令
|
||||
* **寄存器与常量模型**: 统一管理虚拟寄存器、常量、标签等值类型
|
||||
* **IR 打印与调试支持**: 辅助输出 IR 文本格式,支持可视化与调试
|
||||
|
||||
## 模块结构
|
||||
|
||||
```
|
||||
ir/
|
||||
├── builder/ // 构建器模块:负责构造表达式、函数与语句的 IR
|
||||
├── core/ // 核心定义:IR 基础结构,如函数、指令、程序、访问器等
|
||||
├── instruction/ // 指令实现:具体的 IR 指令类型(如加法、跳转、返回等)
|
||||
├── utils/ // 工具模块:提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等)
|
||||
└── value/ // 值模型:常量、标签、虚拟寄存器等
|
||||
├── builder/ // 构建器模块: 负责构造表达式、函数与语句的 IR
|
||||
├── core/ // 核心定义: IR 基础结构,如函数、指令、程序、访问器等
|
||||
├── instruction/ // 指令实现: 具体的 IR 指令类型(如加法、跳转、返回等)
|
||||
├── utils/ // 工具模块: 提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等)
|
||||
└── value/ // 值模型: 常量、标签、虚拟寄存器等
|
||||
```
|
||||
|
||||
## 开发环境
|
||||
|
||||
* JDK 24 或更高版本
|
||||
* Maven 构建管理
|
||||
* 推荐 IDE:IntelliJ IDEA
|
||||
* 推荐 IDE: IntelliJ IDEA
|
||||
|
||||
---
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BinaryOperationInstruction —— 表示一个二元运算指令,格式为:dest = lhs OP rhs
|
||||
* BinaryOperationInstruction —— 表示一个二元运算指令,格式为: dest = lhs OP rhs
|
||||
* <p>
|
||||
* 该类用于描述形如 a = b + c 或 a = x * y 的二元运算指令。
|
||||
* 运算类型(OP)由 {@link IROpCode} 指定,包括加法、减法、乘法、除法等。
|
||||
@ -76,7 +76,7 @@ public final class BinaryOperationInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 转换为字符串格式,便于调试与打印。
|
||||
* 例:v1 = ADD_I32 v2, v3
|
||||
* 例: v1 = ADD_I32 v2, v3
|
||||
*
|
||||
* @return 指令的字符串表示形式
|
||||
*/
|
||||
|
||||
@ -46,7 +46,7 @@ public class CallInstruction extends IRInstruction {
|
||||
return isVoidReturn() ? null : dest;
|
||||
}
|
||||
|
||||
/** 操作数列表:void 调用不包含 dest */
|
||||
/** 操作数列表: void 调用不包含 dest */
|
||||
@Override
|
||||
public List<IRValue> operands() {
|
||||
List<IRValue> ops = new ArrayList<>();
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IRAddInstruction —— 表示一个加法指令,形如:dest = lhs + rhs
|
||||
* IRAddInstruction —— 表示一个加法指令,形如: dest = lhs + rhs
|
||||
* <p>
|
||||
* 本类是一个具体的 IRInstruction 子类,表示将两个值相加,并将结果写入目标寄存器的操作。
|
||||
* 虽然功能与通用的 {@link BinaryOperationInstruction} 类似,但它作为更简化明确的指令实现,
|
||||
@ -40,7 +40,7 @@ public class IRAddInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回该指令的操作码:ADD_I32。
|
||||
* 返回该指令的操作码: ADD_I32。
|
||||
*
|
||||
* @return 加法操作码
|
||||
*/
|
||||
@ -81,7 +81,7 @@ public class IRAddInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 返回指令的字符串形式,方便调试。
|
||||
* 例如:v1 = v2 + v3
|
||||
* 例如: v1 = v2 + v3
|
||||
*
|
||||
* @return 字符串表示形式
|
||||
*/
|
||||
|
||||
@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.ir.core.IRVisitor;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
/**
|
||||
* “比较 + 条件跳转” 复合指令:
|
||||
* “比较 + 条件跳转” 复合指令:
|
||||
* if ( left <cmpOp> right ) jump targetLabel;
|
||||
* <p>
|
||||
* 其中 cmpOp 只能是 IROpCode.CMP_* 六种比较操作码。
|
||||
|
||||
@ -25,7 +25,7 @@ public class IRJumpInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该指令对应的操作码:JUMP。
|
||||
* 获取该指令对应的操作码: JUMP。
|
||||
*
|
||||
* @return IROpCode.JUMP
|
||||
*/
|
||||
@ -55,7 +55,7 @@ public class IRJumpInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 将指令转为字符串形式,便于打印与调试。
|
||||
* 例如:jump L1
|
||||
* 例如: jump L1
|
||||
*
|
||||
* @return 指令的字符串表示
|
||||
*/
|
||||
|
||||
@ -29,7 +29,7 @@ public class IRReturnInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该指令的操作码:RET。
|
||||
* 获取该指令的操作码: RET。
|
||||
*
|
||||
* @return IROpCode.RET,表示返回操作
|
||||
*/
|
||||
@ -60,7 +60,7 @@ public class IRReturnInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 转换为字符串形式,便于调试与打印。
|
||||
* 示例:ret v1
|
||||
* 示例: ret v1
|
||||
*
|
||||
* @return 字符串形式的返回指令
|
||||
*/
|
||||
|
||||
@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LoadConstInstruction —— 表示一个常量加载指令,格式为:dest = CONST k
|
||||
* LoadConstInstruction —— 表示一个常量加载指令,格式为: dest = CONST k
|
||||
* <p>
|
||||
* 该指令的功能是将一个常量(字面量或编译期已知值)加载到一个虚拟寄存器中,
|
||||
* 供后续指令使用。例如,在表达式计算、参数传递、初始化等场景中常用。
|
||||
@ -66,7 +66,7 @@ public final class LoadConstInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 返回该指令的字符串形式,便于调试或打印。
|
||||
* 例如:v1 = CONST 42
|
||||
* 例如: v1 = CONST 42
|
||||
*
|
||||
* @return 指令的字符串表示
|
||||
*/
|
||||
|
||||
@ -9,11 +9,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ReturnInstruction —— 表示函数返回指令,格式:RET 或 RET <value>
|
||||
* ReturnInstruction —— 表示函数返回指令,格式: RET 或 RET <value>
|
||||
* <p>
|
||||
* 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
|
||||
* - 无返回值(void):生成无参的 RET 指令
|
||||
* - 有返回值:将指定虚拟寄存器中的值返回给调用者
|
||||
* 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
|
||||
* - 无返回值(void): 生成无参的 RET 指令
|
||||
* - 有返回值: 将指定虚拟寄存器中的值返回给调用者
|
||||
* <p>
|
||||
* 与 {@link IRReturnInstruction} 类似,但更通用,适配多种函数返回风格。
|
||||
*/
|
||||
@ -36,7 +36,7 @@ public final class ReturnInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回该指令的操作码类型:RET。
|
||||
* 返回该指令的操作码类型: RET。
|
||||
*
|
||||
* @return IROpCode.RET
|
||||
*/
|
||||
@ -68,8 +68,8 @@ public final class ReturnInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 转换为字符串形式,便于调试与输出。
|
||||
* - 无返回值:RET
|
||||
* - 有返回值:RET v1
|
||||
* - 无返回值: RET
|
||||
* - 有返回值: RET v1
|
||||
*
|
||||
* @return 字符串表示的返回指令
|
||||
*/
|
||||
|
||||
@ -9,14 +9,14 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* UnaryOperationInstruction —— 表示一个一元运算指令,格式:dest = OP val
|
||||
* UnaryOperationInstruction —— 表示一个一元运算指令,格式: dest = OP val
|
||||
* <p>
|
||||
* 用于对单个操作数 val 执行指定的一元运算 OP(例如取负 NEG),
|
||||
* 并将结果写入目标虚拟寄存器 dest。
|
||||
* <p>
|
||||
* 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
|
||||
* 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
|
||||
* <ul>
|
||||
* <li>NEG_I32 —— 整数取负:dest = -val</li>
|
||||
* <li>NEG_I32 —— 整数取负: dest = -val</li>
|
||||
* <li>(可扩展)逻辑非、按位非等</li>
|
||||
* </ul>
|
||||
*/
|
||||
@ -76,7 +76,7 @@ public final class UnaryOperationInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 将该指令格式化为字符串,便于打印与调试。
|
||||
* 形式:dest = OP val,例如:v1 = NEG v2
|
||||
* 形式: dest = OP val,例如: v1 = NEG v2
|
||||
*
|
||||
* @return 字符串形式的指令
|
||||
*/
|
||||
|
||||
@ -16,11 +16,11 @@ import java.util.Map;
|
||||
* 支持自动类型提升,保证 int、long、float、double 等类型的比较均能得到正确的 IR 指令。
|
||||
* </p>
|
||||
*
|
||||
* 类型判定支持:
|
||||
* 类型判定支持:
|
||||
* <ul>
|
||||
* <li>字面量后缀:支持 B/S/I/L/F/D(大小写均可)</li>
|
||||
* <li>浮点数支持:如无后缀但有小数点,视为 double</li>
|
||||
* <li>变量类型:根据传入变量表推断类型,未识别则默认 int</li>
|
||||
* <li>字面量后缀: 支持 B/S/I/L/F/D(大小写均可)</li>
|
||||
* <li>浮点数支持: 如无后缀但有小数点,视为 double</li>
|
||||
* <li>变量类型: 根据传入变量表推断类型,未识别则默认 int</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ComparisonUtils {
|
||||
@ -39,7 +39,7 @@ public final class ComparisonUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
|
||||
* 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
|
||||
* - D (double): 6
|
||||
* - F (float): 5
|
||||
* - L (long): 4
|
||||
@ -106,7 +106,7 @@ public final class ComparisonUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部工具方法:根据表达式节点和变量表推断类型标记字符。
|
||||
* 内部工具方法: 根据表达式节点和变量表推断类型标记字符。
|
||||
* 字面量支持 B/S/I/L/F/D(大小写均可),浮点数默认 double;
|
||||
* 标识符类型按变量表映射,未知则默认 int。
|
||||
*
|
||||
|
||||
@ -14,7 +14,7 @@ import java.util.Map;
|
||||
/**
|
||||
* 表达式分析与操作符选择工具类。
|
||||
* <p>
|
||||
* 主要功能:
|
||||
* 主要功能:
|
||||
* - 解析字面量常量,自动推断类型
|
||||
* - 自动匹配并选择适合的算术/比较操作码
|
||||
* - 表达式类型的合并与类型提升
|
||||
@ -138,7 +138,7 @@ public final class ExpressionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧逻辑:仅凭操作符直接返回 int32 比较指令。
|
||||
* 兼容旧逻辑: 仅凭操作符直接返回 int32 比较指令。
|
||||
*
|
||||
* @param op 比较操作符
|
||||
* @return int32 类型的比较操作码
|
||||
@ -148,7 +148,7 @@ public final class ExpressionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 推荐调用:根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码。
|
||||
* 推荐调用: 根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码。
|
||||
*
|
||||
* @param variables 变量名到类型的映射
|
||||
* @param op 比较符号
|
||||
@ -196,7 +196,7 @@ public final class ExpressionUtils {
|
||||
|
||||
/**
|
||||
* 返回两个类型后缀中的最大类型(宽度优先)。
|
||||
* 优先级:d > f > l > i > s > b > '\0'
|
||||
* 优先级: d > f > l > i > s > b > '\0'
|
||||
*
|
||||
* @param l 类型后缀1
|
||||
* @param r 类型后缀2
|
||||
|
||||
@ -9,18 +9,18 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
|
||||
* 与 {@link IRVirtualRegister} 不同,常量不需要通过寄存器存储,
|
||||
* 可直接作为 IR 指令的操作数使用。
|
||||
* <p>
|
||||
* 典型应用:
|
||||
* - 加载常量指令:v1 = CONST 42
|
||||
* - 计算表达式:v2 = ADD v1, 100
|
||||
* 典型应用:
|
||||
* - 加载常量指令: v1 = CONST 42
|
||||
* - 计算表达式: v2 = ADD v1, 100
|
||||
*/
|
||||
public record IRConstant(Object value) implements IRValue {
|
||||
|
||||
/**
|
||||
* 将常量值转换为字符串,用于打印 IR 指令或调试输出。
|
||||
* <p>
|
||||
* 例如:
|
||||
* - 整数常量:42
|
||||
* - 字符串常量:"hello"
|
||||
* 例如:
|
||||
* - 整数常量: 42
|
||||
* - 字符串常量: "hello"
|
||||
*
|
||||
* @return 常量的字符串表示
|
||||
*/
|
||||
|
||||
@ -8,11 +8,11 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
|
||||
* 在 IR 系统中,虚拟寄存器用于存储每个中间计算结果,是 SSA(Static Single Assignment)形式的核心。
|
||||
* 每个虚拟寄存器在程序中只被赋值一次,其值来源于一条明确的指令输出。
|
||||
* <p>
|
||||
* 特点:
|
||||
* 特点:
|
||||
* <ul>
|
||||
* <li>每个寄存器有唯一编号 {@code id},由 {@code IRFunction.newRegister()} 自动生成</li>
|
||||
* <li>实现 {@link IRValue} 接口,可作为 IRInstruction 的操作数</li>
|
||||
* <li>具备良好的打印与调试格式:%id</li>
|
||||
* <li>具备良好的打印与调试格式: %id</li>
|
||||
* </ul>
|
||||
*
|
||||
* 适用于表达式求值、参数传递、函数返回值、临时变量等所有中间值场景。
|
||||
@ -23,7 +23,7 @@ public record IRVirtualRegister(int id) implements IRValue {
|
||||
|
||||
/**
|
||||
* 将虚拟寄存器转换为字符串格式,方便输出和调试。
|
||||
* 格式为:%<id>,例如 %3 表示编号为 3 的虚拟寄存器。
|
||||
* 格式为: %<id>,例如 %3 表示编号为 3 的虚拟寄存器。
|
||||
*
|
||||
* @return 格式化的字符串表示
|
||||
*/
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.lexer.base.TokenScanner;
|
||||
* 是 {@link TokenScanner} 实现进行词法识别的基础设施。
|
||||
* </p>
|
||||
* <p>
|
||||
* 设计要点:
|
||||
* 设计要点:
|
||||
* <ul>
|
||||
* <li>构造时统一将 Windows 换行符 (<code>\r\n</code>) 转换为 Unix 风格 (<code>\n</code>)。</li>
|
||||
* <li>所有坐标均以 <strong>1</strong> 为起始行/列号,更贴合人类直觉。</li>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jcnc.snow.compiler.lexer.core;
|
||||
|
||||
import org.jcnc.snow.common.SnowConfig;
|
||||
import org.jcnc.snow.compiler.lexer.base.TokenScanner;
|
||||
import org.jcnc.snow.compiler.lexer.scanners.*;
|
||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
@ -10,9 +11,11 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jcnc.snow.common.SnowConfig.print;
|
||||
|
||||
/**
|
||||
* Snow 语言词法分析器核心实现。
|
||||
* <p>采用“<b>先扫描 → 后批量校验 → 统一报告</b>”策略:
|
||||
* <p>采用“<b>先扫描 → 后批量校验 → 统一报告</b>”策略:
|
||||
* <ol>
|
||||
* <li>{@link #scanAllTokens()}— 用扫描器链把字符流拆成 {@link Token}</li>
|
||||
* <li>{@link #validateTokens()}— 基于 token 序列做轻量上下文校验</li>
|
||||
@ -21,20 +24,21 @@ import java.util.List;
|
||||
*/
|
||||
public class LexerEngine {
|
||||
|
||||
private final List<Token> tokens = new ArrayList<>(); // 扫描结果
|
||||
private final List<LexicalError> errors = new ArrayList<>();
|
||||
private final String absPath; // 绝对路径
|
||||
private final List<Token> tokens = new ArrayList<>(); // 扫描结果
|
||||
private final List<LexicalError> errors = new ArrayList<>();
|
||||
private final String absPath; // 绝对路径
|
||||
private final LexerContext context; // 字符流
|
||||
private final List<TokenScanner> scanners; // 扫描器链
|
||||
|
||||
/**
|
||||
* 创建并立即执行扫描-校验-报告流程。
|
||||
*
|
||||
* @param source 源代码文本
|
||||
* @param sourceName 文件名(诊断用)
|
||||
*/
|
||||
public LexerEngine(String source, String sourceName) {
|
||||
this.absPath = new File(sourceName).getAbsolutePath();
|
||||
this.context = new LexerContext(source);
|
||||
this.absPath = new File(sourceName).getAbsolutePath();
|
||||
this.context = new LexerContext(source);
|
||||
this.scanners = List.of(
|
||||
new WhitespaceTokenScanner(),
|
||||
new NewlineTokenScanner(),
|
||||
@ -52,31 +56,33 @@ public class LexerEngine {
|
||||
/* 2. 后置整体校验 */
|
||||
validateTokens();
|
||||
/* 3. 打印 token */
|
||||
TokenPrinter.print(tokens);
|
||||
if (SnowConfig.isDebug()) {
|
||||
TokenPrinter.print(tokens);
|
||||
}
|
||||
|
||||
/* 4. 统一报告错误 */
|
||||
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) {
|
||||
if (errors == null || errors.isEmpty()) {
|
||||
System.out.println("\n## 词法分析通过,没有发现错误\n");
|
||||
print("\n## 词法分析通过,没有发现错误\n");
|
||||
return;
|
||||
}
|
||||
System.err.println("\n词法分析发现 " + errors.size() + " 个错误:");
|
||||
errors.forEach(e -> System.err.println(" " + e));
|
||||
System.err.println("\n词法分析发现 " + errors.size() + " 个错误: ");
|
||||
errors.forEach(e -> System.err.println("\t" + e));
|
||||
}
|
||||
|
||||
public List<Token> getAllTokens() { return List.copyOf(tokens); }
|
||||
public List<LexicalError> getErrors() { return List.copyOf(errors); }
|
||||
public List<Token> getAllTokens() {
|
||||
return List.copyOf(tokens);
|
||||
}
|
||||
|
||||
public List<LexicalError> getErrors() {
|
||||
return List.copyOf(errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* 逐字符扫描:依次尝试各扫描器;扫描器抛出的
|
||||
* 逐字符扫描: 依次尝试各扫描器;扫描器抛出的
|
||||
* {@link LexicalException} 被捕获并转为 {@link LexicalError}。
|
||||
*/
|
||||
private void scanAllTokens() {
|
||||
@ -93,7 +99,7 @@ public class LexerEngine {
|
||||
errors.add(new LexicalError(
|
||||
absPath, le.getLine(), le.getColumn(), le.getReason()
|
||||
));
|
||||
context.advance(); // 跳过问题字符
|
||||
skipInvalidLexeme();
|
||||
}
|
||||
handled = true;
|
||||
break;
|
||||
@ -105,10 +111,24 @@ public class LexerEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 目前包含三条规则:<br>
|
||||
* 1. Dot-Prefix'.' 不能作标识符前缀<br>
|
||||
* 2. Declare-Ident declare 后必须紧跟合法标识符,并且只能一个<br>
|
||||
* 3. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余<br>
|
||||
* 跳过当前位置起连续的“标识符 / 数字 / 下划线 / 点”字符。
|
||||
* <p>这样可以把诸如 {@code 1abc} 的残余 {@code abc}、{@code _}、
|
||||
* {@code .999} 等一次性忽略,避免后续被误识别为新的 token。</p>
|
||||
*/
|
||||
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>
|
||||
*/
|
||||
private void validateTokens() {
|
||||
@ -138,7 +158,9 @@ public class LexerEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/** index 右侧最近非 NEWLINE token;无则 null */
|
||||
/**
|
||||
* index 右侧最近非 NEWLINE token;无则 null
|
||||
*/
|
||||
private Token findNextNonNewline(int index) {
|
||||
for (int j = index + 1; j < tokens.size(); j++) {
|
||||
Token t = tokens.get(j);
|
||||
@ -147,8 +169,10 @@ public class LexerEngine {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 构造统一的 LexicalError */
|
||||
/**
|
||||
* 构造统一的 LexicalError
|
||||
*/
|
||||
private LexicalError err(Token t, String msg) {
|
||||
return new LexicalError(absPath, t.getLine(), t.getCol(), "非法的标记序列:" + msg);
|
||||
return new LexicalError(absPath, t.getLine(), t.getCol(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,41 @@
|
||||
package org.jcnc.snow.compiler.lexer.core;
|
||||
|
||||
/**
|
||||
* 表示词法分析过程中发生的错误信息。
|
||||
* <p>
|
||||
* 该类用于封装词法分析(lexical analysis)阶段发现的错误,包括错误位置(文件名、行号、列号)
|
||||
* 以及错误描述信息,便于定位和调试。
|
||||
* </p>
|
||||
*/
|
||||
public class LexicalError {
|
||||
/**
|
||||
* 出错所在的源文件名。
|
||||
*/
|
||||
private final String file;
|
||||
|
||||
/**
|
||||
* 出错所在的行号(从1开始)。
|
||||
*/
|
||||
private final int line;
|
||||
|
||||
/**
|
||||
* 出错所在的列号(从1开始)。
|
||||
*/
|
||||
private final int column;
|
||||
|
||||
/**
|
||||
* 错误的详细描述信息。
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* 构造一个新的 {@code LexicalError} 实例。
|
||||
*
|
||||
* @param file 出错的源文件名
|
||||
* @param line 出错所在的行号(从1开始)
|
||||
* @param column 出错所在的列号(从1开始)
|
||||
* @param message 错误的详细描述信息
|
||||
*/
|
||||
public LexicalError(String file, int line, int column, String message) {
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
@ -13,6 +43,11 @@ public class LexicalError {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以易于阅读的字符串形式返回错误信息。
|
||||
*
|
||||
* @return 格式化的错误信息字符串,包含文件名、行号、列号和错误描述
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return file + ": 行 " + line + ", 列 " + column + ": " + message;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user