!23 release: 合并 v0.4.0 版本至 main 分支
Merge pull request !23 from Luke/release/v0.4.0
@ -69,7 +69,7 @@ body:
|
||||
attributes:
|
||||
label: 软件版本/分支
|
||||
options:
|
||||
- v0.3.0
|
||||
- v0.4.0
|
||||
- main
|
||||
- dev
|
||||
- 其他
|
||||
|
||||
@ -20,7 +20,7 @@ https://gitee.com/jcnc-org/snow/blob/main/doc/Git-Management/Git-Management.md
|
||||
感谢你的配合!🙏
|
||||
-->
|
||||
|
||||
# 描述 (Description)
|
||||
## 描述 (Description)
|
||||
|
||||
请简要描述本次变更的目的和内容。
|
||||
|
||||
|
||||
3
.gitignore
vendored
@ -37,3 +37,6 @@ target/
|
||||
/.idea/
|
||||
/Snow.tar
|
||||
/src/main/java/org/jcnc/snow/compiler/ir.tar
|
||||
|
||||
### Snow 虚拟机指令 ###
|
||||
*.water
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo1" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo1" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo1 -o target/Demo1" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
17
.run/Demo10.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo10" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<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/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>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo2" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo2" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo2 -o target/Demo2" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo3" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo3" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo3 -o target/Demo3" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo4" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo4" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo4 -o target/Demo4" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo5" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo5" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo5 -o target/Demo5" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo6" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo6" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo6 -o target/Demo6" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo7" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo7" />
|
||||
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo7 -o target/Demo7" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
|
||||
17
.run/Demo8.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo8" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<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/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>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Demo9.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo9" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<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/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>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
16
.run/Help.run.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Help" type="Application" factoryName="Application">
|
||||
<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>
|
||||
</configuration>
|
||||
</component>
|
||||
16
.run/Version.run.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Version" type="Application" factoryName="Application">
|
||||
<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>
|
||||
</configuration>
|
||||
</component>
|
||||
299
README.md
@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img src="doc/README/IMG/IMG_Snow_icon_128.svg" alt="Snow Icon">
|
||||
<img src="docs/README/IMG/icon/IMG_Snow_icon_128.svg" alt="Snow Icon">
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Snow编程语言</h1>
|
||||
|
||||
<p align="center">
|
||||
@ -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.3.0/">
|
||||
<img src="https://img.shields.io/badge/version-v0.3.0-blue" alt="">
|
||||
<a href="https://gitee.com/jcnc-org/snow/tree/v0.4.0/">
|
||||
<img src="https://img.shields.io/badge/version-v0.4.0-blue" alt="">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -30,37 +30,55 @@
|
||||
|
||||
## 项目简介
|
||||
|
||||
Snow 语言是一个正在发展的编程语言,采用类模块(module)语法风格,支持函数定义和类型注解。它设计目标是让大型语言模型(LLM)更容易生成和理解编程代码。该项目实现了 Snow 语言的完整编译流程,包括词法分析,语法分析,语义分析,中间表示(IR)生成以及最终的虚拟机(VM)指令生成和执行器。通过 Snow 编译器,可以将 `.snow` 源文件编译为中间表示和自定义的虚拟机指令,并在内置的虚拟机上直接运行。
|
||||
Snow 是一门受 LLM 时代启发的、面向 AI 友好的编程语言。它设计目标是让 LLM 更容易生成和理解编程代码。
|
||||
|
||||
该项目实现了 Snow
|
||||
语言的完整编译流程,包括词法分析,语法分析,语义分析,中间表示(IR)生成以及最终的虚拟机(VM)指令生成和执行器,提供从源码到字节码再到自研编程语言虚拟机 (
|
||||
SnowVM) 的完整编译-执行链路。
|
||||
|
||||
通过 Snow 编译器,可以将 `.snow` 源文件编译为 `.water`虚拟机指令,并在 SnowVM 上直接运行。
|
||||
|
||||
从源码编译、构建管理、依赖管理、项目标准化、可视化调试面板到原生镜像发布,全部由 Snow 官方工具完成,降低学习与集成成本。
|
||||
|
||||
## 背景理念
|
||||
|
||||
Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的语法和严格的类型系统,以帮助人工智能模型更好地理解程序结构。语言使用显式的 `module` 声明来组织代码,用 `function`,`parameter`,`return_type`,`body` 等关键字分隔不同代码块,语法结构固定且易读。此外,Snow 实现了语义分析来检查变量作用域和类型一致性,在编译阶段捕获错误并确保生成的中间代码正确无误。这种自上而下的编译流程,使得代码设计和生成更加模块化,可解释,也有利于调试和优化。
|
||||
Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的语法和严格的类型系统,以帮助 LLM 更好地理解程序。
|
||||
|
||||
相关背景: [心路历程](doc/Snow's-Journey/Snow's-Journey.md)
|
||||
语言使用显式的 `module` 声明来组织代码,用 `function`,`parameter`,`return_type`,`body` 等关键字分隔不同代码块,语法结构固定且易读。此外,Snow
|
||||
实现了语义分析来检查变量作用域和类型一致性,在编译阶段捕获错误并确保生成的中间代码正确无误。这种自上而下的编译流程,使得代码设计和生成更加模块化,可解释,也有利于调试和优化。
|
||||
|
||||
## 下载Snow发行版
|
||||
|
||||
访问: https://gitee.com/jcnc-org/snow/releases
|
||||
|
||||
## 相关文档
|
||||
|
||||
[Git 管理规范](doc/Git-Management/Git-Management.md)
|
||||
相关背景: [心路历程](docs/Snow-Lang-Journey/Snow-Lang-Journey.md)
|
||||
|
||||
## 功能特性
|
||||
|
||||
* **模块化语法**:支持顶层的 `module:` 声明和 `import:` 导入语句,用于组织代码和依赖管理。
|
||||
* **函数与类型**:支持函数定义,函数参数和返回值。在函数体中可以声明变量并进行类型检查。
|
||||
* **丰富语句**:支持变量声明(`declare name:Type`,可选初始化),条件语句(`if ... end if`),循环语句(`loop ... end loop`),返回语句等。
|
||||
* **表达式解析**:实现了 Pratt 算法的表达式解析器,支持算术,比较和逻辑运算,以及函数调用,成员访问等操作。
|
||||
* **完整编译器前端**:包含词法分析器(Lexer),语法分析器(Parser)和语义分析器,对源代码生成抽象语法树(AST)并检查类型/作用域。
|
||||
* **中间表示(IR)**:将高层 AST 转换为自定义的三地址式 IR(Intermediate Representation),结构清晰便于后端优化。
|
||||
* **后端指令生成**:IR 模块通过线性扫描寄存器分配器映射寄存器,使用指令生成器将 IR 翻译为定制的 VM 指令集。
|
||||
* **虚拟机执行**:自带虚拟机引擎(VirtualMachineEngine),能够加载并执行生成的指令序列,支持调试模式输出虚拟机状态。
|
||||
* **调试与输出**:编译过程会输出源码,AST(JSON 格式),IR 和最终生成的 VM 代码,方便用户查看编译中间结果和调试。
|
||||
| 类别 | 关键特性 |
|
||||
|----------|---------------------------------------------------------------------------------------------------|
|
||||
| 语言层 | `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` |
|
||||
|
||||
## Snow-Lang 官网
|
||||
|
||||
[https://snow-lang.com](https://snow-lang.com)
|
||||
|
||||
## 下载 Snow 发行版
|
||||
|
||||
[https://gitee.com/jcnc-org/snow/releases](https://gitee.com/jcnc-org/snow/releases)
|
||||
|
||||
## 相关文档
|
||||
|
||||
[Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
|
||||
|
||||
[SnowVM OpCode 指令表](docs/SnowVM-OpCode/SnowVM-OpCode.md)
|
||||
|
||||
[Snow-Lang GraalVM AOT 打包指南](docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/Snow-Lang-GraalVM-AOT-Native-Image-Package.md)
|
||||
|
||||
## 开发计划
|
||||
|
||||
[Snow 语言现状和下一阶段开发路线图-2025-06-11](doc/Snow's-current-language-situation-and-the-development-roadmap-for-the-next-stage/Snow's-current-language-situation-and-the-development-roadmap-for-the-next-stage.md)
|
||||
~~[Snow 语言现状和下一阶段开发路线图-2025-06-11-已废弃](docs/Snow-Lang-Roadmap/Snow-Lang-Roadmap-2025-06-11.md)~~
|
||||
|
||||
## 开发环境安装
|
||||
|
||||
@ -76,40 +94,38 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
3. **运行项目**
|
||||
|
||||
使用IDEA配置好的运行配置SnowCompiler
|
||||
使用IDEA配置好的运行配置 `Demo1`
|
||||
|
||||

|
||||

|
||||
|
||||
4. **运行成功**
|
||||
|
||||
``` snow
|
||||
## 源代码 (main.snow)
|
||||
`````snow
|
||||
## 编译器输出
|
||||
### Snow 源代码
|
||||
#### Main.snow
|
||||
module: Main
|
||||
import:Math
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
Math.factorial(6L,1L)
|
||||
Math.add(6,1)
|
||||
return 0
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
|
||||
## 源代码 (test.snow)
|
||||
#### Math.snow
|
||||
module: Math
|
||||
function: factorial
|
||||
function: add
|
||||
parameter:
|
||||
declare n1: long
|
||||
declare n2: long
|
||||
return_type: long
|
||||
declare n1: int
|
||||
declare n2: int
|
||||
return_type: int
|
||||
body:
|
||||
return n1 + n2
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
|
||||
## 编译器输出
|
||||
### AST
|
||||
[
|
||||
{
|
||||
@ -140,16 +156,16 @@ end module
|
||||
"type": "Identifier",
|
||||
"name": "Math"
|
||||
},
|
||||
"member": "factorial"
|
||||
"member": "add"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"type": "NumberLiteral",
|
||||
"value": "6L"
|
||||
"value": "6"
|
||||
},
|
||||
{
|
||||
"type": "NumberLiteral",
|
||||
"value": "1L"
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -174,18 +190,18 @@ end module
|
||||
"functions": [
|
||||
{
|
||||
"type": "Function",
|
||||
"name": "factorial",
|
||||
"name": "add",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "n1",
|
||||
"type": "long"
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
"name": "n2",
|
||||
"type": "long"
|
||||
"type": "int"
|
||||
}
|
||||
],
|
||||
"returnType": "long",
|
||||
"returnType": "int",
|
||||
"body": [
|
||||
{
|
||||
"type": "Return",
|
||||
@ -211,64 +227,144 @@ end module
|
||||
func main() {
|
||||
%0 = CONST 6
|
||||
%1 = CONST 1
|
||||
%2 = CALL Math.factorial, %0, %1
|
||||
%2 = CALL Math.add, %0, %1
|
||||
%3 = CONST 0
|
||||
RET %3
|
||||
}
|
||||
func factorial(%0, %1) {
|
||||
%2 = ADD_L64 %0, %1
|
||||
func add(%0, %1) {
|
||||
%2 = ADD_I32 %0, %1
|
||||
RET %2
|
||||
}
|
||||
|
||||
|
||||
### VM code
|
||||
112 6
|
||||
152 0
|
||||
112 1
|
||||
152 1
|
||||
162 0
|
||||
162 1
|
||||
201 12 2
|
||||
152 2
|
||||
111 0
|
||||
151 3
|
||||
161 3
|
||||
255
|
||||
162 0
|
||||
162 1
|
||||
11
|
||||
152 2
|
||||
162 2
|
||||
202
|
||||
0000: I_PUSH 6
|
||||
0001: I_STORE 0
|
||||
0002: I_PUSH 1
|
||||
0003: I_STORE 1
|
||||
0004: I_LOAD 0
|
||||
0005: I_LOAD 1
|
||||
0006: CALL 12 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
|
||||
Written to D:\Devs\IdeaProjects\Snow\target\Demo1.water
|
||||
|
||||
=== Launching VM ===
|
||||
Calling function at address: 12
|
||||
Return 7
|
||||
Process has ended
|
||||
|
||||
Operand Stack state:[0]
|
||||
|
||||
--- Call Stack State ---
|
||||
|
||||
|
||||
### VM Local Variable Table:
|
||||
0: 6
|
||||
1: 1
|
||||
2: 7
|
||||
3: 0
|
||||
|
||||
```
|
||||
|
||||
`````
|
||||
|
||||
## 编译 Snow 源代码
|
||||
|
||||
1. **运行编译器**:
|
||||
运行 Snow 来编译 `.snow` 源文件 (Windows环境) 并且在Snow虚拟机运行,默认以 DEBUG 模式显示执行过程和状态。例如:
|
||||
### 1. 独立编译 (Standalone Compilation)
|
||||
|
||||
独立编译不依赖 `.cloud` 文件,而是直接使用 `Snow` 编译器进行 `.snow` 文件的编译和执行。
|
||||
|
||||
#### 独立编译步骤:
|
||||
|
||||
1. **运行编译器:**
|
||||
你可以通过以下命令来编译单个或多个 `.snow` 文件,或者递归编译一个目录中的所有 `.snow` 源文件为`.water`虚拟机指令。
|
||||
|
||||
* **单个文件编译:**
|
||||
|
||||
```bash
|
||||
# 单个文件编译
|
||||
Snow.exe [SnowCode].snow
|
||||
# 多个文件编译
|
||||
Snow.exe [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow
|
||||
# 目录递归编译(-d 参数)
|
||||
Snow.exe -d path/to/source_dir
|
||||
Snow complete [SnowCode].snow
|
||||
```
|
||||
|
||||
* **多个文件编译:**
|
||||
|
||||
编译器会输出源代码,AST,IR 和 VM 指令等内容,并自动执行虚拟机引擎,最后打印所有局部变量的值
|
||||
2. **查看 AST/IR/VM 输出**:在编译器输出中,可看到 `### AST`,`### IR` 和 `### VM code` 等分段内容。AST 部分为 JSON 格式,IR 和 VM 部分为逐行指令文本。
|
||||
```bash
|
||||
Snow complete [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow -o [Name]
|
||||
```
|
||||
|
||||
* **目录递归编译:**
|
||||
|
||||
```bash
|
||||
Snow -d path/to/source_dir
|
||||
```
|
||||
|
||||
2. **查看编译输出:**
|
||||
编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出:
|
||||
|
||||
* **AST**(抽象语法树)部分以 JSON 格式输出。
|
||||
* **IR**(中间表示)部分会列出逐行的中间代码。
|
||||
* **VM code**(虚拟机指令)会展示虚拟机的字节码指令。
|
||||
|
||||
3. **默认执行模式:**
|
||||
编译器会在 **DEBUG 模式** 下运行,显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。
|
||||
|
||||
---
|
||||
|
||||
### 2. **集成编译 (Integrated Compilation)**
|
||||
|
||||
集成编译需要使用 `.cloud` 文件来指定项目的配置和结构,适用于项目标准化、依赖管理、构建管理和项目分发等场景。
|
||||
|
||||
#### 集成编译命令:
|
||||
|
||||
1. **基本用法:**
|
||||
|
||||
```bash
|
||||
snow [OPTIONS] <command>
|
||||
```
|
||||
|
||||
2. **命令选项:**
|
||||
|
||||
* `-h, --help`:显示帮助信息并退出。
|
||||
* `-v, --version`:打印 Snow 编程语言的版本并退出。
|
||||
|
||||
3. **可用命令:**
|
||||
|
||||
* `compile`:将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。
|
||||
* `clean`:清理构建输出和本地缓存,移除中间产物,释放磁盘空间。
|
||||
* `version`:打印 Snow 的版本。
|
||||
* `run`:运行已编译的虚拟机字节码文件(`.water`)。
|
||||
* `init`:初始化一个新项目,生成 `project.cloud` 文件。
|
||||
* `generate`:根据 `project.cloud` 生成项目目录结构。
|
||||
* `build`:构建当前项目,按顺序解析依赖、编译和打包。
|
||||
|
||||
4. **例如,执行集成编译命令:**
|
||||
|
||||
```bash
|
||||
snow compile [SnowCode].snow
|
||||
```
|
||||
|
||||
* 此命令会使用 `.cloud` 文件中的配置信息来指导编译过程,并生成 `.water`。
|
||||
|
||||
5. **使用帮助:**
|
||||
如果你需要了解某个命令的详细选项,可以使用:
|
||||
|
||||
```bash
|
||||
snow <command> --help
|
||||
```
|
||||
|
||||
例如,查看 `compile` 命令的具体选项:
|
||||
|
||||
```bash
|
||||
snow compile --help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 示例代码片段
|
||||
|
||||
@ -277,7 +373,6 @@ Process has ended
|
||||
```snow
|
||||
module: Math
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
Math.factorial(6)
|
||||
@ -306,32 +401,52 @@ module: Math
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
|
||||
```
|
||||
|
||||
上述代码定义了一个名为 `Math` 的模块,其中包含两个函数:
|
||||
|
||||
* `main`:不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。
|
||||
* `factorial`:接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个 `loop` 循环(从 `counter = 1` 到 `counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。
|
||||
* `factorial`:接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个
|
||||
`loop` 循环(从 `counter = 1` 到 `counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。
|
||||
|
||||
|
||||
> 更多示例代码见 [playground 目录](https://gitee.com/jcnc-org/snow/tree/main/playground)
|
||||
|
||||
## 项目结构说明
|
||||
|
||||
* `compiler/`:Snow 编译器源代码目录
|
||||
|
||||
* `cli/`:命令行接口,包括 `SnowCompiler` 主程序
|
||||
* `lexer/`:词法分析模块,负责将源码切分为 Token
|
||||
* `parser/`:语法分析模块,将 Token 流解析为 AST;包括模块解析,函数解析,语句解析等子模块
|
||||
* `semantic/`:语义分析模块,负责符号表管理,类型检查等
|
||||
* `ir/`:中间表示(IR)模块,生成和管理三地址码形式的中间代码
|
||||
* `backend/`:编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
|
||||
* `lexer/`:词法分析模块,负责将源码切分为 Token
|
||||
* `parser/`:语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析)
|
||||
* `semantic/`:语义分析模块,负责符号表管理、类型检查等
|
||||
* `ir/`:中间表示(IR)模块,生成并管理三地址码形式的中间代码
|
||||
* `backend/`:编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
|
||||
|
||||
* `vm/`:虚拟机相关源代码目录
|
||||
|
||||
* `commands/`:定义 VM 指令集的具体实现
|
||||
* `engine/`:核心执行引擎,提供指令执行和寄存器栈管理
|
||||
* `execution/`:执行流程控制(按指令顺序执行,分支跳转等)
|
||||
* `io/`:输入输出辅助类(加载指令,文件解析等)
|
||||
* 其他如 `factories/`,`utils/` 等目录包含指令创建和调试工具类
|
||||
* `commands/`:定义 SnowVM 指令集的具体实现
|
||||
* `engine/`:核心执行引擎,提供指令执行和寄存器/栈管理
|
||||
* `execution/`:执行流程控制(按指令顺序执行、分支跳转等)
|
||||
* `io/`:输入输出辅助类(加载指令、文件解析等)
|
||||
* `gui/`:Swing 可视化调试面板,实时展示局部变量表
|
||||
* `factories/`、`utils/`:指令创建、日志调试等公共工具
|
||||
|
||||
* `pkg/`:内置构建与包管理器 **snow pkg**
|
||||
|
||||
* `dsl/`:`.cloud` 描述文件解析器
|
||||
* `tasks/`:预设任务实现(`clean · compile · run · package · publish` 等)
|
||||
* `resolver/`:本地/远程仓库解析与缓存
|
||||
* `lifecycle/`:任务生命周期钩子(pre/post 脚本等)
|
||||
* `model/`:项目、依赖、版本等模型
|
||||
* `utils/`:文件、日志、校验和等通用工具
|
||||
* `doc/`:开发者文档与示例 `.cloud` 配置
|
||||
|
||||
* `cli/`:独立的命令行前端
|
||||
|
||||
* `commands/`:`compile` / `run` / `pkg` 等子命令实现
|
||||
* `api/`:公共选项解析、终端交互抽象
|
||||
* `utils/`:终端颜色、进度条、异常格式化等
|
||||
* `SnowCLI.java`:CLI 主入口
|
||||
|
||||
|
||||
## 版权声明
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB |
BIN
docs/README/IMG/IMG_Run-Profile_1.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 455 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 976 B After Width: | Height: | Size: 976 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,174 @@
|
||||
# Snow-Lang GraalVM AOT 打包指南
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档介绍如何使用 GraalVM 的 AOT(Ahead-of-Time)编译功能将一个 Snow-Lang 项目打包成原生可执行文件(Native Image)。
|
||||
|
||||
## 2. 前置条件
|
||||
|
||||
1. 操作系统:Linux/macOS/Windows
|
||||
2. Java 项目(Maven)
|
||||
3. GraalVM(建议 24+ 版本)
|
||||
|
||||
## 3. 环境准备
|
||||
|
||||
### 3.1 安装 GraalVM
|
||||
|
||||
1. 下载对应平台的 GraalVM Community 版本:[https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/)
|
||||
2. 解压并配置环境变量:
|
||||
|
||||
3. 验证安装:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
# 应显示 GraalVM 版本信息
|
||||
java version "24.0.1" 2025-04-15
|
||||
Java(TM) SE Runtime Environment Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmci-b01)
|
||||
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmci-b01, mixed mode, sharing)
|
||||
```
|
||||
### 3.2 Windows 上 Native Image 的先决条件
|
||||
|
||||
在 Windows 上,Native Image 需要 Visual Studio 和 Microsoft Visual C++(MSVC)。
|
||||
|
||||
1. 从 [visualstudio.microsoft.com](https://visualstudio.microsoft.com/zh-hans/vs/) 下载 Visual Studio Build Tools 2022 或更高版本(C 开发环境)。
|
||||
|
||||
2. 通过打开下载的文件来启动安装,然后单击 **继续**
|
||||
|
||||

|
||||
|
||||
3. 在主窗口中选择 **使用 C++ 进行桌面开发** 复选框。在右侧的“安装详细信息”下,确保选择了两个要求,**Windows 11 SDK** 和 **MSVC (…) C++ x64/x86 构建工具**。单击 **安装** 继续。
|
||||
|
||||

|
||||
|
||||
您现在能够使用 GraalVM Native Image 进行构建。
|
||||
|
||||
## 4. Maven 项目配置文件
|
||||
|
||||
通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件:
|
||||
|
||||
```xml
|
||||
<profiles>
|
||||
<!--
|
||||
原生镜像构建:Linux 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
|
||||
- 依赖 musl libc,需提前安装并配置 musl-gcc 工具链
|
||||
-->
|
||||
<profile>
|
||||
<id>native-linux</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>unix</family>
|
||||
</os>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>${native.maven.plugin.version}</version>
|
||||
<!-- 启用插件扩展,允许在 build 生命周期中无须额外配置 -->
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<!-- 打包阶段生成原生可执行文件 -->
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
<!-- compile-no-fork 在当前 JVM 进程中执行 native-image -->
|
||||
<goal>compile-no-fork</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
<!-- 测试阶段运行原生镜像的测试 -->
|
||||
<execution>
|
||||
<id>test-native</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<phase>test</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<buildArgs>
|
||||
<!-- 静态链接 -->
|
||||
<buildArg>--static</buildArg>
|
||||
<!-- 指定 musl libc -->
|
||||
<buildArg>--libc=musl</buildArg>
|
||||
<!-- 输出构建报告 -->
|
||||
<buildArg>--emit build-report</buildArg>
|
||||
<!-- 优化级别 O2 -->
|
||||
<buildArg>-O2</buildArg>
|
||||
</buildArgs>
|
||||
<environment>
|
||||
<!-- 指定使用 musl 工具链 -->
|
||||
<PATH>/opt/musl-1.2.5/bin:${env.PATH}</PATH>
|
||||
<C_INCLUDE_PATH>/opt/musl-1.2.5/include</C_INCLUDE_PATH>
|
||||
<LIBRARY_PATH>/opt/musl-1.2.5/lib</LIBRARY_PATH>
|
||||
</environment>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!--
|
||||
原生镜像构建:Windows 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
|
||||
- Windows 上不使用 musl,因此不配置静态链接
|
||||
-->
|
||||
<profile>
|
||||
<id>native-windows</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>Windows</family>
|
||||
</os>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>${native.maven.plugin.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<!-- 打包阶段生成 Windows 可执行文件 -->
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
<goal>compile-no-fork</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
<!-- 测试阶段运行原生镜像测试 -->
|
||||
<execution>
|
||||
<id>test-native</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<phase>test</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<buildArgs>
|
||||
<!-- 输出构建报告 -->
|
||||
<buildArg>--emit build-report</buildArg>
|
||||
<!-- 优化级别 O2 -->
|
||||
<buildArg>-O2</buildArg>
|
||||
</buildArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
## 5. 构建 Native Image
|
||||
|
||||
1. 确保项目已在 JVM 下通过测试。
|
||||
2. 点击 `Maven` `生命周期` `package`
|
||||
|
||||

|
||||
|
||||
3. 等待 Native Image 构建完成:这个过程可能较慢(数分钟)。
|
||||
4. 可执行文件即可直接运行,无需 JVM。
|
||||
> 生成的可执行文件位于 target/ 目录。
|
||||
|
After Width: | Height: | Size: 10 KiB |
BIN
docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/img/IMG_VS_1.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/Snow-Lang-GraalVM-AOT-Native-Image-Package/img/IMG_VS_2.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
226
docs/SnowVM-OpCode/SnowVM-OpCode.md
Normal file
@ -0,0 +1,226 @@
|
||||
# SnowVM-OpCode
|
||||
|
||||
## 1. Byte8 区域(0x0000-0x001F)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|----------------|
|
||||
| B\_ADD | 0x0000 | byte8 加法 |
|
||||
| B\_SUB | 0x0001 | byte8 减法 |
|
||||
| B\_MUL | 0x0002 | byte8 乘法 |
|
||||
| B\_DIV | 0x0003 | byte8 除法 |
|
||||
| B\_MOD | 0x0004 | byte8 取余 |
|
||||
| B\_NEG | 0x0005 | byte8 取负 |
|
||||
| B\_INC | 0x0006 | byte8 自增 |
|
||||
| B\_AND | 0x0007 | byte8 按位与 |
|
||||
| B\_OR | 0x0008 | byte8 按位或 |
|
||||
| B\_XOR | 0x0009 | byte8 按位异或 |
|
||||
| B\_PUSH | 0x000A | byte8 入栈 |
|
||||
| B\_LOAD | 0x000B | byte8 本地变量加载 |
|
||||
| B\_STORE | 0x000C | byte8 本地变量存储 |
|
||||
| B\_CE | 0x000D | byte8 等于条件判断 |
|
||||
| B\_CNE | 0x000E | byte8 不等于条件判断 |
|
||||
| B\_CG | 0x000F | byte8 大于条件判断 |
|
||||
| B\_CGE | 0x0010 | byte8 大于等于条件判断 |
|
||||
| B\_CL | 0x0011 | byte8 小于条件判断 |
|
||||
| B\_CLE | 0x0012 | byte8 小于等于条件判断 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Short16 区域(0x0020-0x003F)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|------------------|
|
||||
| S\_ADD | 0x0020 | short16 加法 |
|
||||
| S\_SUB | 0x0021 | short16 减法 |
|
||||
| S\_MUL | 0x0022 | short16 乘法 |
|
||||
| S\_DIV | 0x0023 | short16 除法 |
|
||||
| S\_MOD | 0x0024 | short16 取余 |
|
||||
| S\_NEG | 0x0025 | short16 取负 |
|
||||
| S\_INC | 0x0026 | short16 自增 |
|
||||
| S\_AND | 0x0027 | short16 按位与 |
|
||||
| S\_OR | 0x0028 | short16 按位或 |
|
||||
| S\_XOR | 0x0029 | short16 按位异或 |
|
||||
| S\_PUSH | 0x002A | short16 入栈 |
|
||||
| S\_LOAD | 0x002B | short16 本地变量加载 |
|
||||
| S\_STORE | 0x002C | short16 本地变量存储 |
|
||||
| S\_CE | 0x002D | short16 等于条件判断 |
|
||||
| S\_CNE | 0x002E | short16 不等于条件判断 |
|
||||
| S\_CG | 0x002F | short16 大于条件判断 |
|
||||
| S\_CGE | 0x0030 | short16 大于等于条件判断 |
|
||||
| S\_CL | 0x0031 | short16 小于条件判断 |
|
||||
| S\_CLE | 0x0032 | short16 小于等于条件判断 |
|
||||
|
||||
---
|
||||
|
||||
## 3. Int32 区域(0x0040-0x005F)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|----------------|
|
||||
| I\_ADD | 0x0040 | int32 加法 |
|
||||
| I\_SUB | 0x0041 | int32 减法 |
|
||||
| I\_MUL | 0x0042 | int32 乘法 |
|
||||
| I\_DIV | 0x0043 | int32 除法 |
|
||||
| I\_MOD | 0x0044 | int32 取余 |
|
||||
| I\_NEG | 0x0045 | int32 取负 |
|
||||
| I\_INC | 0x0046 | int32 自增 |
|
||||
| I\_AND | 0x0047 | int32 按位与 |
|
||||
| I\_OR | 0x0048 | int32 按位或 |
|
||||
| I\_XOR | 0x0049 | int32 按位异或 |
|
||||
| I\_PUSH | 0x004A | int32 入栈 |
|
||||
| I\_LOAD | 0x004B | int32 本地变量加载 |
|
||||
| I\_STORE | 0x004C | int32 本地变量存储 |
|
||||
| I\_CE | 0x004D | int32 等于条件判断 |
|
||||
| I\_CNE | 0x004E | int32 不等于条件判断 |
|
||||
| I\_CG | 0x004F | int32 大于条件判断 |
|
||||
| I\_CGE | 0x0050 | int32 大于等于条件判断 |
|
||||
| I\_CL | 0x0051 | int32 小于条件判断 |
|
||||
| I\_CLE | 0x0052 | int32 小于等于条件判断 |
|
||||
|
||||
---
|
||||
|
||||
## 4. Long64 区域(0x0060-0x007F)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|-----------------|
|
||||
| L\_ADD | 0x0060 | long64 加法 |
|
||||
| L\_SUB | 0x0061 | long64 减法 |
|
||||
| L\_MUL | 0x0062 | long64 乘法 |
|
||||
| L\_DIV | 0x0063 | long64 除法 |
|
||||
| L\_MOD | 0x0064 | long64 取余 |
|
||||
| L\_NEG | 0x0065 | long64 取负 |
|
||||
| L\_INC | 0x0066 | long64 自增 |
|
||||
| L\_AND | 0x0067 | long64 按位与 |
|
||||
| L\_OR | 0x0068 | long64 按位或 |
|
||||
| L\_XOR | 0x0069 | long64 按位异或 |
|
||||
| L\_PUSH | 0x006A | long64 入栈 |
|
||||
| L\_LOAD | 0x006B | long64 本地变量加载 |
|
||||
| L\_STORE | 0x006C | long64 本地变量存储 |
|
||||
| L\_CE | 0x006D | long64 等于条件判断 |
|
||||
| L\_CNE | 0x006E | long64 不等于条件判断 |
|
||||
| L\_CG | 0x006F | long64 大于条件判断 |
|
||||
| L\_CGE | 0x0070 | long64 大于等于条件判断 |
|
||||
| L\_CL | 0x0071 | long64 小于条件判断 |
|
||||
| L\_CLE | 0x0072 | long64 小于等于条件判断 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Float32 区域(0x0080-0x009F)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|------------------|
|
||||
| F\_ADD | 0x0080 | float32 加法 |
|
||||
| F\_SUB | 0x0081 | float32 减法 |
|
||||
| F\_MUL | 0x0082 | float32 乘法 |
|
||||
| F\_DIV | 0x0083 | float32 除法 |
|
||||
| F\_MOD | 0x0084 | float32 取余 |
|
||||
| F\_NEG | 0x0085 | float32 取负 |
|
||||
| F\_INC | 0x0086 | float32 自增 |
|
||||
| F\_PUSH | 0x0087 | float32 入栈 |
|
||||
| F\_LOAD | 0x0088 | float32 本地变量加载 |
|
||||
| F\_STORE | 0x0089 | float32 本地变量存储 |
|
||||
| F\_CE | 0x008A | float32 等于条件判断 |
|
||||
| F\_CNE | 0x008B | float32 不等于条件判断 |
|
||||
| F\_CG | 0x008C | float32 大于条件判断 |
|
||||
| F\_CGE | 0x008D | float32 大于等于条件判断 |
|
||||
| F\_CL | 0x008E | float32 小于条件判断 |
|
||||
| F\_CLE | 0x008F | float32 小于等于条件判断 |
|
||||
|
||||
---
|
||||
|
||||
## 6. Double64 区域(0x00A0-0x00BF)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|----------|--------|-------------------|
|
||||
| D\_ADD | 0x00A0 | double64 加法 |
|
||||
| D\_SUB | 0x00A1 | double64 减法 |
|
||||
| D\_MUL | 0x00A2 | double64 乘法 |
|
||||
| D\_DIV | 0x00A3 | double64 除法 |
|
||||
| D\_MOD | 0x00A4 | double64 取余 |
|
||||
| D\_NEG | 0x00A5 | double64 取负 |
|
||||
| D\_INC | 0x00A6 | double64 自增 |
|
||||
| D\_PUSH | 0x00A7 | double64 入栈 |
|
||||
| D\_LOAD | 0x00A8 | double64 本地变量加载 |
|
||||
| D\_STORE | 0x00A9 | double64 本地变量存储 |
|
||||
| D\_CE | 0x00AA | double64 等于条件判断 |
|
||||
| D\_CNE | 0x00AB | double64 不等于条件判断 |
|
||||
| D\_CG | 0x00AC | double64 大于条件判断 |
|
||||
| D\_CGE | 0x00AD | double64 大于等于条件判断 |
|
||||
| D\_CL | 0x00AE | double64 小于条件判断 |
|
||||
| D\_CLE | 0x00AF | double64 小于等于条件判断 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 类型转换(0x00C0-0x00DF)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|-----|--------|--------------------|
|
||||
| B2S | 0x00C0 | byte8 转 short16 |
|
||||
| B2I | 0x00C1 | byte8 转 int32 |
|
||||
| B2L | 0x00C2 | byte8 转 long64 |
|
||||
| B2F | 0x00C3 | byte8 转 float32 |
|
||||
| B2D | 0x00C4 | byte8 转 double64 |
|
||||
| S2B | 0x00C5 | short16 转 byte8 |
|
||||
| S2I | 0x00C6 | short16 转 int32 |
|
||||
| S2L | 0x00C7 | short16 转 long64 |
|
||||
| S2F | 0x00C8 | short16 转 float32 |
|
||||
| S2D | 0x00C9 | short16 转 double64 |
|
||||
| I2B | 0x00CA | int32 转 byte8 |
|
||||
| I2S | 0x00CB | int32 转 short16 |
|
||||
| I2L | 0x00CC | int32 转 long64 |
|
||||
| I2F | 0x00CD | int32 转 float32 |
|
||||
| I2D | 0x00CE | int32 转 double64 |
|
||||
| L2B | 0x00CF | long64 转 byte8 |
|
||||
| L2S | 0x00D0 | long64 转 short16 |
|
||||
| L2I | 0x00D1 | long64 转 int32 |
|
||||
| L2F | 0x00D2 | long64 转 float32 |
|
||||
| L2D | 0x00D3 | long64 转 double64 |
|
||||
| F2B | 0x00D4 | float32 转 byte8 |
|
||||
| F2S | 0x00D5 | float32 转 short16 |
|
||||
| F2I | 0x00D6 | float32 转 int32 |
|
||||
| F2L | 0x00D7 | float32 转 long64 |
|
||||
| F2D | 0x00D8 | float32 转 double64 |
|
||||
| D2B | 0x00D9 | double64 转 byte8 |
|
||||
| D2S | 0x00DA | double64 转 short16 |
|
||||
| D2I | 0x00DB | double64 转 int32 |
|
||||
| D2L | 0x00DC | double64 转 long64 |
|
||||
| D2F | 0x00DD | double64 转 float32 |
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 8. 栈控制(0x0100-0x01FF)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|------|--------|----------|
|
||||
| POP | 0x0100 | 弹出栈顶元素 |
|
||||
| DUP | 0x0101 | 复制栈顶元素 |
|
||||
| SWAP | 0x0102 | 交换栈顶前两元素 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 流程控制(0x0200-0x02FF)
|
||||
|
||||
| 指令名 | 十六进制/十进制 | 说明 |
|
||||
|------|----------|-------|
|
||||
| JUMP | 0x0200 | 无条件跳转 |
|
||||
| CALL | 0x0201 | 子程序调用 |
|
||||
| RET | 0x0202 | 子程序返回 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 寄存器控制(0x0300-0x03FF)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|-----|--------|---------|
|
||||
| MOV | 0x0300 | 局部变量间赋值 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 系统控制(0x0400-0x04FF)
|
||||
|
||||
| 指令名 | 十六进制 | 说明 |
|
||||
|-------------|--------|------|
|
||||
| HALT | 0x0400 | 程序终止 |
|
||||
| SYSCALL | 0x0401 | 系统调用 |
|
||||
| DEBUG\_TRAP | 0x0402 | 调试断点 |
|
||||
@ -1,10 +1,9 @@
|
||||
module: Main
|
||||
import:Math
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
Math.factorial(6L,1L)
|
||||
Math.add(6,1)
|
||||
return 0
|
||||
end body
|
||||
end function
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
module: Math
|
||||
function: factorial
|
||||
function: add
|
||||
parameter:
|
||||
declare n1: long
|
||||
declare n2: long
|
||||
return_type: long
|
||||
declare n1: int
|
||||
declare n2: int
|
||||
return_type: int
|
||||
body:
|
||||
return n1 + n2
|
||||
end body
|
||||
|
||||
10
playground/Demo10/Main.snow
Normal file
@ -0,0 +1,10 @@
|
||||
function: main
|
||||
return_type: int
|
||||
body:
|
||||
declare res: boolean = 8L > 7L
|
||||
if res then
|
||||
return 131
|
||||
end if
|
||||
return 65537
|
||||
end body
|
||||
end function
|
||||
12
playground/Demo8/Main.snow
Normal file
@ -0,0 +1,12 @@
|
||||
module: Main
|
||||
function: main
|
||||
parameter:
|
||||
return_type: long
|
||||
body:
|
||||
declare n: long
|
||||
n = 2147483647
|
||||
n = n + 1
|
||||
return n
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
31
playground/Demo9/Main.snow
Normal file
@ -0,0 +1,31 @@
|
||||
module: Math
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
Math.factorial(6)
|
||||
return 0
|
||||
end body
|
||||
end function
|
||||
|
||||
function: factorial
|
||||
parameter:
|
||||
declare n:int
|
||||
return_type: int
|
||||
body:
|
||||
declare num1:int = 1
|
||||
loop:
|
||||
initializer:
|
||||
declare counter:int = 1
|
||||
condition:
|
||||
counter <= n
|
||||
update:
|
||||
counter = counter + 1
|
||||
body:
|
||||
num1 = num1 * counter
|
||||
end body
|
||||
end loop
|
||||
return num1
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
62
pom.xml
@ -7,9 +7,11 @@
|
||||
|
||||
<groupId>org.jcnc.snow</groupId>
|
||||
<artifactId>Snow</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>0.4.0</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven.compiler.source>24</maven.compiler.source>
|
||||
<maven.compiler.target>24</maven.compiler.target>
|
||||
<native.maven.plugin.version>0.10.5</native.maven.plugin.version>
|
||||
@ -17,17 +19,36 @@
|
||||
|
||||
<!-- 通用编译 & 打包插件 -->
|
||||
<build>
|
||||
<!-- 资源文件目录及占位符替换(resource filtering) -->
|
||||
<resources>
|
||||
<resource>
|
||||
<!-- 指定资源文件所在目录 -->
|
||||
<directory>src/main/resources</directory>
|
||||
<!-- 开启资源文件中的占位符(如 ${project.version})替换 -->
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<!-- Java 编译插件 -->
|
||||
<!--
|
||||
Java 编译插件:
|
||||
- 使用 Maven 自带的 maven-compiler-plugin 进行源码编译
|
||||
- <fork>true</fork> 表示在单独的进程中执行 javac,提高兼容性
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.14.0</version>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
<release>24</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Jar 打包插件 -->
|
||||
|
||||
<!--
|
||||
Jar 打包插件:
|
||||
- 使用 maven-jar-plugin 将编译产物打包成可执行 JAR
|
||||
- 在 MANIFEST 中指定主类,支持命令行直接 java -jar 调用
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
@ -35,8 +56,12 @@
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.jcnc.snow.compiler.cli.SnowCompiler</mainClass>
|
||||
<!-- 指定程序入口类,运行 java -jar 时会执行此类的 main 方法 -->
|
||||
<mainClass>org.jcnc.snow.cli.SnowCLI</mainClass>
|
||||
<!-- 将项目类路径添加到 MANIFEST Class-Path 中 -->
|
||||
<addClasspath>true</addClasspath>
|
||||
<!-- 在 MANIFEST 中添加实现版本、实现供应商等默认条目 -->
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
@ -45,6 +70,11 @@
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!--
|
||||
原生镜像构建:Linux 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
|
||||
- 依赖 musl libc,需提前安装并配置 musl-gcc 工具链
|
||||
-->
|
||||
<profile>
|
||||
<id>native-linux</id>
|
||||
<activation>
|
||||
@ -58,15 +88,19 @@
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<version>${native.maven.plugin.version}</version>
|
||||
<!-- 启用插件扩展,允许在 build 生命周期中无须额外配置 -->
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<!-- 打包阶段生成原生可执行文件 -->
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
<!-- compile-no-fork 在当前 JVM 进程中执行 native-image -->
|
||||
<goal>compile-no-fork</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
<!-- 测试阶段运行原生镜像的测试 -->
|
||||
<execution>
|
||||
<id>test-native</id>
|
||||
<goals>
|
||||
@ -77,13 +111,17 @@
|
||||
</executions>
|
||||
<configuration>
|
||||
<buildArgs>
|
||||
<!-- 静态链接 -->
|
||||
<buildArg>--static</buildArg>
|
||||
<!-- 指定 musl libc -->
|
||||
<buildArg>--libc=musl</buildArg>
|
||||
<!-- 输出构建报告 -->
|
||||
<buildArg>--emit build-report</buildArg>
|
||||
<!-- 优化级别 O2 -->
|
||||
<buildArg>-O2</buildArg>
|
||||
</buildArgs>
|
||||
<environment>
|
||||
<!-- 指定 musl-gcc 工具链 -->
|
||||
<!-- 指定使用 musl 工具链 -->
|
||||
<PATH>/opt/musl-1.2.5/bin:${env.PATH}</PATH>
|
||||
<C_INCLUDE_PATH>/opt/musl-1.2.5/include</C_INCLUDE_PATH>
|
||||
<LIBRARY_PATH>/opt/musl-1.2.5/lib</LIBRARY_PATH>
|
||||
@ -94,6 +132,11 @@
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!--
|
||||
原生镜像构建:Windows 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
|
||||
- Windows 上不使用 musl,因此不配置静态链接
|
||||
-->
|
||||
<profile>
|
||||
<id>native-windows</id>
|
||||
<activation>
|
||||
@ -109,6 +152,7 @@
|
||||
<version>${native.maven.plugin.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<!-- 打包阶段生成 Windows 可执行文件 -->
|
||||
<execution>
|
||||
<id>build-native</id>
|
||||
<goals>
|
||||
@ -116,6 +160,7 @@
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
<!-- 测试阶段运行原生镜像测试 -->
|
||||
<execution>
|
||||
<id>test-native</id>
|
||||
<goals>
|
||||
@ -126,7 +171,9 @@
|
||||
</executions>
|
||||
<configuration>
|
||||
<buildArgs>
|
||||
<!-- 输出构建报告 -->
|
||||
<buildArg>--emit build-report</buildArg>
|
||||
<!-- 优化级别 O2 -->
|
||||
<buildArg>-O2</buildArg>
|
||||
</buildArgs>
|
||||
</configuration>
|
||||
@ -135,4 +182,5 @@
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
|
||||
module org.jcnc.snow.compiler {
|
||||
uses CLICommand;
|
||||
requires java.desktop;
|
||||
requires java.logging;
|
||||
exports org.jcnc.snow.compiler.ir.core;
|
||||
|
||||
98
src/main/java/org/jcnc/snow/cli/SnowCLI.java
Normal file
@ -0,0 +1,98 @@
|
||||
package org.jcnc.snow.cli;
|
||||
|
||||
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 java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Snow 编程语言的命令行接口入口类。
|
||||
* <p>
|
||||
* 该类解析用户输入的命令行参数,调度相应的子命令(compile、run、version),
|
||||
* 并处理全局帮助和版本信息输出。
|
||||
* </p>
|
||||
*/
|
||||
public class SnowCLI {
|
||||
|
||||
/**
|
||||
* Snow 编程语言的当前版本号,从资源文件中加载。
|
||||
*/
|
||||
public static final String SNOW_VERSION = VersionUtils.loadVersion();
|
||||
|
||||
/**
|
||||
* 可用子命令名称与对应命令处理器的映射表。
|
||||
* 键为子命令名称("compile", "run", "version"),
|
||||
* 值为返回相应 {@link CLICommand} 实例的 Supplier。
|
||||
*/
|
||||
private static final Map<String, Supplier<CLICommand>> COMMANDS = Map.of(
|
||||
"generate", GenerateCommand::new,
|
||||
"compile", CompileCommand::new,
|
||||
"run", RunCommand::new,
|
||||
"version", VersionCommand::new,
|
||||
"init", InitCommand::new,
|
||||
"build", BuildCommand::new,
|
||||
"install", InstallCommand::new,
|
||||
"publish", PublishCommand::new,
|
||||
"clean", CleanCommand::new
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
* 程序入口方法,解析并调度子命令。
|
||||
* <p>
|
||||
*
|
||||
* @param args 命令行参数数组
|
||||
* 无参数或首参数为帮助标志时,打印全局用法说明并退出
|
||||
* 首参数为版本标志时,打印版本信息并退出
|
||||
* 首参数为子命令名时,进一步解析该子命令的参数并执行
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// 处理全局帮助
|
||||
if (args.length == 0 || CLIUtils.GLOBAL_HELP_FLAGS.contains(args[0])) {
|
||||
CLIUtils.printGeneralUsage(COMMANDS);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// 处理全局版本请求
|
||||
if (CLIUtils.GLOBAL_VERSION_FLAGS.contains(args[0])) {
|
||||
new VersionCommand().execute(new String[0]);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// 子命令名称
|
||||
String cmdName = args[0];
|
||||
Supplier<CLICommand> cmdSupplier = COMMANDS.get(cmdName);
|
||||
|
||||
// 未知子命令处理
|
||||
if (cmdSupplier == null) {
|
||||
System.err.println("Unknown command: " + cmdName);
|
||||
CLIUtils.printGeneralUsage(COMMANDS);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// 创建对应子命令实例
|
||||
CLICommand cmd = cmdSupplier.get();
|
||||
// 提取子命令参数
|
||||
String[] subArgs = Arrays.copyOfRange(args, 1, args.length);
|
||||
|
||||
// 如果子命令请求帮助,则打印该命令的用法说明并退出
|
||||
if (subArgs.length > 0 && CLIUtils.GLOBAL_HELP_FLAGS.contains(subArgs[0])) {
|
||||
cmd.printUsage();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// 执行子命令并根据返回的退出码退出
|
||||
try {
|
||||
int exitCode = cmd.execute(subArgs);
|
||||
System.exit(exitCode);
|
||||
} catch (Exception e) {
|
||||
// 捕获命令执行过程中的异常并打印错误消息
|
||||
System.err.println("Error: " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/main/java/org/jcnc/snow/cli/api/CLICommand.java
Normal file
@ -0,0 +1,47 @@
|
||||
package org.jcnc.snow.cli.api;
|
||||
|
||||
import org.jcnc.snow.cli.SnowCLI;
|
||||
|
||||
/**
|
||||
* 所有 CLI 子命令(如 compile、run 等)都必须实现的命令接口。
|
||||
* <p>
|
||||
* 实现类应为无状态(stateless)、线程安全(thread-safe)。
|
||||
* 可通过 {@link java.util.ServiceLoader ServiceLoader} 自动发现,
|
||||
* 或直接在 {@link SnowCLI} 中注册。
|
||||
* </p>
|
||||
*/
|
||||
public interface CLICommand {
|
||||
|
||||
/**
|
||||
* 获取命令的名称(如 "compile"、"run")。
|
||||
*
|
||||
* @return 命令名字符串
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* 获取命令的一行简介(用于 help 列表)。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
String description();
|
||||
|
||||
/**
|
||||
* 打印命令的专用 usage 信息(可选实现)。
|
||||
* <p>
|
||||
* 可覆盖此方法自定义帮助信息,默认无操作。
|
||||
* </p>
|
||||
*/
|
||||
default void printUsage() {
|
||||
// 默认实现为空,可由子类覆盖
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令逻辑。
|
||||
*
|
||||
* @param args 传递给子命令的参数(不含命令名本身)
|
||||
* @return 进程退出码(0 为成功,非 0 为错误)
|
||||
* @throws Exception 可抛出任意异常,框架会统一捕获和输出
|
||||
*/
|
||||
int execute(String[] args) throws Exception;
|
||||
}
|
||||
86
src/main/java/org/jcnc/snow/cli/commands/BuildCommand.java
Normal file
@ -0,0 +1,86 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.dsl.CloudDSLParser;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecycleManager;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
|
||||
import org.jcnc.snow.pkg.model.Project;
|
||||
import org.jcnc.snow.pkg.resolver.DependencyResolver;
|
||||
import org.jcnc.snow.pkg.tasks.CompileTask;
|
||||
import org.jcnc.snow.pkg.tasks.PackageTask;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:构建当前项目(包含依赖解析、编译、打包)。
|
||||
* <p>
|
||||
* 该命令会依次执行依赖解析、源码编译和产物打包阶段。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow build
|
||||
* </pre>
|
||||
*/
|
||||
public final class BuildCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名称,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称,如 "build"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "build";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Build the current project by resolving dependencies, compiling, and packaging in sequence.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage: snow build ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行项目构建流程。
|
||||
* <ul>
|
||||
* <li>解析项目描述文件(project.cloud)</li>
|
||||
* <li>依赖解析(RESOLVE_DEPENDENCIES)</li>
|
||||
* <li>源码编译(COMPILE)</li>
|
||||
* <li>产物打包(PACKAGE)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param args CLI 传入的参数数组
|
||||
* @return 执行结果码(0 表示成功)
|
||||
* @throws Exception 执行过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
|
||||
Path dslFile = Paths.get("project.cloud");
|
||||
Project project = CloudDSLParser.parse(dslFile);
|
||||
DependencyResolver resolver = new DependencyResolver(Paths.get(System.getProperty("user.home"), ".snow", "cache"));
|
||||
LifecycleManager lm = new LifecycleManager();
|
||||
|
||||
// 注册各阶段任务
|
||||
lm.register(LifecyclePhase.RESOLVE_DEPENDENCIES, () -> resolver.resolve(project));
|
||||
lm.register(LifecyclePhase.COMPILE, new CompileTask(project));
|
||||
lm.register(LifecyclePhase.PACKAGE, new PackageTask(project));
|
||||
|
||||
lm.executeAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
63
src/main/java/org/jcnc/snow/cli/commands/CleanCommand.java
Normal file
@ -0,0 +1,63 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecycleManager;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
|
||||
import org.jcnc.snow.pkg.tasks.CleanTask;
|
||||
|
||||
/**
|
||||
* CLI 命令:清理构建输出和本地缓存目录。
|
||||
* <p>
|
||||
* 用于清除项目生成的 build、dist 等中间产物,保持工作区整洁。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow clean
|
||||
* </pre>
|
||||
*/
|
||||
public final class CleanCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名称,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称,如 "clean"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "clean";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Clean build outputs and local cache, remove intermediate artifacts, and free disk space.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage: snow clean ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行清理任务。
|
||||
*
|
||||
* @param args CLI 传入的参数数组
|
||||
* @return 执行结果码(0 表示成功)
|
||||
* @throws Exception 执行过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
LifecycleManager lm = new LifecycleManager();
|
||||
lm.register(LifecyclePhase.CLEAN, new CleanTask());
|
||||
lm.executeAll();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
92
src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
Normal file
@ -0,0 +1,92 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.dsl.CloudDSLParser;
|
||||
import org.jcnc.snow.pkg.model.Project;
|
||||
import org.jcnc.snow.pkg.tasks.CompileTask;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CLI 命令:编译当前项目。
|
||||
*
|
||||
* <p>工作模式说明:</p>
|
||||
* <ul>
|
||||
* <li><strong>Cloud 模式</strong>
|
||||
* - 项目根目录存在 {@code project.cloud} 时触发;
|
||||
* - 解析 build 区块,自动推导源码目录与输出文件名;
|
||||
* - 用法:{@code snow compile [run]}</li>
|
||||
* <li><strong>Local 模式</strong>
|
||||
* - 未检测到 {@code project.cloud} 时回退;
|
||||
* - 保持向后兼容:{@code snow compile [run] [-o <name>] [-d <srcDir>] [file.snow …]}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>两种模式均将最终参数交由 {@link CompileTask} 处理。</p>
|
||||
*/
|
||||
public final class CompileCommand implements CLICommand {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "compile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Compile .snow source files into VM byte-code (.water).";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" snow compile [run] (cloud mode, use project.cloud)");
|
||||
System.out.println(" snow compile [run] [-o <name>] [-d <srcDir>] [file1.snow …] (GOPATH mode)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
|
||||
Path dslFile = Paths.get("project.cloud");
|
||||
Project project;
|
||||
String[] compileArgs;
|
||||
|
||||
/* ---------- 1. Cloud 模式 ---------- */
|
||||
if (Files.exists(dslFile)) {
|
||||
project = CloudDSLParser.parse(dslFile);
|
||||
|
||||
List<String> argList = new ArrayList<>();
|
||||
|
||||
// 保留用户在 cloud 模式下传入的 “run” 标志
|
||||
for (String a : args) {
|
||||
if ("run".equals(a)) {
|
||||
argList.add("run");
|
||||
}
|
||||
}
|
||||
|
||||
/* 源码目录:build.srcDir -> 默认 src */
|
||||
String srcDir = project.getBuild().get("srcDir", "src");
|
||||
argList.add("-d");
|
||||
argList.add(srcDir);
|
||||
|
||||
/* 输出名称:build.output -> fallback to artifact */
|
||||
String output = project.getBuild().get("output", project.getArtifact());
|
||||
argList.add("-o");
|
||||
argList.add(output);
|
||||
|
||||
compileArgs = argList.toArray(new String[0]);
|
||||
}
|
||||
/* ---------- 2. Local 模式 ---------- */
|
||||
else {
|
||||
project = Project.fromFlatMap(Collections.emptyMap()); // 占位项目,保持接口统一
|
||||
compileArgs = args; // 透传原始 CLI 参数
|
||||
}
|
||||
|
||||
// 委托给 CompileTask 完成实际编译/运行
|
||||
new CompileTask(project, compileArgs).run();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.dsl.CloudDSLParser;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecycleManager;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
|
||||
import org.jcnc.snow.pkg.model.Project;
|
||||
import org.jcnc.snow.pkg.tasks.GenerateTask;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:根据 project.cloud 生成项目目录结构。
|
||||
* <p>
|
||||
* 负责解析云项目描述文件,并通过 {@link GenerateTask}
|
||||
* 在 INIT 生命周期阶段内生成基础目录结构。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow generate
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 注意事项:
|
||||
* - 若当前目录不存在 project.cloud,则提示用户先执行 `snow init`。
|
||||
* - 执行成功后,会输出已创建的目录/文件。
|
||||
* </p>
|
||||
*/
|
||||
public final class GenerateCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名称,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称,如 "generate"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "generate";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Generate project directory structure based on project.cloud.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage: snow generate");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行生成任务。
|
||||
*
|
||||
* @param args CLI 传入的参数数组(此命令不接受参数)
|
||||
* @return 执行结果码(0 表示成功,1 表示 project.cloud 缺失)
|
||||
* @throws Exception 执行过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
Path dsl = Paths.get("project.cloud");
|
||||
if (Files.notExists(dsl)) {
|
||||
System.err.println("project.cloud not found. Please run `snow init` first.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 1. 解析 DSL */
|
||||
Project project = CloudDSLParser.parse(dsl);
|
||||
|
||||
/* 2. 执行生成任务 —— 复用 Lifecycle INIT 阶段 */
|
||||
LifecycleManager lm = new LifecycleManager();
|
||||
lm.register(LifecyclePhase.INIT, new GenerateTask(project));
|
||||
lm.executeAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
71
src/main/java/org/jcnc/snow/cli/commands/InitCommand.java
Normal file
@ -0,0 +1,71 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.cli.utils.ProjectCloudExample;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:初始化项目配置文件。
|
||||
* <p>
|
||||
* 用于快速生成 DSL 配置文件(project.cloud)。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow init
|
||||
* </pre>
|
||||
*/
|
||||
public final class InitCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名称,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称,如 "init"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "init";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Initialize a new project with project.cloud file.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage: snow init");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行项目初始化流程,仅创建 DSL 配置文件。
|
||||
*
|
||||
* @param args CLI 传入的参数数组
|
||||
* @return 执行结果码(0 表示成功)
|
||||
* @throws Exception 文件创建过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
// 仅生成 `.cloud` 文件
|
||||
Path dir = Paths.get(".").toAbsolutePath();
|
||||
Path dsl = dir.resolve("project.cloud");
|
||||
if (Files.notExists(dsl)) {
|
||||
Files.writeString(dsl, ProjectCloudExample.getProjectCloud());
|
||||
System.out.println("[init] created " + dsl);
|
||||
} else {
|
||||
System.out.println("[init] project.cloud already exists");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
65
src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java
Normal file
@ -0,0 +1,65 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.dsl.CloudDSLParser;
|
||||
import org.jcnc.snow.pkg.model.Project;
|
||||
import org.jcnc.snow.pkg.resolver.DependencyResolver;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:解析并下载项目依赖到本地缓存。
|
||||
* <p>
|
||||
* 适用于离线使用和依赖预热场景,会自动读取项目描述文件并处理依赖缓存。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow install
|
||||
* </pre>
|
||||
*/
|
||||
public final class InstallCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名称,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称,如 "install"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "install";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Resolve and download project dependencies to local cache for offline development or faster builds.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage: snow install ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行依赖解析和下载任务。
|
||||
*
|
||||
* @param args CLI 传入的参数数组
|
||||
* @return 执行结果码(0 表示成功)
|
||||
* @throws Exception 解析或下载依赖过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
Project project = CloudDSLParser.parse(Paths.get("project.cloud"));
|
||||
DependencyResolver resolver = new DependencyResolver(Paths.get(System.getProperty("user.home"), ".snow", "cache"));
|
||||
resolver.resolve(project);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
74
src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java
Normal file
@ -0,0 +1,74 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.dsl.CloudDSLParser;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecycleManager;
|
||||
import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
|
||||
import org.jcnc.snow.pkg.model.Project;
|
||||
import org.jcnc.snow.pkg.tasks.PublishTask;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:将已构建的项目包发布到远程仓库。
|
||||
* <p>
|
||||
* 用于持续集成、交付或分发场景。
|
||||
* 支持自动读取 DSL 项目描述文件,并注册和执行发布生命周期阶段的任务。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow publish
|
||||
* </pre>
|
||||
*/
|
||||
public final class PublishCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回该命令的名称(用于 CLI 调用)。
|
||||
*
|
||||
* @return 命令名称字符串,如 "publish"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "publish";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Publish the built package to a remote repository, suitable for continuous integration, delivery, or project distribution.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息,供终端用户参考。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage: snow publish ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行发布命令。
|
||||
* <ul>
|
||||
* <li>解析项目描述文件(如 project.cloud)</li>
|
||||
* <li>注册并执行 PUBLISH 阶段的任务</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param args CLI 传入的参数数组
|
||||
* @return 执行结果码(0表示成功)
|
||||
* @throws Exception 执行过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
Project project = CloudDSLParser.parse(Paths.get("project.cloud"));
|
||||
LifecycleManager lm = new LifecycleManager();
|
||||
lm.register(LifecyclePhase.PUBLISH, new PublishTask(project));
|
||||
lm.executeAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
66
src/main/java/org/jcnc/snow/cli/commands/RunCommand.java
Normal file
@ -0,0 +1,66 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.tasks.RunTask;
|
||||
|
||||
/**
|
||||
* CLI 命令:运行已编译的 VM 字节码文件(.water)。
|
||||
* <p>
|
||||
* 仅解析参数并委托给 {@link RunTask},
|
||||
* 将 VM 运行逻辑下沉至 pkg 层,保持 CLI 无状态、薄封装。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow run main.water
|
||||
* </pre>
|
||||
*/
|
||||
public final class RunCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名称,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称,如 "run"
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "run";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Run the compiled VM bytecode file (.water)";
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行运行任务。
|
||||
*
|
||||
* @param args CLI 传入的参数数组
|
||||
* @return 执行结果码(0 表示成功,非 0 表示失败)
|
||||
* @throws Exception 执行过程中出现错误时抛出
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
printUsage();
|
||||
return 1;
|
||||
}
|
||||
// 委托给 RunTask 执行字节码运行逻辑
|
||||
new RunTask(args).run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印命令用法信息。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" snow run <program.water>");
|
||||
}
|
||||
}
|
||||
59
src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java
Normal file
@ -0,0 +1,59 @@
|
||||
package org.jcnc.snow.cli.commands;
|
||||
|
||||
import org.jcnc.snow.cli.SnowCLI;
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
|
||||
/**
|
||||
* CLI 子命令:输出当前 Snow 工具的版本号。
|
||||
* <p>
|
||||
* 用于显示当前 CLI 工具版本,便于诊断、升级、兼容性确认等场景。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* $ snow version
|
||||
* </pre>
|
||||
*/
|
||||
public final class VersionCommand implements CLICommand {
|
||||
|
||||
/**
|
||||
* 返回命令名,用于 CLI 调用。
|
||||
*
|
||||
* @return 命令名称字符串("version")
|
||||
*/
|
||||
@Override
|
||||
public String name() {
|
||||
return "version";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回命令简介,用于 CLI 帮助或命令列表展示。
|
||||
*
|
||||
* @return 命令描述字符串
|
||||
*/
|
||||
@Override
|
||||
public String description() {
|
||||
return "Print snow version.";
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印该命令的用法说明。
|
||||
*/
|
||||
@Override
|
||||
public void printUsage() {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" snow version");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 version 命令,输出当前 Snow 的版本号。
|
||||
*
|
||||
* @param args 命令参数,此命令不接受额外参数
|
||||
* @return 0 表示成功执行
|
||||
*/
|
||||
@Override
|
||||
public int execute(String[] args) {
|
||||
System.out.println("snow version \"" + SnowCLI.SNOW_VERSION + "\"");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
70
src/main/java/org/jcnc/snow/cli/utils/CLIUtils.java
Normal file
@ -0,0 +1,70 @@
|
||||
package org.jcnc.snow.cli.utils;
|
||||
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 命令行界面通用工具类,提供全局帮助和版本标志、全局选项定义,以及打印通用用法的方法。
|
||||
*/
|
||||
public class CLIUtils {
|
||||
|
||||
/**
|
||||
* 全局帮助标志集合,支持 "help"、"-h"、"--help"。
|
||||
*/
|
||||
public static final Set<String> GLOBAL_HELP_FLAGS = Set.of(
|
||||
"help", "-h", "--help"
|
||||
);
|
||||
|
||||
/**
|
||||
* 全局版本标志集合,支持 "-v"、"--version"。
|
||||
*/
|
||||
public static final Set<String> GLOBAL_VERSION_FLAGS = Set.of(
|
||||
"-v", "--version"
|
||||
);
|
||||
|
||||
/**
|
||||
* 全局选项列表,包括帮助和版本选项的描述。
|
||||
*/
|
||||
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")
|
||||
);
|
||||
|
||||
/**
|
||||
* 打印命令行工具的通用用法说明。
|
||||
* <p>
|
||||
*
|
||||
* @param commands 可用子命令名称到命令处理器的映射,用于列出所有子命令及其描述
|
||||
*/
|
||||
public static void printGeneralUsage(Map<String, Supplier<CLICommand>> commands) {
|
||||
System.out.println("Usage:");
|
||||
System.out.println(" snow [OPTIONS] <command>");
|
||||
System.out.println();
|
||||
System.out.println("Options:");
|
||||
for (Option opt : GLOBAL_OPTIONS) {
|
||||
String flags = String.join(", ", opt.flags());
|
||||
System.out.printf(" %-15s %s%n", flags, opt.description());
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println("Commands:");
|
||||
commands.forEach((name, supplier) -> {
|
||||
CLICommand c = supplier.get();
|
||||
System.out.printf(" %-10s %s%n", name, c.description());
|
||||
});
|
||||
System.out.println();
|
||||
System.out.println("Use \"snow <command> --help\" for command-specific options.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局选项的数据结构,包含选项标志和描述。
|
||||
*
|
||||
* @param flags 选项标志列表,例如 ["-h", "--help"]
|
||||
* @param description 选项功能描述
|
||||
*/
|
||||
public record Option(List<String> flags, String description) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package org.jcnc.snow.cli.utils;
|
||||
|
||||
public class ProjectCloudExample {
|
||||
/**
|
||||
* 工具类构造方法,禁止实例化。
|
||||
*/
|
||||
private ProjectCloudExample() {
|
||||
// 工具类不允许实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 main.snow 示例模块的内容字符串。
|
||||
*
|
||||
* @return main.snow 示例模块的完整代码
|
||||
*/
|
||||
public static String getProjectCloud() {
|
||||
return """
|
||||
# Generated by snow init
|
||||
project {
|
||||
group = "com.example"
|
||||
artifact = "demo-app"
|
||||
version = "0.0.1-SNAPSHOT"
|
||||
}
|
||||
|
||||
build {
|
||||
srcDir = "src"
|
||||
output = "build/demo-app"
|
||||
}
|
||||
""";
|
||||
}
|
||||
}
|
||||
41
src/main/java/org/jcnc/snow/cli/utils/VersionUtils.java
Normal file
@ -0,0 +1,41 @@
|
||||
package org.jcnc.snow.cli.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 版本工具类,用于加载资源文件中的 Snow 编程语言版本信息。
|
||||
* <p>
|
||||
* 从 classpath 路径下的 version.properties 文件中读取属性 "snow.version",
|
||||
* 并返回对应的版本号字符串。
|
||||
* </p>
|
||||
*/
|
||||
public class VersionUtils {
|
||||
|
||||
/**
|
||||
* 资源文件路径常量,指向 classpath 根目录下的 version.properties 文件。
|
||||
*/
|
||||
private static final String PROPERTIES_PATH = "/version.properties";
|
||||
|
||||
/**
|
||||
* 加载并返回 Snow 编程语言的版本号。
|
||||
* <p>
|
||||
* 通过 Class.getResourceAsStream 方法读取 version.properties 文件,
|
||||
* 使用 {@link Properties} 类解析并获取 key 为 "snow.version" 的值。
|
||||
* </p>
|
||||
*
|
||||
* @return 从 version.properties 中读取的版本号(如 "1.0.0")
|
||||
* @throws UncheckedIOException 如果读取或解析配置文件时发生 I/O 错误
|
||||
*/
|
||||
public static String loadVersion() {
|
||||
try (InputStream in = VersionUtils.class.getResourceAsStream(PROPERTIES_PATH)) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(in);
|
||||
return properties.getProperty("snow.version");
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to load version from " + PROPERTIES_PATH, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,8 @@ package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper;
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.ir.core.IRValue;
|
||||
import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||
|
||||
@ -2,7 +2,7 @@ package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
@ -62,7 +62,7 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
||||
char t = out.getSlotType(slotId); // 获取参数类型
|
||||
if (t == '\0') t = 'I'; // 类型未知时默认整型
|
||||
// 生成类型相关的加载指令,如 I_LOAD、F_LOAD 等
|
||||
out.emit(OpHelper.opcode(String.valueOf(t) + "_LOAD") + " " + slotId);
|
||||
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
|
||||
}
|
||||
|
||||
// —— 3. 生成 CALL 调用指令 ——
|
||||
@ -70,7 +70,7 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
||||
|
||||
// —— 4. 将返回值存入目标槽,并记录槽的类型 ——
|
||||
int destSlot = slotMap.get(ins.getDest()); // 目标寄存器槽
|
||||
out.emit(OpHelper.opcode(String.valueOf(retType) + "_STORE") + " " + destSlot);
|
||||
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
|
||||
out.setSlotType(destSlot, retType); // 标记返回值类型
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper;
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.ir.instruction.IRCompareJumpInstruction;
|
||||
@ -10,18 +10,26 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 条件比较跳转指令生成器
|
||||
* <b>条件比较跳转指令生成器</b>
|
||||
* <p>
|
||||
* 该类实现了 {@link InstructionGenerator} 接口,用于将 IR 中的条件比较跳转指令
|
||||
* 转换为虚拟机可执行的指令序列。主要流程是先将比较操作数加载到虚拟机栈中,生成比较操作码,
|
||||
* 并发出跳转到目标标签的指令。
|
||||
* 该类实现了 {@link InstructionGenerator} 接口,
|
||||
* 负责将 IR 中的 {@link IRCompareJumpInstruction}(条件比较并跳转指令)
|
||||
* 转换为目标虚拟机(VM)可执行的指令序列。
|
||||
* </p>
|
||||
*
|
||||
* <b>主要功能</b>
|
||||
* <ul>
|
||||
* <li>根据 IR 比较指令左右操作数的类型,自动进行类型提升与转换</li>
|
||||
* <li>生成相应的 VM 加载、类型转换、比较与跳转指令</li>
|
||||
* <li>保证指令的类型前缀与操作数类型一致,提升兼容性与正确性</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstruction> {
|
||||
|
||||
/**
|
||||
* 返回该生成器所支持的指令类型。
|
||||
* 返回本生成器支持的 IR 指令类型。
|
||||
*
|
||||
* @return {@link IRCompareJumpInstruction} 的类对象
|
||||
* @return IRCompareJumpInstruction 的类对象
|
||||
*/
|
||||
@Override
|
||||
public Class<IRCompareJumpInstruction> supportedClass() {
|
||||
@ -29,29 +37,138 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成条件比较跳转相关的虚拟机指令。
|
||||
* <b>类型宽度优先级</b>:D > F > L > I > S > B
|
||||
* <ul>
|
||||
* <li>D(double):6</li>
|
||||
* <li>F(float):5</li>
|
||||
* <li>L(long):4</li>
|
||||
* <li>I(int):3</li>
|
||||
* <li>S(short):2</li>
|
||||
* <li>B(byte):1</li>
|
||||
* <li>未识别类型:0</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param ins 需要生成的条件比较跳转中间指令(IR)
|
||||
* @param out 虚拟机程序构建器,用于输出生成的指令
|
||||
* @param slotMap 虚拟寄存器到实际槽(slot)编号的映射表
|
||||
* @param currentFn 当前处理的函数名(可用于调试或作用域标识)
|
||||
* @param p 类型标记字符
|
||||
* @return 优先级数值(越大类型越宽)
|
||||
*/
|
||||
private static int rank(char p) {
|
||||
return switch (p) {
|
||||
case 'D' -> 6;
|
||||
case 'F' -> 5;
|
||||
case 'L' -> 4;
|
||||
case 'I' -> 3;
|
||||
case 'S' -> 2;
|
||||
case 'B' -> 1;
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回更“宽”的公共类型(即优先级高的类型)。
|
||||
*
|
||||
* @param a 类型标记字符 1
|
||||
* @param b 类型标记字符 2
|
||||
* @return 宽度更高的类型标记字符
|
||||
*/
|
||||
private static char promote(char a, char b) {
|
||||
return rank(a) >= rank(b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单字符类型标记转字符串。
|
||||
*
|
||||
* @param p 类型标记字符
|
||||
* @return 类型字符串
|
||||
*/
|
||||
private static String str(char p) {
|
||||
return String.valueOf(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 {@code from → to} 的类型转换指令名(如不需转换则返回 {@code null})。
|
||||
* <p>
|
||||
* 仅覆盖目前常见的整数与浮点类型提升与转换,后续有新类型可补充。
|
||||
* </p>
|
||||
*
|
||||
* @param from 源类型标记字符
|
||||
* @param to 目标类型标记字符
|
||||
* @return 转换指令名,如“L2I”;无转换返回 {@code null}
|
||||
*/
|
||||
private static String convert(char from, char to) {
|
||||
if (from == to) return null;
|
||||
return switch ("" + from + to) {
|
||||
case "IL" -> "I2L";
|
||||
case "ID" -> "I2D";
|
||||
case "IF" -> "I2F";
|
||||
case "LI" -> "L2I";
|
||||
case "LD" -> "L2D";
|
||||
case "LF" -> "L2F";
|
||||
case "FI" -> "F2I";
|
||||
case "FL" -> "F2L";
|
||||
case "FD" -> "F2D";
|
||||
case "DI" -> "D2I";
|
||||
case "DL" -> "D2L";
|
||||
case "DF" -> "D2F";
|
||||
case "SI" -> "S2I";
|
||||
case "BI" -> "B2I";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 IR 条件比较跳转指令的 VM 指令序列。
|
||||
* <ol>
|
||||
* <li>确定左右操作数的槽位及静态类型</li>
|
||||
* <li>加载并按需类型提升转换</li>
|
||||
* <li>根据公共类型调整比较指令前缀</li>
|
||||
* <li>发出最终比较和跳转指令</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param ins IR 条件比较跳转指令
|
||||
* @param out VMProgramBuilder:用于发出 VM 指令
|
||||
* @param slotMap 虚拟寄存器到 VM 槽位的映射表
|
||||
* @param currentFn 当前处理的函数名(调试用,当前未使用)
|
||||
*/
|
||||
@Override
|
||||
public void generate(IRCompareJumpInstruction ins,
|
||||
VMProgramBuilder out,
|
||||
Map<IRVirtualRegister,Integer> slotMap,
|
||||
String currentFn) {
|
||||
// 获取左操作数所在的寄存器槽编号
|
||||
|
||||
// 1. 获取左右操作数的槽位与静态类型
|
||||
int leftSlot = slotMap.get(ins.left());
|
||||
// 获取右操作数所在的寄存器槽编号
|
||||
int rightSlot = slotMap.get(ins.right());
|
||||
// 加载左操作数到虚拟机栈
|
||||
out.emit(OpHelper.opcode("I_LOAD") + " " + leftSlot);
|
||||
// 加载右操作数到虚拟机栈
|
||||
out.emit(OpHelper.opcode("I_LOAD") + " " + rightSlot);
|
||||
// 获取与当前比较操作对应的虚拟机操作码
|
||||
char lType = out.getSlotType(leftSlot); // 若未登记则默认 'I'
|
||||
char rType = out.getSlotType(rightSlot);
|
||||
char tType = promote(lType, rType); // 公共类型提升
|
||||
|
||||
// 2. 加载左右操作数并按需类型转换
|
||||
// 左操作数
|
||||
out.emit(OpHelper.opcode(str(lType) + "_LOAD") + " " + leftSlot);
|
||||
String cvt = convert(lType, tType);
|
||||
if (cvt != null) {
|
||||
out.emit(OpHelper.opcode(cvt));
|
||||
}
|
||||
|
||||
// 右操作数
|
||||
out.emit(OpHelper.opcode(str(rType) + "_LOAD") + " " + rightSlot);
|
||||
cvt = convert(rType, tType);
|
||||
if (cvt != null) {
|
||||
out.emit(OpHelper.opcode(cvt));
|
||||
}
|
||||
|
||||
// 3. 选择正确的比较指令前缀
|
||||
String cmpOp = IROpCodeMapper.toVMOp(ins.op());
|
||||
// 生成分支跳转指令,如果比较成立则跳转到目标标签
|
||||
/*
|
||||
* 指令前缀(如 int 类型要用 IC_*, long 类型要用 LC_*)
|
||||
*/
|
||||
if (tType == 'I' && cmpOp.startsWith("LC_")) {
|
||||
cmpOp = "IC_" + cmpOp.substring(3);
|
||||
} else if (tType == 'L' && cmpOp.startsWith("IC_")) {
|
||||
cmpOp = "LC_" + cmpOp.substring(3);
|
||||
}
|
||||
|
||||
// 4. 发出比较与跳转指令
|
||||
out.emitBranch(OpHelper.opcode(cmpOp), ins.label());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 指令生成器集中注册表。
|
||||
*
|
||||
* <p>本类在类加载阶段即完成所有后端 {@link InstructionGenerator} 实例
|
||||
* 的创建,并以不可变列表形式对外暴露。
|
||||
*/
|
||||
public final class InstructionGeneratorProvider {
|
||||
|
||||
/** 工具类禁止实例化。 */
|
||||
private InstructionGeneratorProvider() { /* no-instance */ }
|
||||
|
||||
/** 缺省指令生成器列表(不可修改,顺序即执行顺序)。 */
|
||||
private static final List<InstructionGenerator<? extends IRInstruction>> DEFAULT =
|
||||
List.of(
|
||||
new LoadConstGenerator(), // 常量加载
|
||||
new BinaryOpGenerator(), // 二元运算
|
||||
new UnaryOpGenerator(), // 一元运算
|
||||
new CallGenerator(), // 函数调用
|
||||
new ReturnGenerator(), // 函数返回
|
||||
new LabelGenerator(), // 标签定义
|
||||
new JumpGenerator(), // 无条件跳转
|
||||
new CmpJumpGenerator() // 条件跳转
|
||||
);
|
||||
|
||||
/**
|
||||
* 返回生产环境使用的缺省指令生成器列表。
|
||||
* 该列表为不可变集合,如尝试修改将抛出
|
||||
* {@link UnsupportedOperationException}。
|
||||
*
|
||||
* @return 不可变的 {@code List} 实例
|
||||
*/
|
||||
public static List<InstructionGenerator<? extends IRInstruction>> defaultGenerators() {
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.ir.instruction.IRJumpInstruction;
|
||||
|
||||
@ -2,7 +2,7 @@ package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
@ -2,7 +2,7 @@ package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.ir.instruction.ReturnInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package org.jcnc.snow.compiler.backend.generator;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.util.IROpCodeMapper;
|
||||
import org.jcnc.snow.compiler.backend.util.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.utils.IROpCodeMapper;
|
||||
import org.jcnc.snow.compiler.backend.utils.OpHelper;
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package org.jcnc.snow.compiler.backend.util;
|
||||
package org.jcnc.snow.compiler.backend.utils;
|
||||
|
||||
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||
|
||||
@ -82,12 +82,21 @@ public final class IROpCodeMapper {
|
||||
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
|
||||
|
||||
// 比较运算映射
|
||||
opcodeMap.put(IROpCode.CMP_EQ, "IC_E"); // 相等
|
||||
opcodeMap.put(IROpCode.CMP_NE, "IC_NE"); // 不等
|
||||
opcodeMap.put(IROpCode.CMP_LT, "IC_L"); // 小于
|
||||
opcodeMap.put(IROpCode.CMP_GT, "IC_G"); // 大于
|
||||
opcodeMap.put(IROpCode.CMP_LE, "IC_LE"); // 小于等于
|
||||
opcodeMap.put(IROpCode.CMP_GE, "IC_GE"); // 大于等于
|
||||
// 整形32位比较运算映射
|
||||
opcodeMap.put(IROpCode.CMP_IEQ, "IC_E"); // 相等
|
||||
opcodeMap.put(IROpCode.CMP_INE, "IC_NE"); // 不等
|
||||
opcodeMap.put(IROpCode.CMP_ILT, "IC_L"); // 小于
|
||||
opcodeMap.put(IROpCode.CMP_IGT, "IC_G"); // 大于
|
||||
opcodeMap.put(IROpCode.CMP_ILE, "IC_LE"); // 小于等于
|
||||
opcodeMap.put(IROpCode.CMP_IGE, "IC_GE"); // 大于等于
|
||||
|
||||
// 整形64位比较运算映射
|
||||
opcodeMap.put(IROpCode.CMP_LEQ, "LC_E"); // 相等
|
||||
opcodeMap.put(IROpCode.CMP_LNE, "LC_NE"); // 不等
|
||||
opcodeMap.put(IROpCode.CMP_LLT, "LC_L"); // 小于
|
||||
opcodeMap.put(IROpCode.CMP_LGT, "LC_G"); // 大于
|
||||
opcodeMap.put(IROpCode.CMP_LLE, "LC_LE"); // 小于等于
|
||||
opcodeMap.put(IROpCode.CMP_LGE, "LC_GE"); // 大于等于
|
||||
|
||||
// 加载与存储
|
||||
opcodeMap.put(IROpCode.LOAD, "I_LOAD"); // 加载
|
||||
@ -1,4 +1,4 @@
|
||||
package org.jcnc.snow.compiler.backend.util;
|
||||
package org.jcnc.snow.compiler.backend.utils;
|
||||
|
||||
import org.jcnc.snow.vm.engine.VMOpCode;
|
||||
|
||||
@ -22,6 +22,11 @@ public final class OpHelper {
|
||||
*/
|
||||
private static final Map<String, String> OPCODE_MAP;
|
||||
|
||||
/**
|
||||
* opcode 字符串 → 指令名 的静态映射表
|
||||
*/
|
||||
private static final Map<Integer, String> OPCODE_NAME_MAP;
|
||||
|
||||
static {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("I_ADD", Integer.toString(VMOpCode.I_ADD));
|
||||
@ -89,12 +94,18 @@ public final class OpHelper {
|
||||
map.put("L_OR", Integer.toString(VMOpCode.L_OR));
|
||||
map.put("L_XOR", Integer.toString(VMOpCode.L_XOR));
|
||||
map.put("JUMP", Integer.toString(VMOpCode.JUMP));
|
||||
map.put("IC_E", Integer.toString(VMOpCode.IC_E));
|
||||
map.put("IC_NE", Integer.toString(VMOpCode.IC_NE));
|
||||
map.put("IC_G", Integer.toString(VMOpCode.IC_G));
|
||||
map.put("IC_GE", Integer.toString(VMOpCode.IC_GE));
|
||||
map.put("IC_L", Integer.toString(VMOpCode.IC_L));
|
||||
map.put("IC_LE", Integer.toString(VMOpCode.IC_LE));
|
||||
map.put("IC_E", Integer.toString(VMOpCode.I_CE));
|
||||
map.put("IC_NE", Integer.toString(VMOpCode.I_CNE));
|
||||
map.put("IC_G", Integer.toString(VMOpCode.I_CG));
|
||||
map.put("IC_GE", Integer.toString(VMOpCode.I_CGE));
|
||||
map.put("IC_L", Integer.toString(VMOpCode.I_CL));
|
||||
map.put("IC_LE", Integer.toString(VMOpCode.I_CLE));
|
||||
map.put("LC_E", Integer.toString(VMOpCode.L_CE));
|
||||
map.put("LC_NE", Integer.toString(VMOpCode.L_CNE));
|
||||
map.put("LC_G", Integer.toString(VMOpCode.L_CG));
|
||||
map.put("LC_GE", Integer.toString(VMOpCode.L_CGE));
|
||||
map.put("LC_L", Integer.toString(VMOpCode.L_CL));
|
||||
map.put("LC_LE", Integer.toString(VMOpCode.L_CLE));
|
||||
map.put("I_PUSH", Integer.toString(VMOpCode.I_PUSH));
|
||||
map.put("L_PUSH", Integer.toString(VMOpCode.L_PUSH));
|
||||
map.put("S_PUSH", Integer.toString(VMOpCode.S_PUSH));
|
||||
@ -121,6 +132,11 @@ public final class OpHelper {
|
||||
map.put("RET", Integer.toString(VMOpCode.RET));
|
||||
map.put("HALT", Integer.toString(VMOpCode.HALT));
|
||||
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_NAME_MAP = Collections.unmodifiableMap(revmap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,5 +180,27 @@ public final class OpHelper {
|
||||
throw new IllegalStateException("Unknown const type: " + v.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 opcode 数值的字符串形式获取指令名
|
||||
* @param code 字符串形式的 opcode 数值
|
||||
* @return opcode 对应的指令名
|
||||
*/
|
||||
public static String opcodeName(String code) {
|
||||
return opcodeName(Integer.parseInt(code));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 opcode 获取指令名
|
||||
* @param code opcode
|
||||
* @return opcode 对应的指令名
|
||||
*/
|
||||
public static String opcodeName(int code) {
|
||||
String name = OPCODE_NAME_MAP.get(code);
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("Unknown opcode: " + name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
@ -1,149 +0,0 @@
|
||||
package org.jcnc.snow.compiler.cli;
|
||||
|
||||
import org.jcnc.snow.compiler.backend.alloc.RegisterAllocator;
|
||||
import org.jcnc.snow.compiler.backend.builder.VMCodeGenerator;
|
||||
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
|
||||
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
|
||||
import org.jcnc.snow.compiler.backend.generator.*;
|
||||
import org.jcnc.snow.compiler.ir.builder.IRProgramBuilder;
|
||||
import org.jcnc.snow.compiler.ir.core.IRFunction;
|
||||
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
||||
import org.jcnc.snow.compiler.ir.core.IRProgram;
|
||||
import org.jcnc.snow.compiler.lexer.core.LexerEngine;
|
||||
import org.jcnc.snow.compiler.parser.ast.base.Node;
|
||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||
import org.jcnc.snow.compiler.parser.core.ParserEngine;
|
||||
import org.jcnc.snow.compiler.parser.function.ASTPrinter;
|
||||
import org.jcnc.snow.compiler.semantic.core.SemanticAnalyzerRunner;
|
||||
import org.jcnc.snow.vm.engine.VMMode;
|
||||
import org.jcnc.snow.vm.engine.VirtualMachineEngine;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* SnowCompiler CLI —— 多文件 / 单文件 / 目录 模式。
|
||||
*/
|
||||
public class SnowCompiler {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
if (args.length == 0) {
|
||||
System.err.println("""
|
||||
Usage:
|
||||
snow <file1.snow> [file2.snow …]
|
||||
snow -d <srcDir> (compile all *.snow recursively)
|
||||
""");
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------- 1. 收集所有待编译源码 ---------- */
|
||||
List<Path> sources = collectSources(args);
|
||||
if (sources.isEmpty()) {
|
||||
System.err.println("No .snow source files found.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------- 2. 逐个词法+语法分析,合并 AST ---------- */
|
||||
List<Node> allAst = new ArrayList<>();
|
||||
for (Path p : sources) {
|
||||
if (!Files.exists(p)) {
|
||||
System.err.println("File not found: " + p);
|
||||
return;
|
||||
}
|
||||
String code = Files.readString(p, StandardCharsets.UTF_8);
|
||||
|
||||
// 保持原有“## 源代码”打印,但标注文件名,兼容旧脚本
|
||||
System.out.println("## 源代码 (" + p.getFileName() + ")");
|
||||
System.out.println(code);
|
||||
|
||||
LexerEngine lexer = new LexerEngine(code, p.toString());
|
||||
ParserContext ctx = new ParserContext(lexer.getAllTokens(), p.toString());
|
||||
allAst.addAll(new ParserEngine(ctx).parse());
|
||||
}
|
||||
|
||||
/* ---------- 3. 语义分析 ---------- */
|
||||
SemanticAnalyzerRunner.runSemanticAnalysis(allAst, false);
|
||||
|
||||
/* ---------- 4. AST → IR ---------- */
|
||||
IRProgram program = new IRProgramBuilder().buildProgram(allAst);
|
||||
program = reorderForEntry(program); // 保证入口 main 在首位
|
||||
|
||||
System.out.println("## 编译器输出");
|
||||
System.out.println("### AST");
|
||||
ASTPrinter.printJson(allAst);
|
||||
System.out.println("### IR");
|
||||
System.out.println(program);
|
||||
|
||||
/* ---------- 5. IR → VM 指令 ---------- */
|
||||
VMProgramBuilder builder = new VMProgramBuilder();
|
||||
List<InstructionGenerator<? extends IRInstruction>> generators = Arrays.asList(
|
||||
new LoadConstGenerator(),
|
||||
new BinaryOpGenerator(),
|
||||
new UnaryOpGenerator(),
|
||||
new CallGenerator(),
|
||||
new ReturnGenerator(),
|
||||
new LabelGenerator(),
|
||||
new JumpGenerator(),
|
||||
new CmpJumpGenerator()
|
||||
);
|
||||
|
||||
for (IRFunction fn : program.functions()) {
|
||||
Map<org.jcnc.snow.compiler.ir.value.IRVirtualRegister, Integer> slotMap =
|
||||
new RegisterAllocator().allocate(fn);
|
||||
new VMCodeGenerator(slotMap, builder, generators).generate(fn);
|
||||
}
|
||||
List<String> finalCode = builder.build();
|
||||
|
||||
System.out.println("### VM code");
|
||||
finalCode.forEach(System.out::println);
|
||||
|
||||
/* ---------- 6. 运行虚拟机 ---------- */
|
||||
VirtualMachineEngine vm = new VirtualMachineEngine(VMMode.RUN);
|
||||
vm.execute(finalCode);
|
||||
vm.printLocalVariables();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据参数收集待编译文件:
|
||||
* - snow file1 file2 … ← 多文件 / 单文件
|
||||
* - snow -d srcDir ← 目录递归所有 *.snow
|
||||
*/
|
||||
private static List<Path> collectSources(String[] args) throws IOException {
|
||||
if (args.length == 2 && "-d".equals(args[0])) {
|
||||
Path dir = Path.of(args[1]);
|
||||
if (!Files.isDirectory(dir)) {
|
||||
System.err.println("Not a directory: " + dir);
|
||||
return List.of();
|
||||
}
|
||||
try (var stream = Files.walk(dir)) {
|
||||
return stream.filter(p -> p.toString().endsWith(".snow"))
|
||||
.sorted() // 稳定顺序,方便比对输出
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
// 普通文件参数
|
||||
return Arrays.stream(args).map(Path::of).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 把 main 函数放到 Program.functions()[0],保证 PC=0 即入口;
|
||||
* 如果用户未写 main,则保持原顺序(语义分析会报错)。
|
||||
*/
|
||||
private static IRProgram reorderForEntry(IRProgram in) {
|
||||
List<IRFunction> ordered = new ArrayList<>(in.functions());
|
||||
int idx = -1;
|
||||
for (int i = 0; i < ordered.size(); i++) {
|
||||
if ("main".equals(ordered.get(i).name())) {
|
||||
idx = i; break;
|
||||
}
|
||||
}
|
||||
if (idx > 0) Collections.swap(ordered, 0, idx);
|
||||
|
||||
IRProgram out = new IRProgram();
|
||||
ordered.forEach(out::add);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||
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.value.IRConstant;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
||||
@ -90,7 +91,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
// !x → (x == 0)
|
||||
if (op.equals("!")) {
|
||||
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
|
||||
return InstructionFactory.binOp(ctx, IROpCode.CMP_EQ, val, zero);
|
||||
return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, val, zero);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("未知一元运算符: " + op);
|
||||
@ -109,7 +110,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
switch (node) {
|
||||
// 数字字面量,直接加载到目标寄存器
|
||||
case NumberLiteralNode n ->
|
||||
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.parseIntSafely(n.value()));
|
||||
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
|
||||
// 标识符,查找并move到目标寄存器
|
||||
case IdentifierNode id -> {
|
||||
IRVirtualRegister src = ctx.getScope().lookup(id.name());
|
||||
@ -139,11 +140,16 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
String op = bin.operator();
|
||||
IRVirtualRegister left = build(bin.left());
|
||||
IRVirtualRegister right = build(bin.right());
|
||||
// 处理比较操作符
|
||||
if (ExpressionUtils.isComparisonOperator(op)) {
|
||||
return InstructionFactory.binOp(ctx, ExpressionUtils.cmpOp(op), left, right);
|
||||
|
||||
// 1. 比较运算
|
||||
if (ComparisonUtils.isComparisonOperator(op)) {
|
||||
return InstructionFactory.binOp(
|
||||
ctx,
|
||||
ComparisonUtils.cmpOp(op, bin.left(), bin.right()),
|
||||
left, right);
|
||||
}
|
||||
// 处理算术运算符
|
||||
|
||||
// 2. 其他算术 / 逻辑运算
|
||||
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
||||
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
||||
return InstructionFactory.binOp(ctx, code, left, right);
|
||||
@ -161,8 +167,12 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
IRVirtualRegister a = build(bin.left());
|
||||
IRVirtualRegister b = build(bin.right());
|
||||
String op = bin.operator();
|
||||
if (ExpressionUtils.isComparisonOperator(op)) {
|
||||
InstructionFactory.binOpInto(ctx, ExpressionUtils.cmpOp(op), a, b, dest);
|
||||
|
||||
if (ComparisonUtils.isComparisonOperator(op)) {
|
||||
InstructionFactory.binOpInto(
|
||||
ctx,
|
||||
ComparisonUtils.cmpOp(op, bin.left(), bin.right()),
|
||||
a, b, dest);
|
||||
} else {
|
||||
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
|
||||
if (code == null) throw new IllegalStateException("不支持的运算符: " + op);
|
||||
@ -207,7 +217,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
* @return 存放该常量的寄存器
|
||||
*/
|
||||
private IRVirtualRegister buildNumberLiteral(String value) {
|
||||
IRConstant constant = ExpressionUtils.buildNumberConstant(value);
|
||||
IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value);
|
||||
IRVirtualRegister reg = ctx.newRegister();
|
||||
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
||||
return reg;
|
||||
|
||||
@ -51,7 +51,7 @@ public class FunctionBuilder {
|
||||
// 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域
|
||||
for (ParameterNode p : functionNode.parameters()) {
|
||||
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
|
||||
irContext.getScope().declare(p.name(), reg); // 变量名→寄存器绑定
|
||||
irContext.getScope().declare(p.name(), p.type(), reg); // 变量名→寄存器绑定
|
||||
irFunction.addParameter(reg); // 添加到函数参数列表
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,13 @@ final class IRBuilderScope {
|
||||
*/
|
||||
private final Map<String, IRVirtualRegister> vars = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 存储变量名到对应类型的映射。
|
||||
* <br>
|
||||
* 变量名为键,变量类型为值,用于变量类型提升。
|
||||
*/
|
||||
private final Map<String, String> varTypes = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 当前作用域所绑定的 IRFunction 对象,用于申请新的虚拟寄存器。
|
||||
*/
|
||||
@ -44,10 +51,12 @@ final class IRBuilderScope {
|
||||
* 调用绑定的 IRFunction.newRegister() 生成寄存器后保存到映射表中。
|
||||
*
|
||||
* @param name 变量名称,作为映射键使用
|
||||
* @param type 变量类型
|
||||
*/
|
||||
void declare(String name) {
|
||||
void declare(String name, String type) {
|
||||
IRVirtualRegister reg = fn.newRegister();
|
||||
vars.put(name, reg);
|
||||
varTypes.put(name, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,10 +64,12 @@ final class IRBuilderScope {
|
||||
* 该方法可用于将外部或前一作用域的寄存器导入到本作用域。
|
||||
*
|
||||
* @param name 变量名称,作为映射键使用
|
||||
* @param type 变量类型
|
||||
* @param reg 要绑定到该名称的 IRVirtualRegister 实例
|
||||
*/
|
||||
void declare(String name, IRVirtualRegister reg) {
|
||||
void declare(String name, String type, IRVirtualRegister reg) {
|
||||
vars.put(name, reg);
|
||||
varTypes.put(name, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,4 +93,15 @@ final class IRBuilderScope {
|
||||
IRVirtualRegister lookup(String name) {
|
||||
return vars.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据变量名称在当前作用域中查找对应的类型。
|
||||
*
|
||||
* @param name 需要查询的变量名称
|
||||
* @return 如果该名称已声明,则返回对应的类型
|
||||
* 如果未声明,则返回 null
|
||||
*/
|
||||
String lookupType(String name) {
|
||||
return varTypes.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.ir.core.IRFunction;
|
||||
import org.jcnc.snow.compiler.ir.core.IRInstruction;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
|
||||
/**
|
||||
* IRContext 类负责封装当前正在构建的 IRFunction 实例
|
||||
* 以及与之配套的作用域管理(IRBuilderScope),
|
||||
@ -31,6 +32,11 @@ public class IRContext {
|
||||
*/
|
||||
private final IRBuilderScope scope;
|
||||
|
||||
/**
|
||||
* 当前声明变量的类型,不在声明变量时为空
|
||||
*/
|
||||
private String varType;
|
||||
|
||||
/**
|
||||
* 构造一个新的 IRContext,并将指定的 IRFunction 与作用域关联。
|
||||
*
|
||||
@ -41,6 +47,7 @@ public class IRContext {
|
||||
this.scope = new IRBuilderScope();
|
||||
// 关联作用域与 IRFunction,以便在声明变量时申请寄存器
|
||||
this.scope.attachFunction(function);
|
||||
this.varType = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,4 +92,29 @@ public class IRContext {
|
||||
public String newLabel() {
|
||||
return "L" + (labelCounter++);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 declare 编译阶段变量类型
|
||||
*
|
||||
* @return 当前 declare 的变量类型
|
||||
*/
|
||||
public String getVarType() {
|
||||
return varType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前 declare 编译阶段变量类型
|
||||
*
|
||||
*/
|
||||
public void setVarType(String type) {
|
||||
this.varType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前 declare 编译阶段变量类型
|
||||
*
|
||||
*/
|
||||
public void clearVarType() {
|
||||
this.varType = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,14 @@ public final class IRProgramBuilder {
|
||||
* @return 生成的 FunctionNode,用于后续 IRFunction 构建
|
||||
*/
|
||||
private FunctionNode wrapTopLevel(StatementNode stmt) {
|
||||
return new FunctionNode("_start", null, String.valueOf(List.of()), List.of(stmt));
|
||||
return new FunctionNode(
|
||||
"_start",
|
||||
null,
|
||||
String.valueOf(List.of()),
|
||||
List.of(stmt),
|
||||
-1,
|
||||
-1,
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,8 +58,8 @@ public class InstructionFactory {
|
||||
* @param dest 目标寄存器
|
||||
* @param value 要加载的整数常量
|
||||
*/
|
||||
public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, int value) {
|
||||
ctx.addInstruction(new LoadConstInstruction(dest, new IRConstant(value)));
|
||||
public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, IRConstant value) {
|
||||
ctx.addInstruction(new LoadConstInstruction(dest, value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package org.jcnc.snow.compiler.ir.builder;
|
||||
|
||||
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
|
||||
import org.jcnc.snow.compiler.ir.utils.ComparisonUtils;
|
||||
import org.jcnc.snow.compiler.ir.utils.IROpCodeUtils;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import org.jcnc.snow.compiler.parser.ast.*;
|
||||
@ -18,13 +18,18 @@ import java.util.Locale;
|
||||
*/
|
||||
public class StatementBuilder {
|
||||
|
||||
/** 当前 IR 上下文,包含作用域、指令序列等信息。 */
|
||||
/**
|
||||
* 当前 IR 上下文,包含作用域、指令序列等信息。
|
||||
*/
|
||||
private final IRContext ctx;
|
||||
/** 表达式 IR 构建器,用于将表达式节点转为 IR 指令。 */
|
||||
/**
|
||||
* 表达式 IR 构建器,用于将表达式节点转为 IR 指令。
|
||||
*/
|
||||
private final ExpressionBuilder expr;
|
||||
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param ctx IR 编译上下文环境
|
||||
*/
|
||||
public StatementBuilder(IRContext ctx) {
|
||||
@ -32,9 +37,22 @@ public class StatementBuilder {
|
||||
this.expr = new ExpressionBuilder(ctx);
|
||||
}
|
||||
|
||||
private static char typeSuffixFromType(String type) {
|
||||
if (type == null) return '\0';
|
||||
return switch (type.toLowerCase(Locale.ROOT)) {
|
||||
case "byte" -> 'b';
|
||||
case "short" -> 's';
|
||||
case "long" -> 'l';
|
||||
case "float" -> 'f';
|
||||
case "double" -> 'd';
|
||||
default -> '\0'; // 其余默认按 32-bit 整型处理
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个 AST 语句节点转为 IR 指令序列。
|
||||
* 根据节点类型分发到对应的处理方法。
|
||||
*
|
||||
* @param stmt 待转换的语句节点
|
||||
*/
|
||||
public void build(StatementNode stmt) {
|
||||
@ -48,26 +66,44 @@ public class StatementBuilder {
|
||||
buildIf(ifNode);
|
||||
return;
|
||||
}
|
||||
if (stmt instanceof ExpressionStatementNode(ExpressionNode exp)) {
|
||||
if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, _, _, _)) {
|
||||
// 纯表达式语句,如 foo();
|
||||
expr.build(exp);
|
||||
return;
|
||||
}
|
||||
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) {
|
||||
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, _, _, _)) {
|
||||
// 赋值语句,如 a = b + 1;
|
||||
IRVirtualRegister target = getOrDeclareRegister(var);
|
||||
|
||||
final String type = ctx.getScope().lookupType(var);
|
||||
|
||||
// 1. 设置声明变量的类型
|
||||
ctx.setVarType(type);
|
||||
|
||||
IRVirtualRegister target = getOrDeclareRegister(var, type);
|
||||
expr.buildInto(rhs, target);
|
||||
|
||||
// 2. 清除变量声明
|
||||
ctx.clearVarType();
|
||||
|
||||
return;
|
||||
}
|
||||
if (stmt instanceof DeclarationNode decl) {
|
||||
// 变量声明,如 int a = 1;
|
||||
if (decl.getInitializer().isPresent()) {
|
||||
// 声明同时有初值
|
||||
|
||||
// 1. 设置声明变量的类型
|
||||
ctx.setVarType(decl.getType());
|
||||
|
||||
IRVirtualRegister r = expr.build(decl.getInitializer().get());
|
||||
ctx.getScope().declare(decl.getName(), r);
|
||||
|
||||
// 2. 清除变量声明
|
||||
ctx.clearVarType();
|
||||
|
||||
ctx.getScope().declare(decl.getName(), decl.getType(), r);
|
||||
} else {
|
||||
// 仅声明,无初值
|
||||
ctx.getScope().declare(decl.getName());
|
||||
ctx.getScope().declare(decl.getName(), decl.getType());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -89,20 +125,22 @@ public class StatementBuilder {
|
||||
|
||||
/**
|
||||
* 获取变量名对应的寄存器,不存在则声明一个新的。
|
||||
*
|
||||
* @param name 变量名
|
||||
* @return 变量对应的虚拟寄存器
|
||||
*/
|
||||
private IRVirtualRegister getOrDeclareRegister(String name) {
|
||||
private IRVirtualRegister getOrDeclareRegister(String name, String type) {
|
||||
IRVirtualRegister reg = ctx.getScope().lookup(name);
|
||||
if (reg == null) {
|
||||
reg = ctx.newRegister();
|
||||
ctx.getScope().declare(name, reg);
|
||||
ctx.getScope().declare(name, type, reg);
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量构建一组语句节点,顺序处理每个语句。
|
||||
*
|
||||
* @param stmts 语句节点集合
|
||||
*/
|
||||
private void buildStatements(Iterable<StatementNode> stmts) {
|
||||
@ -112,6 +150,7 @@ public class StatementBuilder {
|
||||
/**
|
||||
* 构建循环语句(for/while)。
|
||||
* 处理流程:初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
||||
*
|
||||
* @param loop 循环节点
|
||||
*/
|
||||
private void buildLoop(LoopNode loop) {
|
||||
@ -137,6 +176,7 @@ public class StatementBuilder {
|
||||
/**
|
||||
* 构建分支语句(if/else)。
|
||||
* 处理流程:条件判断 → then 分支 → else 分支(可选)。
|
||||
*
|
||||
* @param ifNode if 语句节点
|
||||
*/
|
||||
private void buildIf(IfNode ifNode) {
|
||||
@ -160,35 +200,33 @@ public class StatementBuilder {
|
||||
/**
|
||||
* 条件跳转指令的生成。
|
||||
* 如果是二元比较表达式,直接使用对应比较操作码;否则等价于与 0 比较。
|
||||
*
|
||||
* @param cond 条件表达式
|
||||
* @param falseLabel 条件不成立时跳转到的标签
|
||||
*/
|
||||
private void emitConditionalJump(ExpressionNode cond, String falseLabel) {
|
||||
if (cond instanceof BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right)
|
||||
&& ExpressionUtils.isComparisonOperator(operator)) {
|
||||
// 如果是比较操作(如 ==, >, <),直接生成对应的条件跳转
|
||||
if (cond instanceof BinaryExpressionNode(
|
||||
ExpressionNode left,
|
||||
String operator,
|
||||
ExpressionNode right,
|
||||
_,
|
||||
_,
|
||||
_
|
||||
)
|
||||
&& ComparisonUtils.isComparisonOperator(operator)) {
|
||||
|
||||
IRVirtualRegister a = expr.build(left);
|
||||
IRVirtualRegister b = expr.build(right);
|
||||
// 获取反向比较操作码
|
||||
IROpCode falseOp = IROpCodeUtils.invert(ExpressionUtils.cmpOp(operator));
|
||||
|
||||
// 使用适配后位宽正确的比较指令
|
||||
IROpCode cmp = ComparisonUtils.cmpOp(operator, left, right);
|
||||
IROpCode falseOp = IROpCodeUtils.invert(cmp);
|
||||
|
||||
InstructionFactory.cmpJump(ctx, falseOp, a, b, falseLabel);
|
||||
} else {
|
||||
// 否则将 cond 与 0 比较,相等则跳转
|
||||
IRVirtualRegister condReg = expr.build(cond);
|
||||
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
|
||||
InstructionFactory.cmpJump(ctx, IROpCode.CMP_EQ, condReg, zero, falseLabel);
|
||||
InstructionFactory.cmpJump(ctx, IROpCode.CMP_IEQ, condReg, zero, falseLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private static char typeSuffixFromType(String type) {
|
||||
if (type == null) return '\0';
|
||||
return switch (type.toLowerCase(Locale.ROOT)) {
|
||||
case "byte" -> 'b';
|
||||
case "short" -> 's';
|
||||
case "long" -> 'l';
|
||||
case "float" -> 'f';
|
||||
case "double" -> 'd';
|
||||
default -> '\0'; // 其余默认按 32-bit 整型处理
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,13 +66,21 @@ public enum IROpCode {
|
||||
DIV_D64, // 64位浮点除法
|
||||
NEG_D64, // 64位浮点取负
|
||||
|
||||
/* ───── 逻辑与比较运算指令 ───── */
|
||||
CMP_EQ, // 相等比较:a == b
|
||||
CMP_NE, // 不等比较:a != b
|
||||
CMP_LT, // 小于比较:a < b
|
||||
CMP_GT, // 大于比较:a > b
|
||||
CMP_LE, // 小于等于:a <= b
|
||||
CMP_GE, // 大于等于: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
|
||||
|
||||
/* ───── 数据访问与常量操作 ───── */
|
||||
LOAD, // 从内存加载数据至寄存器
|
||||
|
||||
@ -9,12 +9,12 @@ public final class IROpCodeMappings {
|
||||
private IROpCodeMappings() {} // 禁止实例化
|
||||
|
||||
// 8位整型运算符映射
|
||||
public static final Map<String, IROpCode> OP_I8 = Map.of(
|
||||
public static final Map<String, IROpCode> OP_B8 = Map.of(
|
||||
"+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8,
|
||||
"*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8
|
||||
);
|
||||
// 16位整型
|
||||
public static final Map<String, IROpCode> OP_I16 = Map.of(
|
||||
public static final Map<String, IROpCode> OP_S16 = Map.of(
|
||||
"+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16,
|
||||
"*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16
|
||||
);
|
||||
@ -38,13 +38,27 @@ public final class IROpCodeMappings {
|
||||
"+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64,
|
||||
"*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64
|
||||
);
|
||||
// 比较操作符映射
|
||||
public static final Map<String, IROpCode> CMP = Map.of(
|
||||
"==", IROpCode.CMP_EQ,
|
||||
"!=", IROpCode.CMP_NE,
|
||||
"<", IROpCode.CMP_LT,
|
||||
">", IROpCode.CMP_GT,
|
||||
"<=", IROpCode.CMP_LE,
|
||||
">=", IROpCode.CMP_GE
|
||||
|
||||
/* ────── 比较运算符映射 ────── */
|
||||
/** 32-bit(int)比较 */
|
||||
public static final Map<String, IROpCode> CMP_I32 = Map.of(
|
||||
"==", IROpCode.CMP_IEQ,
|
||||
"!=", IROpCode.CMP_INE,
|
||||
"<", IROpCode.CMP_ILT,
|
||||
">", IROpCode.CMP_IGT,
|
||||
"<=", IROpCode.CMP_ILE,
|
||||
">=", IROpCode.CMP_IGE
|
||||
);
|
||||
|
||||
/** 64-bit(long)比较 */
|
||||
public static final Map<String, IROpCode> CMP_L64 = Map.of(
|
||||
"==", IROpCode.CMP_LEQ,
|
||||
"!=", IROpCode.CMP_LNE,
|
||||
"<", IROpCode.CMP_LLT,
|
||||
">", IROpCode.CMP_LGT,
|
||||
"<=", IROpCode.CMP_LLE,
|
||||
">=", IROpCode.CMP_LGE
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
package org.jcnc.snow.compiler.ir.utils;
|
||||
|
||||
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||
import org.jcnc.snow.compiler.ir.core.IROpCodeMappings;
|
||||
import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 比较运算辅助工具:
|
||||
* 根据左右操作数类型(目前通过字面量后缀 <code>L/l</code> 判定)选择
|
||||
* 正确的 IR 比较指令,保证 int/long 均能正常运行。
|
||||
*/
|
||||
public final class ComparisonUtils {
|
||||
private ComparisonUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定操作符是否为比较运算符
|
||||
*/
|
||||
public static boolean isComparisonOperator(String op) {
|
||||
// 两张表 key 完全一致,只需检查一张
|
||||
return IROpCodeMappings.CMP_I32.containsKey(op);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回符合操作数位宽的比较 IROpCode。
|
||||
*
|
||||
* @param op 比较符号(==, !=, <, >, <=, >=)
|
||||
* @param left 左操作数 AST
|
||||
* @param right 右操作数 AST
|
||||
*/
|
||||
public static IROpCode cmpOp(String op, ExpressionNode left, ExpressionNode right) {
|
||||
boolean useLong = isLongLiteral(left) || isLongLiteral(right);
|
||||
Map<String, IROpCode> table = useLong ? IROpCodeMappings.CMP_L64
|
||||
: IROpCodeMappings.CMP_I32;
|
||||
return table.get(op);
|
||||
}
|
||||
|
||||
/* ------------ 内部工具 ------------ */
|
||||
|
||||
private static boolean isLongLiteral(ExpressionNode node) {
|
||||
if (node instanceof NumberLiteralNode(String value)) {
|
||||
return value.endsWith("L") || value.endsWith("l");
|
||||
}
|
||||
return false; // 变量暂不处理(后续可扩展符号表查询)
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jcnc.snow.compiler.ir.utils;
|
||||
|
||||
import org.jcnc.snow.compiler.ir.builder.IRContext;
|
||||
import org.jcnc.snow.compiler.ir.core.IROpCode;
|
||||
import org.jcnc.snow.compiler.ir.core.IROpCodeMappings;
|
||||
import org.jcnc.snow.compiler.ir.value.IRConstant;
|
||||
@ -11,61 +12,67 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 表达式分析与运算符辅助工具类。
|
||||
* <p>
|
||||
* 主要功能包括:
|
||||
*
|
||||
* <p>主要功能:</p>
|
||||
* <ul>
|
||||
* <li>字面量常量的解析与类型推断</li>
|
||||
* <li>自动匹配操作码</li>
|
||||
* <li>表达式类型合并与判定</li>
|
||||
* <li>自动匹配算术/比较操作码</li>
|
||||
* <li>表达式类型合并与提升</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class ExpressionUtils {
|
||||
public final class ExpressionUtils {
|
||||
|
||||
/** 用于存储默认的类型后缀(如函数返回类型),线程隔离。 */
|
||||
private ExpressionUtils() {}
|
||||
|
||||
/* ────────────────── 线程级默认类型后缀 ────────────────── */
|
||||
|
||||
/** 默认类型后缀(如当前函数返回类型),线程隔离。 */
|
||||
private static final ThreadLocal<Character> DEFAULT_SUFFIX =
|
||||
ThreadLocal.withInitial(() -> '\0');
|
||||
|
||||
/**
|
||||
* 在进入函数 IR 构建前设置默认的类型后缀(比如函数返回类型)。
|
||||
* @param suffix 默认后缀字符,如 'i', 'l', 'f', 'd' 等
|
||||
*/
|
||||
public static void setDefaultSuffix(char suffix) {
|
||||
DEFAULT_SUFFIX.set(suffix);
|
||||
}
|
||||
public static void setDefaultSuffix(char suffix) { DEFAULT_SUFFIX.set(suffix); }
|
||||
|
||||
/**
|
||||
* 在函数 IR 构建结束后清除默认后缀,避免影响后续分析。
|
||||
*/
|
||||
public static void clearDefaultSuffix() {
|
||||
DEFAULT_SUFFIX.set('\0');
|
||||
}
|
||||
public static void clearDefaultSuffix() { DEFAULT_SUFFIX.set('\0'); }
|
||||
|
||||
/* ───────────────────── 字面量 & 常量 ───────────────────── */
|
||||
|
||||
/**
|
||||
* 解析整数字面量字符串,自动去除类型后缀(b/s/l/f/d/B/S/L/F/D),并转换为 int。
|
||||
*
|
||||
* @param literal 字面量字符串,如 "123", "123l", "42B"
|
||||
* @return 解析得到的 int 整数
|
||||
*/
|
||||
public static int parseIntSafely(String literal) {
|
||||
// 去掉类型后缀,只保留数字部分
|
||||
String digits = literal.replaceAll("[bslfdBSDLF]$", "");
|
||||
return Integer.parseInt(digits);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数字字面量字符串自动判断类型,生成对应类型的 IRConstant。
|
||||
* 支持 b/s/l/f/d 类型后缀与浮点格式,自动分配合适类型。
|
||||
*
|
||||
* @param value 字面量字符串(如 "1", "2l", "3.14f", "5D")
|
||||
* @return 生成的 IRConstant 对象,包含正确类型
|
||||
* 根据数字字面量字符串自动判断类型,生成对应类型的 {@link IRConstant}。
|
||||
* 支持 b/s/l/f/d 后缀与浮点格式。
|
||||
*/
|
||||
public static IRConstant buildNumberConstant(String value) {
|
||||
char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1));
|
||||
public static IRConstant buildNumberConstant(IRContext ctx, String value) {
|
||||
char suffix = value.isEmpty() ? '\0'
|
||||
: Character.toLowerCase(value.charAt(value.length() - 1));
|
||||
|
||||
String digits = switch (suffix) {
|
||||
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
|
||||
default -> value;
|
||||
default -> {
|
||||
/* 如果字面量本身没有后缀,则回退到变量目标类型(如声明语句左值) */
|
||||
if (ctx.getVarType() != null) {
|
||||
String t = ctx.getVarType();
|
||||
suffix = switch (t) {
|
||||
case "byte" -> 'b';
|
||||
case "short" -> 's';
|
||||
case "int" -> 'i';
|
||||
case "long" -> 'l';
|
||||
case "float" -> 'f';
|
||||
case "double" -> 'd';
|
||||
default -> '\0';
|
||||
};
|
||||
// 根据类型后缀或数值格式创建常量
|
||||
}
|
||||
yield value;
|
||||
}
|
||||
};
|
||||
|
||||
/* 创建常量 */
|
||||
return switch (suffix) {
|
||||
case 'b' -> new IRConstant(Byte.parseByte(digits));
|
||||
case 's' -> new IRConstant(Short.parseShort(digits));
|
||||
@ -78,17 +85,10 @@ public class ExpressionUtils {
|
||||
};
|
||||
}
|
||||
|
||||
/* ────────────────────── 一元运算 ────────────────────── */
|
||||
|
||||
/**
|
||||
* 根据表达式节点推断一元取负(-)运算应使用的操作码。
|
||||
*
|
||||
* <p>优先级与 {@link #resolveOpCode} 使用的类型提升规则保持一致:</p>
|
||||
* <ul>
|
||||
* <li>字面量或标识符带显式后缀时,直接以后缀决定位宽;</li>
|
||||
* <li>未显式指定时,默认使用 32 位整型 {@link IROpCode#NEG_I32}。</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param operand 一元取负运算的操作数
|
||||
* @return 匹配的 {@link IROpCode}
|
||||
* 推断一元取负(-)运算应使用的 {@link IROpCode}。
|
||||
*/
|
||||
public static IROpCode negOp(ExpressionNode operand) {
|
||||
char t = typeChar(operand);
|
||||
@ -98,113 +98,82 @@ public class ExpressionUtils {
|
||||
case 'l' -> IROpCode.NEG_L64;
|
||||
case 'f' -> IROpCode.NEG_F32;
|
||||
case 'd' -> IROpCode.NEG_D64;
|
||||
default -> IROpCode.NEG_I32;
|
||||
default -> IROpCode.NEG_I32; // '\0' 或 'i'
|
||||
};
|
||||
}
|
||||
|
||||
/* =================== 类型推断与操作符匹配 =================== */
|
||||
/* ────────────────── 比较运算(已适配 long) ────────────────── */
|
||||
|
||||
/** 判断给定字符串是否是比较运算符(==, !=, <, >, <=, >=)。 */
|
||||
public static boolean isComparisonOperator(String op) {
|
||||
return ComparisonUtils.isComparisonOperator(op);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归推断单个表达式节点的类型后缀(b/s/l/f/d)。
|
||||
* 对于二元表达式,将左右两侧的类型自动提升合并,遵循优先级顺序:d > f > l > s > b > '\0'。
|
||||
*
|
||||
* @param node 表达式节点
|
||||
* @return 类型后缀字符,b/s/l/f/d 或 '\0'
|
||||
* 兼容旧调用:仅凭操作符返回 <em>int32</em> 比较指令。
|
||||
*/
|
||||
public static IROpCode cmpOp(String op) {
|
||||
return IROpCodeMappings.CMP_I32.get(op); // 旧逻辑:一律 i32
|
||||
}
|
||||
|
||||
/**
|
||||
* 推荐调用:根据左右表达式类型自动选择 int / long 比较指令。
|
||||
*/
|
||||
public static IROpCode cmpOp(String op, ExpressionNode left, ExpressionNode right) {
|
||||
return ComparisonUtils.cmpOp(op, left, right);
|
||||
}
|
||||
|
||||
/* ──────────────── 类型推断 & 算术操作码匹配 ──────────────── */
|
||||
|
||||
/** 递归推断单个表达式节点的类型后缀(b/s/i/l/f/d)。 */
|
||||
private static char typeChar(ExpressionNode node) {
|
||||
// 字面量节点,直接判断最后一位
|
||||
if (node instanceof NumberLiteralNode(String value)) {
|
||||
char last = Character.toLowerCase(value.charAt(value.length() - 1));
|
||||
return switch (last) {
|
||||
case 'b', 's', 'l', 'f', 'd' -> last;
|
||||
case 'b','s','i','l','f','d' -> last;
|
||||
default -> looksLikeFloat(value) ? 'd' : '\0';
|
||||
};
|
||||
}
|
||||
// 二元表达式,递归判断左右子节点
|
||||
if (node instanceof BinaryExpressionNode bin) {
|
||||
char l = typeChar(bin.left());
|
||||
char r = typeChar(bin.right());
|
||||
return maxTypeChar(l, r);
|
||||
return maxTypeChar(typeChar(bin.left()), typeChar(bin.right()));
|
||||
}
|
||||
// 其他情况(如变量节点),暂不处理,默认返回 '\0'
|
||||
return '\0';
|
||||
return '\0'; // 变量等暂不处理
|
||||
}
|
||||
|
||||
/**
|
||||
* 推断两个表达式节点合并后的类型后缀。
|
||||
* 返回优先级更高的类型后缀字符。
|
||||
*
|
||||
* @param left 左表达式节点
|
||||
* @param right 右表达式节点
|
||||
* @return 合并后类型的后缀字符
|
||||
*/
|
||||
/** 合并两侧表达式的类型后缀。 */
|
||||
public static char resolveSuffix(ExpressionNode left, ExpressionNode right) {
|
||||
return maxTypeChar(typeChar(left), typeChar(right));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在两个类型后缀中选取精度更高的一个。
|
||||
* 优先级依次为:d > f > l > s > b > '\0'
|
||||
*
|
||||
* @param l 左类型后缀
|
||||
* @param r 右类型后缀
|
||||
* @return 更高优先级的类型后缀字符
|
||||
*/
|
||||
/** 类型优先级:d > f > l > i > s > b > '\0' */
|
||||
private static char maxTypeChar(char l, char r) {
|
||||
if (l == 'd' || r == 'd') return 'd';
|
||||
if (l == 'f' || r == 'f') return 'f';
|
||||
if (l == 'l' || r == 'l') return 'l';
|
||||
if (l == 'i' || r == 'i') return 'i';
|
||||
if (l == 's' || r == 's') return 's';
|
||||
if (l == 'b' || r == 'b') return 'b';
|
||||
return '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定字符串是否为比较运算符(如 >, <, == 等)。
|
||||
*
|
||||
* @param op 操作符字符串
|
||||
* @return 如果是比较操作符返回 true,否则返回 false
|
||||
*/
|
||||
public static boolean isComparisonOperator(String op) {
|
||||
return IROpCodeMappings.CMP.containsKey(op);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取比较操作符对应的中间表示操作码(IROpCode)。
|
||||
*
|
||||
* @param op 比较操作符字符串
|
||||
* @return 对应的 IROpCode,如果不存在则返回 null
|
||||
*/
|
||||
public static IROpCode cmpOp(String op) {
|
||||
return IROpCodeMappings.CMP.get(op);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据操作符和两侧表达式自动选择正确的 IROpCode。
|
||||
* 首先根据参与表达式类型推断后缀,若无法推断则回退到函数默认类型,
|
||||
* 还无法推断则默认使用 i32(32位整型)。
|
||||
*
|
||||
* @param op 操作符字符串,如 "+"
|
||||
* @param left 左侧表达式节点
|
||||
* @param right 右侧表达式节点
|
||||
* @return 匹配的 IROpCode,如果不存在则返回 null
|
||||
* 根据操作符和两侧表达式选择正确的算术 {@link IROpCode}。
|
||||
*/
|
||||
public static IROpCode resolveOpCode(String op,
|
||||
ExpressionNode left,
|
||||
ExpressionNode right) {
|
||||
|
||||
/* 1) 尝试从参与者常量字面量推断 */
|
||||
/* 1. 尝试根据字面量推断 */
|
||||
char suffix = resolveSuffix(left, right);
|
||||
|
||||
/* 2) 若无法推断,退回到函数返回类型(DEFAULT_SUFFIX) */
|
||||
if (suffix == '\0') {
|
||||
suffix = DEFAULT_SUFFIX.get();
|
||||
}
|
||||
/* 2. 若失败则使用函数级默认类型 */
|
||||
if (suffix == '\0') suffix = DEFAULT_SUFFIX.get();
|
||||
|
||||
/* 3) 再次失败则默认为 i32 */
|
||||
/* 3. 仍失败则默认为 int32 */
|
||||
Map<String, IROpCode> table = switch (suffix) {
|
||||
case 'b' -> IROpCodeMappings.OP_I8;
|
||||
case 's' -> IROpCodeMappings.OP_I16;
|
||||
case 'b' -> IROpCodeMappings.OP_B8;
|
||||
case 's' -> IROpCodeMappings.OP_S16;
|
||||
case 'i' -> IROpCodeMappings.OP_I32;
|
||||
case 'l' -> IROpCodeMappings.OP_L64;
|
||||
case 'f' -> IROpCodeMappings.OP_F32;
|
||||
case 'd' -> IROpCodeMappings.OP_D64;
|
||||
@ -214,13 +183,12 @@ public class ExpressionUtils {
|
||||
return table.get(op);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为浮点数形式(即包含小数点或科学计数法 e/E)。
|
||||
*
|
||||
* @param digits 数字字符串
|
||||
* @return 如果看起来像浮点数则返回 true,否则返回 false
|
||||
*/
|
||||
/* ────────────────────────── 工具 ───────────────────────── */
|
||||
|
||||
/** 是否像浮点字面量(包含 '.' 或 e/E)。 */
|
||||
private static boolean looksLikeFloat(String digits) {
|
||||
return digits.indexOf('.') >= 0 || digits.indexOf('e') >= 0 || digits.indexOf('E') >= 0;
|
||||
return digits.indexOf('.') >= 0
|
||||
|| digits.indexOf('e') >= 0
|
||||
|| digits.indexOf('E') >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,13 +8,21 @@ import java.util.Map;
|
||||
* IR 操作码辅助工具。
|
||||
*/
|
||||
public class IROpCodeUtils {
|
||||
private static final Map<IROpCode, IROpCode> INVERT = Map.of(
|
||||
IROpCode.CMP_EQ, IROpCode.CMP_NE,
|
||||
IROpCode.CMP_NE, IROpCode.CMP_EQ,
|
||||
IROpCode.CMP_LT, IROpCode.CMP_GE,
|
||||
IROpCode.CMP_GE, IROpCode.CMP_LT,
|
||||
IROpCode.CMP_GT, IROpCode.CMP_LE,
|
||||
IROpCode.CMP_LE, IROpCode.CMP_GT
|
||||
private static final Map<IROpCode, IROpCode> INVERT = Map.ofEntries(
|
||||
// 32-bit
|
||||
Map.entry(IROpCode.CMP_IEQ, IROpCode.CMP_INE),
|
||||
Map.entry(IROpCode.CMP_INE, IROpCode.CMP_IEQ),
|
||||
Map.entry(IROpCode.CMP_ILT, IROpCode.CMP_IGE),
|
||||
Map.entry(IROpCode.CMP_IGE, IROpCode.CMP_ILT),
|
||||
Map.entry(IROpCode.CMP_IGT, IROpCode.CMP_ILE),
|
||||
Map.entry(IROpCode.CMP_ILE, IROpCode.CMP_IGT),
|
||||
// 64-bit
|
||||
Map.entry(IROpCode.CMP_LEQ, IROpCode.CMP_LNE),
|
||||
Map.entry(IROpCode.CMP_LNE, IROpCode.CMP_LEQ),
|
||||
Map.entry(IROpCode.CMP_LLT, IROpCode.CMP_LGE),
|
||||
Map.entry(IROpCode.CMP_LGE, IROpCode.CMP_LLT),
|
||||
Map.entry(IROpCode.CMP_LGT, IROpCode.CMP_LLE),
|
||||
Map.entry(IROpCode.CMP_LLE, IROpCode.CMP_LGT)
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@ -16,8 +16,17 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||
*
|
||||
* @param variable 左值变量名(即赋值目标)
|
||||
* @param value 表达式右值(即赋值来源)
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode {
|
||||
public record AssignmentNode(
|
||||
String variable,
|
||||
ExpressionNode value,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements StatementNode {
|
||||
|
||||
/**
|
||||
* 返回赋值语句的字符串形式,便于调试与日志输出。
|
||||
|
||||
@ -12,9 +12,18 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
* @param left 左操作数(子表达式)
|
||||
* @param operator 运算符字符串(如 "+", "-", "*", "/" 等)
|
||||
* @param right 右操作数(子表达式)
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record BinaryExpressionNode(ExpressionNode left, String operator,
|
||||
ExpressionNode right) implements ExpressionNode {
|
||||
public record BinaryExpressionNode(
|
||||
ExpressionNode left,
|
||||
String operator,
|
||||
ExpressionNode right,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements ExpressionNode {
|
||||
|
||||
/**
|
||||
* 返回该二元运算表达式的字符串表示形式。
|
||||
|
||||
@ -14,6 +14,7 @@ import java.util.List;
|
||||
* @param arguments 参数表达式列表,表示函数调用中传递给函数的实际参数。参数的顺序与调用顺序一致。
|
||||
* @param line 当前表达式所在的行号,方便调试和错误定位。
|
||||
* @param column 当前表达式所在的列号,用于精确定位错误位置。
|
||||
* @param file 当前表达式所在的文件,用于错误定位。
|
||||
*/
|
||||
public record CallExpressionNode(
|
||||
ExpressionNode callee, // 被调用的表达式节点,表示函数或方法名
|
||||
|
||||
@ -23,6 +23,15 @@ public class DeclarationNode implements StatementNode {
|
||||
/** 可选的初始化表达式 */
|
||||
private final Optional<ExpressionNode> initializer;
|
||||
|
||||
/** 当前节点所在的行号 **/
|
||||
private final int line;
|
||||
|
||||
/** 当前节点所在的列号 **/
|
||||
private final int column;
|
||||
|
||||
/** 当前节点所在的文件 **/
|
||||
private final String file;
|
||||
|
||||
/**
|
||||
* 构造一个 {@code DeclarationNode} 实例。
|
||||
*
|
||||
@ -30,10 +39,13 @@ public class DeclarationNode implements StatementNode {
|
||||
* @param type 变量类型字符串(如 "int"、"string")
|
||||
* @param initializer 可选初始化表达式,若为 {@code null} 表示未初始化
|
||||
*/
|
||||
public DeclarationNode(String name, String type, ExpressionNode initializer) {
|
||||
public DeclarationNode(String name, String type, ExpressionNode initializer, int line, int column, String file) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.initializer = Optional.ofNullable(initializer);
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,4 +74,29 @@ public class DeclarationNode implements StatementNode {
|
||||
public Optional<ExpressionNode> getInitializer() {
|
||||
return initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的行号。
|
||||
*
|
||||
* @return 当前表达式的行号。
|
||||
*/
|
||||
public int line() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的列号。
|
||||
*
|
||||
* @return 当前表达式的列号。
|
||||
*/
|
||||
public int column() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的文件名。
|
||||
*
|
||||
* @return 当前表达式所在的文件名。
|
||||
*/
|
||||
public String file() { return file; }
|
||||
}
|
||||
@ -11,6 +11,14 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||
* </p>
|
||||
*
|
||||
* @param expression 表达式主体,通常为函数调用、赋值、方法链式调用等可求值表达式。
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode {
|
||||
public record ExpressionStatementNode(
|
||||
ExpressionNode expression,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements StatementNode {
|
||||
}
|
||||
@ -17,7 +17,17 @@ import java.util.List;
|
||||
* @param parameters 参数列表,每项为 {@link ParameterNode} 表示一个形参定义
|
||||
* @param returnType 函数的返回类型(如 "int"、"void" 等)
|
||||
* @param body 函数体语句块,由一组 {@link StatementNode} 构成
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record FunctionNode(String name, List<ParameterNode> parameters, String returnType,
|
||||
List<StatementNode> body) implements Node {
|
||||
public record FunctionNode(
|
||||
String name,
|
||||
List<ParameterNode> parameters,
|
||||
String returnType,
|
||||
List<StatementNode> body,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements Node {
|
||||
}
|
||||
@ -10,8 +10,16 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
* </p>
|
||||
*
|
||||
* @param name 标识符的文本名称(如变量名 "x",函数名 "foo")
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record IdentifierNode(String name) implements ExpressionNode {
|
||||
public record IdentifierNode(
|
||||
String name,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements ExpressionNode {
|
||||
|
||||
/**
|
||||
* 返回标识符节点的字符串形式,通常为其名称本身。
|
||||
|
||||
@ -29,10 +29,16 @@ import java.util.List;
|
||||
* @param condition 控制分支执行的条件表达式
|
||||
* @param thenBranch 条件为 true 时执行的语句块
|
||||
* @param elseBranch 条件为 false 时执行的语句块(可为空)
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record IfNode(
|
||||
ExpressionNode condition,
|
||||
List<StatementNode> thenBranch,
|
||||
List<StatementNode> elseBranch
|
||||
List<StatementNode> elseBranch,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements StatementNode {
|
||||
}
|
||||
@ -14,6 +14,14 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
|
||||
* </p>
|
||||
*
|
||||
* @param moduleName 被导入的模块名称,通常为点分层次结构(如 "core.utils")
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record ImportNode(String moduleName) implements Node {
|
||||
public record ImportNode(
|
||||
String moduleName,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements Node {
|
||||
}
|
||||
@ -17,7 +17,17 @@ import java.util.List;
|
||||
* @param condition 每次迭代前评估的条件表达式,控制循环是否继续
|
||||
* @param update 每轮迭代完成后执行的更新语句
|
||||
* @param body 循环体语句列表,表示循环主体执行逻辑
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update,
|
||||
List<StatementNode> body) implements StatementNode {
|
||||
public record LoopNode(
|
||||
StatementNode initializer,
|
||||
ExpressionNode condition,
|
||||
StatementNode update,
|
||||
List<StatementNode> body,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements StatementNode {
|
||||
}
|
||||
@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
*
|
||||
* @param object 左侧对象表达式,表示成员所属的作用域或容器
|
||||
* @param member 要访问的成员名称(字段名或方法名)
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode {
|
||||
public record MemberExpressionNode(
|
||||
ExpressionNode object,
|
||||
String member,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements ExpressionNode {
|
||||
|
||||
/**
|
||||
* 返回成员访问表达式的字符串形式。
|
||||
|
||||
@ -13,8 +13,18 @@ import java.util.StringJoiner;
|
||||
* @param name 模块名称。
|
||||
* @param imports 模块导入列表,每个导入是一个 {@link ImportNode}。
|
||||
* @param functions 模块中的函数列表,每个函数是一个 {@link FunctionNode}。
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record ModuleNode(String name, List<ImportNode> imports, List<FunctionNode> functions) implements Node {
|
||||
public record ModuleNode(
|
||||
String name,
|
||||
List<ImportNode> imports,
|
||||
List<FunctionNode> functions,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements Node {
|
||||
|
||||
/**
|
||||
* 返回模块节点的字符串表示形式,包含模块名、导入模块列表和函数列表。
|
||||
|
||||
@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
|
||||
*
|
||||
* @param name 参数名称标识符
|
||||
* @param type 参数类型字符串(如 "int"、"string")
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record ParameterNode(String name, String type) implements Node {
|
||||
public record ParameterNode(
|
||||
String name,
|
||||
String type,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements Node {
|
||||
|
||||
/**
|
||||
* 返回参数的字符串形式,格式为 {@code name:type}。
|
||||
|
||||
@ -23,13 +23,25 @@ public class ReturnNode implements StatementNode {
|
||||
/** 可选的返回值表达式 */
|
||||
private final Optional<ExpressionNode> expression;
|
||||
|
||||
/** 当前节点所在的行号 **/
|
||||
private final int line;
|
||||
|
||||
/** 当前节点所在的列号 **/
|
||||
private final int column;
|
||||
|
||||
/** 当前节点所在的文件 **/
|
||||
private final String file;
|
||||
|
||||
/**
|
||||
* 构造一个 {@code ReturnNode} 实例。
|
||||
*
|
||||
* @param expression 返回值表达式,如果无返回值则可为 {@code null}
|
||||
*/
|
||||
public ReturnNode(ExpressionNode expression) {
|
||||
public ReturnNode(ExpressionNode expression, int line, int column, String file) {
|
||||
this.expression = Optional.ofNullable(expression);
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,4 +52,29 @@ public class ReturnNode implements StatementNode {
|
||||
public Optional<ExpressionNode> getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的行号。
|
||||
*
|
||||
* @return 当前表达式的行号。
|
||||
*/
|
||||
public int line() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的列号。
|
||||
*
|
||||
* @return 当前表达式的列号。
|
||||
*/
|
||||
public int column() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的文件名。
|
||||
*
|
||||
* @return 当前表达式所在的文件名。
|
||||
*/
|
||||
public String file() { return file; }
|
||||
}
|
||||
@ -15,9 +15,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
*
|
||||
* @param operator 一元运算符(仅 "-" 或 "!")
|
||||
* @param operand 运算对象 / 右操作数
|
||||
* @param line 当前节点所在的行号
|
||||
* @param column 当前节点所在的列号
|
||||
* @param file 当前节点所在的文件
|
||||
*/
|
||||
public record UnaryExpressionNode(String operator,
|
||||
ExpressionNode operand) implements ExpressionNode {
|
||||
public record UnaryExpressionNode(
|
||||
String operator,
|
||||
ExpressionNode operand,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements ExpressionNode {
|
||||
|
||||
/**
|
||||
* 生成调试友好的字符串表示,例如 {@code "-x"} 或 {@code "!flag"}。
|
||||
|
||||
@ -37,6 +37,11 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
||||
// 获取当前 token 的行号、列号和文件名
|
||||
int line = ctx.getTokens().peek().getLine();
|
||||
int column = ctx.getTokens().peek().getCol();
|
||||
String file = ctx.getSourceName();
|
||||
|
||||
Token op = ctx.getTokens().next();
|
||||
int prec = precedence.ordinal();
|
||||
|
||||
@ -46,7 +51,7 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i
|
||||
leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]
|
||||
);
|
||||
|
||||
return new BinaryExpressionNode(left, op.getLexeme(), right);
|
||||
return new BinaryExpressionNode(left, op.getLexeme(), right, line, column, file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||