style:优化代码格式和注释
This commit is contained in:
parent
f540d7fad5
commit
e931d9ec06
@ -11,7 +11,7 @@ body:
|
||||
attributes:
|
||||
label: 任务标题
|
||||
description: 简要描述维护内容
|
||||
placeholder: "如:升级 JDK 版本"
|
||||
placeholder: "如: 升级 JDK 版本"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -20,6 +20,6 @@ body:
|
||||
attributes:
|
||||
label: 任务详情
|
||||
description: 描述执行步骤或相关脚本命令
|
||||
placeholder: "如:修改 pom.xml…"
|
||||
placeholder: "如: 修改 pom.xml…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -20,7 +20,7 @@ body:
|
||||
attributes:
|
||||
label: 优化方案
|
||||
description: 详细描述改进思路与实现方式
|
||||
placeholder: "如:缓存机制、算法优化…"
|
||||
placeholder: "如: 缓存机制、算法优化…"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -29,6 +29,6 @@ body:
|
||||
attributes:
|
||||
label: 预期收益
|
||||
description: 描述优化后带来的效益或体验提升
|
||||
placeholder: "如:响应时间缩短 30%…"
|
||||
placeholder: "如: 响应时间缩短 30%…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -32,6 +32,6 @@ body:
|
||||
attributes:
|
||||
label: 修复截止日期
|
||||
description: 填写计划完成的日期 (YYYY-MM-DD)
|
||||
placeholder: "例如:2025-06-20"
|
||||
placeholder: "例如: 2025-06-20"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -20,7 +20,7 @@ body:
|
||||
attributes:
|
||||
label: 已尝试方法
|
||||
description: 列出已尝试过的解决方案或思路
|
||||
placeholder: "如:查阅文档、尝试示例代码…"
|
||||
placeholder: "如: 查阅文档、尝试示例代码…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -29,6 +29,6 @@ body:
|
||||
attributes:
|
||||
label: 期望答案
|
||||
description: 描述希望获得的解答或帮助方向
|
||||
placeholder: "如:最佳实践、配置示例…"
|
||||
placeholder: "如: 最佳实践、配置示例…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -20,7 +20,7 @@ body:
|
||||
attributes:
|
||||
label: 重构原因
|
||||
description: 说明当前存在的痛点或待改进之处
|
||||
placeholder: "如:变量命名不规范、函数职责过多…"
|
||||
placeholder: "如: 变量命名不规范、函数职责过多…"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -29,6 +29,6 @@ body:
|
||||
attributes:
|
||||
label: 预期效果
|
||||
description: 说明重构后带来的好处或验证方式
|
||||
placeholder: "如:提高性能、增强可读性…"
|
||||
placeholder: "如: 提高性能、增强可读性…"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
https://gitee.com/jcnc-org/snow/blob/main/doc/Git-Management/Git-Management.md
|
||||
提交 PR 后,请根据实际情况删除不适用的项。
|
||||
|
||||
1. 请在右侧面板中:
|
||||
1. 请在右侧面板中:
|
||||
- 关联 Issue
|
||||
- 选择 PR 类型(bug 修复 / 新功能 / 文档 / 优化 等)
|
||||
- 添加必要的标签和审查人
|
||||
- 请添加里程碑
|
||||
- 如必要请设置优先级
|
||||
|
||||
2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如:
|
||||
2. 在下面的“检查清单”里,用 `- [x]` 标记已完成,用 `- [ ]` 标记未完成。例如:
|
||||
- [x] 已阅读并遵守项目规范
|
||||
- [ ] 本地通过所有测试
|
||||
- [ ] 文档已更新(如有必要)
|
||||
|
||||
122
README.md
122
README.md
@ -86,11 +86,11 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
## 开发环境安装
|
||||
|
||||
1. **开发环境准备**:
|
||||
1. **开发环境准备**:
|
||||
1. 安装集成开发环境 [IntelliJ IDEA](https://www.jetbrains.com/idea/download)
|
||||
2. 安装 Java 开发工具 [Graalvm-jdk-24](https://www.graalvm.org/downloads/)
|
||||
|
||||
2. **获取源码**:
|
||||
2. **获取源码**:
|
||||
将项目源码下载或克隆到本地目录。
|
||||
```bash
|
||||
git clone https://gitee.com/jcnc-org/snow.git
|
||||
@ -285,37 +285,37 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
独立编译不依赖 `.cloud` 文件,而是直接使用 `Snow` 编译器进行 `.snow` 文件的编译和执行。
|
||||
|
||||
#### 独立编译步骤:
|
||||
#### 独立编译步骤:
|
||||
|
||||
1. **运行编译器:**
|
||||
1. **运行编译器: **
|
||||
你可以通过以下命令来编译单个或多个 `.snow` 文件,或者递归编译一个目录中的所有 `.snow` 源文件为`.water`虚拟机指令。
|
||||
|
||||
* **单个文件编译:**
|
||||
* **单个文件编译: **
|
||||
|
||||
```bash
|
||||
Snow complete [SnowCode].snow
|
||||
```
|
||||
|
||||
* **多个文件编译:**
|
||||
* **多个文件编译: **
|
||||
|
||||
```bash
|
||||
Snow complete [SnowCode1].snow [SnowCode2].snow [SnowCode3].snow -o [Name]
|
||||
```
|
||||
|
||||
* **目录递归编译:**
|
||||
* **目录递归编译: **
|
||||
|
||||
```bash
|
||||
Snow -d path/to/source_dir
|
||||
```
|
||||
|
||||
2. **查看编译输出:**
|
||||
编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出:
|
||||
2. **查看编译输出: **
|
||||
编译过程会输出源代码、抽象语法树(AST)、中间表示(IR)以及虚拟机指令等内容。你可以看到如下几个分段输出:
|
||||
|
||||
* **AST**(抽象语法树)部分以 JSON 格式输出。
|
||||
* **IR**(中间表示)部分会列出逐行的中间代码。
|
||||
* **VM code**(虚拟机指令)会展示虚拟机的字节码指令。
|
||||
|
||||
3. **默认执行模式:**
|
||||
3. **默认执行模式: **
|
||||
编译器会在 **DEBUG 模式** 下运行,显示详细的执行过程和状态,并且在虚拟机中执行编译后的代码,最后会打印出所有局部变量的值。
|
||||
|
||||
---
|
||||
@ -324,30 +324,30 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
集成编译需要使用 `.cloud` 文件来指定项目的配置和结构,适用于项目标准化、依赖管理、构建管理和项目分发等场景。
|
||||
|
||||
#### 集成编译命令:
|
||||
#### 集成编译命令:
|
||||
|
||||
1. **基本用法:**
|
||||
1. **基本用法: **
|
||||
|
||||
```bash
|
||||
snow [OPTIONS] <command>
|
||||
```
|
||||
|
||||
2. **命令选项:**
|
||||
2. **命令选项: **
|
||||
|
||||
* `-h, --help`:显示帮助信息并退出。
|
||||
* `-v, --version`:打印 Snow 编程语言的版本并退出。
|
||||
* `-h, --help`: 显示帮助信息并退出。
|
||||
* `-v, --version`: 打印 Snow 编程语言的版本并退出。
|
||||
|
||||
3. **可用命令:**
|
||||
3. **可用命令: **
|
||||
|
||||
* `compile`:将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。
|
||||
* `clean`:清理构建输出和本地缓存,移除中间产物,释放磁盘空间。
|
||||
* `version`:打印 Snow 的版本。
|
||||
* `run`:运行已编译的虚拟机字节码文件(`.water`)。
|
||||
* `init`:初始化一个新项目,生成 `project.cloud` 文件。
|
||||
* `generate`:根据 `project.cloud` 生成项目目录结构。
|
||||
* `build`:构建当前项目,按顺序解析依赖、编译和打包。
|
||||
* `compile`: 将 `.snow` 源文件编译成虚拟机字节码文件(`.water`)。此命令会使用 `.cloud` 文件来指导编译过程。
|
||||
* `clean`: 清理构建输出和本地缓存,移除中间产物,释放磁盘空间。
|
||||
* `version`: 打印 Snow 的版本。
|
||||
* `run`: 运行已编译的虚拟机字节码文件(`.water`)。
|
||||
* `init`: 初始化一个新项目,生成 `project.cloud` 文件。
|
||||
* `generate`: 根据 `project.cloud` 生成项目目录结构。
|
||||
* `build`: 构建当前项目,按顺序解析依赖、编译和打包。
|
||||
|
||||
4. **例如,执行集成编译命令:**
|
||||
4. **例如,执行集成编译命令: **
|
||||
|
||||
```bash
|
||||
snow compile [SnowCode].snow
|
||||
@ -355,14 +355,14 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
* 此命令会使用 `.cloud` 文件中的配置信息来指导编译过程,并生成 `.water`。
|
||||
|
||||
5. **使用帮助:**
|
||||
如果你需要了解某个命令的详细选项,可以使用:
|
||||
5. **使用帮助: **
|
||||
如果你需要了解某个命令的详细选项,可以使用:
|
||||
|
||||
```bash
|
||||
snow <command> --help
|
||||
```
|
||||
|
||||
例如,查看 `compile` 命令的具体选项:
|
||||
例如,查看 `compile` 命令的具体选项:
|
||||
|
||||
```bash
|
||||
snow compile --help
|
||||
@ -372,7 +372,7 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
|
||||
|
||||
## 示例代码片段
|
||||
|
||||
以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法:
|
||||
以下是一个简单的 Snow 代码示例,演示模块定义,导入和函数声明的基本语法:
|
||||
|
||||
```snow
|
||||
module: Math
|
||||
@ -407,10 +407,10 @@ module: Math
|
||||
end module
|
||||
```
|
||||
|
||||
上述代码定义了一个名为 `Math` 的模块,其中包含两个函数:
|
||||
上述代码定义了一个名为 `Math` 的模块,其中包含两个函数:
|
||||
|
||||
* `main`:不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。
|
||||
* `factorial`:接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个
|
||||
* `main`: 不接收任何参数,返回类型为 `int`。在函数体内调用了 `Math.factorial(6)`,然后返回 `0`。
|
||||
* `factorial`: 接收一个 `int` 类型的参数 `n`,返回类型为 `int`。函数体内先声明并初始化局部变量 `num1` 为 `1`,然后通过一个
|
||||
`loop` 循环(从 `counter = 1` 到 `counter <= n`)依次将 `num1` 乘以 `counter`,循环结束后返回 `num1`,即 `n` 的阶乘值。
|
||||
|
||||
|
||||
@ -418,45 +418,45 @@ end module
|
||||
|
||||
## 项目结构说明
|
||||
|
||||
* `compiler/`:Snow 编译器源代码目录
|
||||
* `compiler/`: Snow 编译器源代码目录
|
||||
|
||||
* `lexer/`:词法分析模块,负责将源码切分为 Token
|
||||
* `parser/`:语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析)
|
||||
* `semantic/`:语义分析模块,负责符号表管理、类型检查等
|
||||
* `ir/`:中间表示(IR)模块,生成并管理三地址码形式的中间代码
|
||||
* `backend/`:编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
|
||||
* `lexer/`: 词法分析模块,负责将源码切分为 Token
|
||||
* `parser/`: 语法分析模块,将 Token 流解析为 AST(含模块/函数/语句解析)
|
||||
* `semantic/`: 语义分析模块,负责符号表管理、类型检查等
|
||||
* `ir/`: 中间表示(IR)模块,生成并管理三地址码形式的中间代码
|
||||
* `backend/`: 编译器后端模块,将 IR 翻译为虚拟机指令,包含寄存器分配和指令生成器
|
||||
|
||||
* `vm/`:虚拟机相关源代码目录
|
||||
* `vm/`: 虚拟机相关源代码目录
|
||||
|
||||
* `commands/`:定义 SnowVM 指令集的具体实现
|
||||
* `engine/`:核心执行引擎,提供指令执行和寄存器/栈管理
|
||||
* `execution/`:执行流程控制(按指令顺序执行、分支跳转等)
|
||||
* `io/`:输入输出辅助类(加载指令、文件解析等)
|
||||
* `gui/`:Swing 可视化调试面板,实时展示局部变量表
|
||||
* `factories/`、`utils/`:指令创建、日志调试等公共工具
|
||||
* `commands/`: 定义 SnowVM 指令集的具体实现
|
||||
* `engine/`: 核心执行引擎,提供指令执行和寄存器/栈管理
|
||||
* `execution/`: 执行流程控制(按指令顺序执行、分支跳转等)
|
||||
* `io/`: 输入输出辅助类(加载指令、文件解析等)
|
||||
* `gui/`: Swing 可视化调试面板,实时展示局部变量表
|
||||
* `factories/`、`utils/`: 指令创建、日志调试等公共工具
|
||||
|
||||
* `pkg/`:内置构建与包管理器 **snow pkg**
|
||||
* `pkg/`: 内置构建与包管理器 **snow pkg**
|
||||
|
||||
* `dsl/`:`.cloud` 描述文件解析器
|
||||
* `tasks/`:预设任务实现(`clean · compile · run · package · publish` 等)
|
||||
* `resolver/`:本地/远程仓库解析与缓存
|
||||
* `lifecycle/`:任务生命周期钩子(pre/post 脚本等)
|
||||
* `model/`:项目、依赖、版本等模型
|
||||
* `utils/`:文件、日志、校验和等通用工具
|
||||
* `doc/`:开发者文档与示例 `.cloud` 配置
|
||||
* `dsl/`: `.cloud` 描述文件解析器
|
||||
* `tasks/`: 预设任务实现(`clean · compile · run · package · publish` 等)
|
||||
* `resolver/`: 本地/远程仓库解析与缓存
|
||||
* `lifecycle/`: 任务生命周期钩子(pre/post 脚本等)
|
||||
* `model/`: 项目、依赖、版本等模型
|
||||
* `utils/`: 文件、日志、校验和等通用工具
|
||||
* `doc/`: 开发者文档与示例 `.cloud` 配置
|
||||
|
||||
* `cli/`:独立的命令行前端
|
||||
* `cli/`: 独立的命令行前端
|
||||
|
||||
* `commands/`:`compile` / `run` / `pkg` 等子命令实现
|
||||
* `api/`:公共选项解析、终端交互抽象
|
||||
* `utils/`:终端颜色、进度条、异常格式化等
|
||||
* `SnowCLI.java`:CLI 主入口
|
||||
* `commands/`: `compile` / `run` / `pkg` 等子命令实现
|
||||
* `api/`: 公共选项解析、终端交互抽象
|
||||
* `utils/`: 终端颜色、进度条、异常格式化等
|
||||
* `SnowCLI.java`: CLI 主入口
|
||||
|
||||
|
||||
## 版权声明
|
||||
|
||||
版权所有 © 2025 许轲(Luke),代表 SnowLang 项目。
|
||||
仓库地址:<https://gitee.com/jcnc-org/snow>
|
||||
仓库地址: <https://gitee.com/jcnc-org/snow>
|
||||
本项目依据 [Apache 2.0 许可证](LICENSE) 进行许可和发布。
|
||||
|
||||
“SnowLang 项目”为由许轲(Luke)发起的独立开源项目。
|
||||
@ -464,7 +464,7 @@ end module
|
||||
|
||||
## 加入我们
|
||||
|
||||
- 微信:`xuxiaolankaka`
|
||||
- QQ:`1399528359`
|
||||
- 邮箱:`luke.k.xu [at] hotmail.com`
|
||||
- 微信: `xuxiaolankaka`
|
||||
- QQ: `1399528359`
|
||||
- 邮箱: `luke.k.xu [at] hotmail.com`
|
||||
|
||||
|
||||
@ -2,27 +2,27 @@
|
||||
|
||||
在执行 `build-project2tar.ps1` 脚本之前,您需要确保 PowerShell 的执行策略允许运行脚本。默认情况下,PowerShell 可能阻止未签名的脚本执行。因此,您需要设置适当的执行策略。
|
||||
|
||||
#### 步骤 1:以管理员身份打开 PowerShell
|
||||
#### 步骤 1: 以管理员身份打开 PowerShell
|
||||
|
||||
* 在 Windows 系统中,搜索 **PowerShell**,右键点击 **Windows PowerShell**,并选择 **以管理员身份运行**。
|
||||
|
||||
#### 步骤 2:设置 PowerShell 执行策略
|
||||
#### 步骤 2: 设置 PowerShell 执行策略
|
||||
|
||||
为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter:
|
||||
为了允许执行 PowerShell 脚本,您需要调整当前用户的执行策略。输入以下命令并按 Enter:
|
||||
|
||||
```powershell
|
||||
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
|
||||
```
|
||||
|
||||
#### 解释:
|
||||
#### 解释:
|
||||
|
||||
* `-Scope CurrentUser`:此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。
|
||||
* `-ExecutionPolicy RemoteSigned`:此策略表示:
|
||||
* `-Scope CurrentUser`: 此参数指定该执行策略仅对当前用户有效,而不会影响系统范围内的其他用户。
|
||||
* `-ExecutionPolicy RemoteSigned`: 此策略表示:
|
||||
|
||||
* 本地创建的脚本可以直接运行。
|
||||
* 从互联网下载的脚本必须具备有效的数字签名才能运行。没有签名的脚本将无法执行,除非您先解除阻止该脚本。
|
||||
|
||||
#### 步骤 3:运行 `build-project2tar.ps1` 脚本
|
||||
#### 步骤 3: 运行 `build-project2tar.ps1` 脚本
|
||||
|
||||
设置完成后,您可以在 PowerShell 中运行 `build-project2tar.ps1` 脚本。确保您已经切换到包含该脚本的目录,或提供完整的文件路径来执行它。
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ $parentDir = Split-Path -Parent $scriptDir
|
||||
$tarPath = Join-Path $parentDir $tarName
|
||||
|
||||
# 输出开始创建 tar 包的消息
|
||||
Write-Output "开始创建 tar 包:$tarName 到 $parentDir ..."
|
||||
Write-Output "开始创建 tar 包: $tarName 到 $parentDir ..."
|
||||
|
||||
# 如果存在旧 tar 包,先删除它
|
||||
if (Test-Path $tarPath) {
|
||||
@ -26,7 +26,7 @@ if (-not (Get-Command $tarCommand -ErrorAction SilentlyContinue)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 执行打包操作:切换到 org\jcnc 目录下再压缩 snow 文件夹
|
||||
# 执行打包操作: 切换到 org\jcnc 目录下再压缩 snow 文件夹
|
||||
try {
|
||||
# 构建命令并执行
|
||||
$tarCommandArgs = "-cf", $tarPath, "-C", "$scriptDir\..\src\main\java\org\jcnc", "snow"
|
||||
@ -34,7 +34,7 @@ try {
|
||||
|
||||
& $tarCommand @tarCommandArgs
|
||||
} catch {
|
||||
Write-Error "❌ 创建 tar 包失败。错误信息:$_"
|
||||
Write-Error "❌ 创建 tar 包失败。错误信息: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
## 1. 版本控制基础
|
||||
|
||||
本项目使用 Git 进行版本控制,并遵循以下基本原则:
|
||||
本项目使用 Git 进行版本控制,并遵循以下基本原则:
|
||||
|
||||
* 所有代码更改必须通过 Git 提交,并推送至远程仓库。
|
||||
* 每次提交必须包括清晰、简洁且具描述性的提交信息,确保团队成员能够轻松理解变更的目的和内容。
|
||||
@ -10,23 +10,23 @@
|
||||
|
||||
## 2. 分支管理
|
||||
|
||||
本项目采用以下分支策略进行代码管理:
|
||||
本项目采用以下分支策略进行代码管理:
|
||||
|
||||
### 2.1 主分支 (`main`)
|
||||
|
||||
* **用途**:`main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。
|
||||
* **更新规则**:仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev` 或 `release` 分支合并到 `main` 时,必须打上版本标签。
|
||||
* **用途**: `main` 分支始终保持项目的稳定版本,且此分支的代码随时可以部署到生产环境。
|
||||
* **更新规则**: 仅允许经过充分测试并审查的代码合并到 `main` 分支。每次从 `dev` 或 `release` 分支合并到 `main` 时,必须打上版本标签。
|
||||
|
||||
### 2.2 开发分支 (`dev`)
|
||||
|
||||
* **用途**:`dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`。
|
||||
* **更新规则**:所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`。
|
||||
* **用途**: `dev` 分支是所有开发工作的集成分支。所有的新功能开发应首先合并至 `dev` 分支,并经过集成测试后再合并到 `main`。
|
||||
* **更新规则**: 所有功能开发完成后,应合并至 `dev` 分支进行集成测试,确认没有问题后再合并到 `main`。
|
||||
|
||||
### 2.3 功能分支 (`feature/*`)
|
||||
|
||||
* **用途**:每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。
|
||||
* **命名规范**:`feature/功能描述`,例如:`feature/ast-folding`、`feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。
|
||||
* **开发流程**:
|
||||
* **用途**: 每个新功能的开发都应从 `dev` 分支创建一个独立的功能分支。
|
||||
* **命名规范**: `feature/功能描述`,例如: `feature/ast-folding`、`feature/user-cli`。所有分支名称应使用小写字母,并且使用破折号(`-`)分隔单词。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `dev` 分支拉取最新代码。
|
||||
2. 完成功能开发后,在本地提交代码并推送至远程仓库。
|
||||
@ -34,9 +34,9 @@
|
||||
|
||||
### 2.4 修复分支 (`bugfix/*`)
|
||||
|
||||
* **用途**:用于修复 Bug,修复分支可以从 `dev` 或 `main` 分支创建。
|
||||
* **命名规范**:`bugfix/bug描述`,例如:`bugfix/fix-ast-error`。
|
||||
* **开发流程**:
|
||||
* **用途**: 用于修复 Bug,修复分支可以从 `dev` 或 `main` 分支创建。
|
||||
* **命名规范**: `bugfix/bug描述`,例如: `bugfix/fix-ast-error`。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `dev` 或 `main` 分支拉取最新代码。
|
||||
2. 完成修复后,提交修改并推送至远程仓库。
|
||||
@ -44,9 +44,9 @@
|
||||
|
||||
### 2.5 发布分支 (`release/*`)
|
||||
|
||||
* **用途**:当 `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。
|
||||
* **命名规范**:`release/vX.X.X`,例如:`release/v1.0.0`。
|
||||
* **开发流程**:
|
||||
* **用途**: 当 `dev` 分支的功能开发完成且准备发布时,应创建一个 `release` 分支进行发布准备。
|
||||
* **命名规范**: `release/vX.X.X`,例如: `release/v1.0.0`。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `dev` 分支创建 `release` 分支。
|
||||
2. 在 `release` 分支上进行版本发布的最终准备工作,如文档更新、版本号调整等。
|
||||
@ -54,24 +54,24 @@
|
||||
|
||||
### 2.6 热修复分支 (`hotfix/*`)
|
||||
|
||||
* **用途**:当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。
|
||||
* **命名规范**:`hotfix/bug描述`,例如:`hotfix/fix-production-crash`。
|
||||
* **开发流程**:
|
||||
* **用途**: 当生产环境中发现紧急问题(如 Bug 或系统崩溃等),需在 `main` 分支上进行快速修复时,应创建一个 `hotfix` 分支进行修复。
|
||||
* **命名规范**: `hotfix/bug描述`,例如: `hotfix/fix-production-crash`。
|
||||
* **开发流程**:
|
||||
|
||||
1. 从 `main` 分支创建 `hotfix` 分支,确保该分支包含生产环境中最新的稳定版本。
|
||||
2. 在 `hotfix` 分支上进行问题修复和相关调整。
|
||||
3. 完成修复后,提交修改并推送至远程仓库。
|
||||
4. 创建拉取请求(PR),将 `hotfix` 分支合并至 `main` 分支并打上版本标签,确保生产环境修复生效。
|
||||
5. 将修复后的变更合并回 `dev` 分支,确保所有的修复和调整同步到开发分支,防止后续开发中出现同样的问题。
|
||||
6. **回滚策略**:如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。
|
||||
6. **回滚策略**: 如果热修复未能解决问题,立即回滚合并,删除 `hotfix` 分支并通知团队,确保不影响生产环境。
|
||||
|
||||
## 3. 提交规范
|
||||
|
||||
为确保提交信息清晰且易于理解,遵循以下提交规范:
|
||||
为确保提交信息清晰且易于理解,遵循以下提交规范:
|
||||
|
||||
### 3.1 提交信息格式
|
||||
|
||||
提交信息应简洁且具有描述性,格式如下:
|
||||
提交信息应简洁且具有描述性,格式如下:
|
||||
|
||||
```
|
||||
[类型] 描述
|
||||
@ -81,20 +81,20 @@
|
||||
|
||||
#### 提交类型
|
||||
|
||||
* `feat`:新增功能
|
||||
* `fix`:修复 Bug
|
||||
* `docs`:文档更新
|
||||
* `style`:代码格式调整(不影响功能)
|
||||
* `refactor`:代码重构
|
||||
* `test`:增加/修改测试
|
||||
* `chore`:工具配置等其他杂项任务
|
||||
* `ci`:持续集成相关改动
|
||||
* `perf`:性能优化
|
||||
* `feat`: 新增功能
|
||||
* `fix`: 修复 Bug
|
||||
* `docs`: 文档更新
|
||||
* `style`: 代码格式调整(不影响功能)
|
||||
* `refactor`: 代码重构
|
||||
* `test`: 增加/修改测试
|
||||
* `chore`: 工具配置等其他杂项任务
|
||||
* `ci`: 持续集成相关改动
|
||||
* `perf`: 性能优化
|
||||
|
||||
#### 示例
|
||||
|
||||
* `feat: 添加 IR 折叠功能`
|
||||
* `fix: 修复问题 Y(原因:X bug,解决方案:Z)`
|
||||
* `fix: 修复问题 Y(原因: X bug,解决方案: Z)`
|
||||
* `docs: 更新 API 文档`
|
||||
* `refactor: 优化 AST 逻辑`
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
### 4.2 代码审查
|
||||
|
||||
* 所有 PR 必须经过至少一名开发者的代码审查。
|
||||
* 审查时应关注以下方面:
|
||||
* 审查时应关注以下方面:
|
||||
|
||||
* 代码是否符合项目的编码规范。
|
||||
* 是否提供了足够的单元测试覆盖。
|
||||
@ -124,14 +124,14 @@
|
||||
|
||||
## 5. 版本发布
|
||||
|
||||
版本发布基于 Git 标签,发布流程如下:
|
||||
版本发布基于 Git 标签,发布流程如下:
|
||||
|
||||
### 5.1 打标签
|
||||
|
||||
每当版本准备发布时,应在 `main` 分支上打上版本标签:
|
||||
每当版本准备发布时,应在 `main` 分支上打上版本标签:
|
||||
|
||||
* **版本号规则**:采用语义化版本控制(SemVer)格式,版本号由三部分组成:`主版本号.次版本号.修订号`(例如:`v1.0.0`)。
|
||||
* **标签命令**:
|
||||
* **版本号规则**: 采用语义化版本控制(SemVer)格式,版本号由三部分组成: `主版本号.次版本号.修订号`(例如: `v1.0.0`)。
|
||||
* **标签命令**:
|
||||
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
## 2. 前置条件
|
||||
|
||||
1. 操作系统:Linux/macOS/Windows
|
||||
1. 操作系统: Linux/macOS/Windows
|
||||
2. Java 项目(Maven)
|
||||
3. GraalVM(建议 24+ 版本)
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
### 3.1 安装 GraalVM
|
||||
|
||||
1. 下载对应平台的 GraalVM Community 版本:[https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/)
|
||||
2. 解压并配置环境变量:
|
||||
1. 下载对应平台的 GraalVM Community 版本: [https://www.graalvm.org/downloads/](https://www.graalvm.org/downloads/)
|
||||
2. 解压并配置环境变量:
|
||||
|
||||
3. 验证安装:
|
||||
3. 验证安装:
|
||||
|
||||
```bash
|
||||
java -version
|
||||
@ -44,12 +44,12 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc
|
||||
|
||||
## 4. Maven 项目配置文件
|
||||
|
||||
通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件:
|
||||
通过将以下配置文件添加到 `pom.xml` 中,为 Native Image 启用 Maven 插件:
|
||||
|
||||
```xml
|
||||
<profiles>
|
||||
<!--
|
||||
原生镜像构建:Linux 平台
|
||||
原生镜像构建: Linux 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
|
||||
- 依赖 musl libc,需提前安装并配置 musl-gcc 工具链
|
||||
-->
|
||||
@ -111,7 +111,7 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc
|
||||
</profile>
|
||||
|
||||
<!--
|
||||
原生镜像构建:Windows 平台
|
||||
原生镜像构建: Windows 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
|
||||
- Windows 上不使用 musl,因此不配置静态链接
|
||||
-->
|
||||
@ -169,6 +169,6 @@ Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24.0.1+9.1 (build 24.0.1+9-jvmc
|
||||
|
||||

|
||||
|
||||
3. 等待 Native Image 构建完成:这个过程可能较慢(数分钟)。
|
||||
3. 等待 Native Image 构建完成: 这个过程可能较慢(数分钟)。
|
||||
4. 可执行文件即可直接运行,无需 JVM。
|
||||
> 生成的可执行文件位于 target/ 目录。
|
||||
|
||||
@ -7,22 +7,22 @@
|
||||
|
||||
## 1.2 背景与目标读者
|
||||
|
||||
自 ChatGPT 3.5 诞生以来,越来越多的个人和企业将 LLM 生成的代码融入日常开发与自动化。然而,实践证明:LLM 生成的代码虽然“看起来没问题”,却常因对底层语言细节把握不准导致微妙 Bug——比如运算符优先级混淆、作用域处理错误、甚至基础库调用都无法编译通过。
|
||||
自 ChatGPT 3.5 诞生以来,越来越多的个人和企业将 LLM 生成的代码融入日常开发与自动化。然而,实践证明: LLM 生成的代码虽然“看起来没问题”,却常因对底层语言细节把握不准导致微妙 Bug——比如运算符优先级混淆、作用域处理错误、甚至基础库调用都无法编译通过。
|
||||
|
||||
于是,我萌生了这样一个想法:**能否设计一门编程语言,让 LLM 在“语法层面”能够更精准、高效地理解和生成代码?**
|
||||
于是,我萌生了这样一个想法: **能否设计一门编程语言,让 LLM 在“语法层面”能够更精准、高效地理解和生成代码?**
|
||||
|
||||
传统编程语言的设计多偏重“计算机”的执行效率,程序员往往在抽象表达和底层性能之间不断权衡。Ruby 之父松本行弘提出“为人而不是为机器编程”的理念。而在 LLM 日益普及的今天,我们应当承认:大型模型正成为“超级程序员”,它们不仅是助手,更是“代码生产的中介”。如果一门语言的语法和设计能最大化发挥 LLM 的推理与生成能力,人机协作的效率将被极大提升。
|
||||
传统编程语言的设计多偏重“计算机”的执行效率,程序员往往在抽象表达和底层性能之间不断权衡。Ruby 之父松本行弘提出“为人而不是为机器编程”的理念。而在 LLM 日益普及的今天,我们应当承认: 大型模型正成为“超级程序员”,它们不仅是助手,更是“代码生产的中介”。如果一门语言的语法和设计能最大化发挥 LLM 的推理与生成能力,人机协作的效率将被极大提升。
|
||||
|
||||
因此,**Snow** 的使命是:让编程语言不再“让人头疼”,而是“让 LLM 更加从容地书写”。目标受众涵盖 LLM 爱好者、开发者、对编译原理感兴趣的学生,以及对性能有追求的工程师甚至是初学者——每个人都能在 Snow 中找到乐趣与成长。
|
||||
因此,**Snow** 的使命是: 让编程语言不再“让人头疼”,而是“让 LLM 更加从容地书写”。目标受众涵盖 LLM 爱好者、开发者、对编译原理感兴趣的学生,以及对性能有追求的工程师甚至是初学者——每个人都能在 Snow 中找到乐趣与成长。
|
||||
|
||||
## 1.3 文章目的
|
||||
|
||||
本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标:
|
||||
本文将带你完整体验 Snow 从零到 v0.1 的诞生历程,围绕四个核心目标:
|
||||
|
||||
* **兴趣驱动的坚持**:用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。
|
||||
* **从规划到实践的拆解**:详解在有限资源下,如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。
|
||||
* **经验与反思**:不仅有“成功输出 1+1=2”的成就感,也有调试死循环、运算符冲突等踩坑经历,全方位展示编程语言设计的挑战与思考。
|
||||
* **激励与号召**:希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。
|
||||
* **兴趣驱动的坚持**: 用真实经历激励更多人相信“兴趣是最好的动力”,哪怕工作再忙,也能靠热爱坚持探索。
|
||||
* **从规划到实践的拆解**: 详解在有限资源下,如何一步步拆解出词法分析、语法解析、AST 构建、解释执行等关键模块,以“先可用后完备”为原则,稳步推进。
|
||||
* **经验与反思**: 不仅有“成功输出 1+1=2”的成就感,也有调试死循环、运算符冲突等踩坑经历,全方位展示编程语言设计的挑战与思考。
|
||||
* **激励与号召**: 希望 Snow 成为开源社区的新起点,邀请更多伙伴参与,见证从 v0.2、v1.0 甚至到未来并发、标准库、包管理等更大梦想的实现。
|
||||
|
||||
---
|
||||
|
||||
@ -31,18 +31,18 @@
|
||||
## 2.1 现有工具的痛点
|
||||
|
||||
* **编程语言过于灵活,缺乏规范**
|
||||
常见的编程语言如 Python、PHP、Ruby,虽然语法简洁、上手快,但“灵活性”本身也带来了不少隐患:变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考:如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶?
|
||||
常见的编程语言如 Python、PHP、Ruby,虽然语法简洁、上手快,但“灵活性”本身也带来了不少隐患: 变量类型可以随意变化,作用域和命名规则宽松,团队协作时代码风格极易失控,隐蔽 Bug 难以及时发现。自动化运维和日常数据处理脚本往往随手一写,维护与交接时却漏洞百出、沟通成本高。许多开发者都在思考: 如果有一门语法严谨、行为可预测,并天然适合团队协作与 LLM 生成的编程语言,是不是能让代码质量和工程效率都上一个台阶?
|
||||
|
||||
* **缺乏专为 LLM 设计的编程语言**
|
||||
当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如:部分语法容易混淆,作用域和可见性规则不直观,LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。
|
||||
当下主流编程语言,基本都是“为人类程序员”而设计,很少考虑 LLM 的生成和推理习惯。比如: 部分语法容易混淆,作用域和可见性规则不直观,LLM 在生成时不仅需要大量提示,结果还常常不理想。缺少一门语法清晰、特征单一、对 LLM 友好的编程语言,导致自动化和智能生成代码场景下,仍然存在很多不可控和效率瓶颈。
|
||||
|
||||
## 2.2 触发想法的场景
|
||||
|
||||
* **对高效与规范的需求日益突出**
|
||||
在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论:能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。
|
||||
在实际开发和运维工作中,我们经常要写各种自动化脚本。由于编程语言过于灵活,代码风格极易失控,维护起来痛苦不堪。团队中常常讨论: 能否有一门语法严谨、易于规范化、适合团队协作的编程语言?大家都希望提升代码质量,减少后期返工。
|
||||
|
||||
* **自研编程语言的大胆设想**
|
||||
随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP,总要写很多提示,还要人工修正各种细节。由此引发思考:如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率?
|
||||
随着 LLM 在自动化、辅助编程中的应用普及,越来越多场景下希望直接“让 LLM 写代码”。但事实是,不管是让 LLM 生成 Python 还是 PHP,总要写很多提示,还要人工修正各种细节。由此引发思考: 如果有一门对 LLM 友好的编程语言,语法特征清晰、行为可预测,能不能大幅提升代码自动生成与落地的效率?
|
||||
|
||||
|
||||
## 2.3 项目愿景
|
||||
@ -62,12 +62,12 @@
|
||||
|
||||
## 3.1 为什么开源
|
||||
|
||||
* **获得社区反馈,检验设计思路**:闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。
|
||||
* **边开源边完善,更吸引贡献者**:功能精简但可用时就发布,容易吸引早期用户参与共建。
|
||||
* **获得社区反馈,检验设计思路**: 闭门造车易“自嗨”,开源能快速获得用户和专家的多视角建议。
|
||||
* **边开源边完善,更吸引贡献者**: 功能精简但可用时就发布,容易吸引早期用户参与共建。
|
||||
|
||||
## 3.2 开源准备工作
|
||||
|
||||
* **许可证选择**:
|
||||
* **许可证选择**:
|
||||
采用 [Apache-2.0](https://gitee.com/jcnc-org/snow/blob/main/LICENSE),最大程度降低贡献门槛。
|
||||
|
||||
## 3.3 项目运行输出
|
||||
@ -248,11 +248,11 @@ Process has ended
|
||||
|
||||
## 4.1 v0.2 初步目标
|
||||
|
||||
1. **完善变量作用域与高级函数调用**:
|
||||
1. **完善变量作用域与高级函数调用**:
|
||||
支持函数参数、返回值、本地与全局变量隔离,以及闭包基础,为并发/异步打基础。
|
||||
2. **完善错误提示与调试信息**:
|
||||
2. **完善错误提示与调试信息**:
|
||||
报错更精准,方便新手调试。
|
||||
3. **预计发布日期:2025 年 7 月 30 日**
|
||||
3. **预计发布日期: 2025 年 7 月 30 日**
|
||||
|
||||
## 4.2 v0.3 目标
|
||||
1. **IDE的支持**
|
||||
@ -262,11 +262,11 @@ Process has ended
|
||||
|
||||
## 4.3 v1.0 长期规划
|
||||
|
||||
1. **初步标准库**:
|
||||
1. **初步标准库**:
|
||||
I/O、字符串、JSON、文件系统,满足日常脚本需求。
|
||||
2. **包管理与模块加载**:
|
||||
2. **包管理与模块加载**:
|
||||
设计 `snowpkg`,支持一键安装依赖、自动模块导入。
|
||||
3. **社区协作与贡献**:
|
||||
3. **社区协作与贡献**:
|
||||
开设设计讨论区、每月线上分享,鼓励贡献代码与案例,让更多人参与 Snow 的成长。
|
||||
|
||||
---
|
||||
@ -275,15 +275,15 @@ Process has ended
|
||||
|
||||
## 5.1 学习收获与成就感
|
||||
|
||||
回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是:让一个想法变成可运行的代码,哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。
|
||||
回望从零到 v0.1 的历程,我最开始设计了虚拟机,然后设计的编译器,最震撼的是: 让一个想法变成可运行的代码,哪怕只输出一句“Hello, Snow!”也足以令人热血沸腾。每一次 Snow 在屏幕上输出,都让我更深刻理解了编译原理的乐趣。
|
||||
|
||||
## 5.2 技术敬畏与情感共鸣
|
||||
|
||||
也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节:多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。
|
||||
也许有人会说“输出一句话算什么”,但其实,每一个简单的表达式背后,都凝结了无数技术细节: 多字符运算符的处理、优先级解析、AST 与符号表、作用域管理、底层 GC 可行性……每一环都让人敬畏计算机科学之美。
|
||||
|
||||
## 5.3 欢迎你的加入
|
||||
|
||||
真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴:
|
||||
真诚邀请所有对编程语言、编译原理、LLM 应用感兴趣的小伙伴:
|
||||
|
||||
1. 在 Gitee 提交 Issue,反馈使用体验和建议;
|
||||
2. Fork 仓库、贡献 PR,参与语法和功能共建;
|
||||
@ -294,7 +294,7 @@ Process has ended
|
||||
> 微信: xuxiaolankaka
|
||||
> QQ: 1399528359
|
||||
|
||||
对于从未写过语言的初学者,我想说:**不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。
|
||||
对于从未写过语言的初学者,我想说: **不要害怕,从 Hello World 开始,你会发现编译原理其实很有趣。** 让我们一起,把 Snow 打造为兼顾 LLM 友好和人类易用的创新编程语言。也许,下一个改变编程世界的创举,就在我们手中诞生。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Snow 语言现状和下一阶段开发路线图
|
||||
|
||||
> 日期:2025-06-11
|
||||
> 日期: 2025-06-11
|
||||
|
||||
## 1. 代码结构与职责
|
||||
| 层次 | 主要包/目录 | 说明 |
|
||||
@ -30,7 +30,7 @@
|
||||
6. **VM**
|
||||
|
||||
* 栈-基 / 寄存器混合架构
|
||||
* 96 条已实现指令(按数据宽度泛化:B/S/I/L/F/D)
|
||||
* 96 条已实现指令(按数据宽度泛化: B/S/I/L/F/D)
|
||||
* 运行时启动器 `VMLauncher`
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
|
||||
## 4. 下一阶段开发路线图
|
||||
|
||||
> 优先级:P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期
|
||||
> 优先级: P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期
|
||||
|
||||
| 优先级 | 功能 | 关键任务 |
|
||||
|--------|------------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
@ -58,18 +58,18 @@
|
||||
| **P0** | **一元表达式解析** | \* 实现 `UnaryOperatorParselet`(`-`, `+`, `!`)<br>\* 对应 `UnaryOpGenerator` 注册 |
|
||||
| **P1** | **数组与切片** | \* 设计 `ArrayType`(元素类型 + 维度)<br>\* 新增 `IndexExpressionNode`、`NewArrayNode`<br>\* VM 扩充 `ALOAD/ASTORE` 指令 |
|
||||
| **P1** | **基础标准库** | \* `print/println`, 文件读写<br>\* 编译期内置绑定到 VM calls |
|
||||
| **P1** | **测试与 CI** | \* JUnit5 单测:Lexer / Parser / Semantic / VM<br>\* CI/CD 自动构建、示例编译运行 |
|
||||
| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局<br>\* 方法调度:静态 or 虚表 |
|
||||
| **P1** | **测试与 CI** | \* JUnit5 单测: Lexer / Parser / Semantic / VM<br>\* CI/CD 自动构建、示例编译运行 |
|
||||
| **P2** | **结构体 / 简单面向对象** | \* 结构体 语法、记录类型布局<br>\* 方法调度: 静态 or 虚表 |
|
||||
| **P2** | **优化管线** | \* 常量折叠、公共子表达式消除<br>\* 简易死代码清除 |
|
||||
| **P2** | **错误与异常系统** | \* 语法:`try … catch … end`<br>\* VM:展开-收缩栈,异常表 |
|
||||
| **P2** | **包管理 & CLI** | \* `snowc` 命令:`build`, `run`, `test`<br>\* 本地缓存 `.snowpkg`与包版本语义 |
|
||||
| **P2** | **错误与异常系统** | \* 语法: `try … catch … end`<br>\* VM: 展开-收缩栈,异常表 |
|
||||
| **P2** | **包管理 & CLI** | \* `snowc` 命令: `build`, `run`, `test`<br>\* 本地缓存 `.snowpkg`与包版本语义 |
|
||||
|
||||
|
||||
## 5.1 里程碑排期
|
||||
|
||||
| 时间 | 目标 |
|
||||
|---------|----------------------------------------|
|
||||
| 2025-07 | 发布 **v0.2.0**:布尔类型 + 一元运算、20+ 单元测试 |
|
||||
| 2025-08 | 发布 **v0.3.0**:数组/切片 & 基础标准库;引入 CLI |
|
||||
| 2025-10 | 发布 **v0.4.0**:结构体支持、首批优化 Pass、>80% 覆盖率 |
|
||||
| 2026-11 | 发布 **v1.0.0**:异常系统、稳定包管理、文档完善 |
|
||||
| 2025-07 | 发布 **v0.2.0**: 布尔类型 + 一元运算、20+ 单元测试 |
|
||||
| 2025-08 | 发布 **v0.3.0**: 数组/切片 & 基础标准库;引入 CLI |
|
||||
| 2025-10 | 发布 **v0.4.0**: 结构体支持、首批优化 Pass、>80% 覆盖率 |
|
||||
| 2026-11 | 发布 **v1.0.0**: 异常系统、稳定包管理、文档完善 |
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
## 0 · 符号约定
|
||||
|
||||
* ⟦ … ⟧:可选项(0 或 1 次)
|
||||
* { … }\*:可重复项(0 次或多次)
|
||||
* ⟦ … ⟧: 可选项(0 或 1 次)
|
||||
* { … }\*: 可重复项(0 次或多次)
|
||||
|
||||
---
|
||||
|
||||
@ -19,12 +19,12 @@
|
||||
identifier ::= [A-Za-z_][A-Za-z0-9_]* ;
|
||||
```
|
||||
|
||||
* **区分大小写**:Foo 与 foo 为不同标识符。
|
||||
* **区分大小写**: Foo 与 foo 为不同标识符。
|
||||
* 保留字 (见 §1.3) **禁止** 用作标识符。
|
||||
|
||||
### 1.2 分隔符与强制空白
|
||||
|
||||
相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例:
|
||||
相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例:
|
||||
|
||||
```snow
|
||||
module: Foo // 推荐
|
||||
@ -44,22 +44,22 @@ end loop break continue self
|
||||
|
||||
### 1.4 文字量 (Literal)
|
||||
|
||||
* **整型**:123 0 -42
|
||||
* **浮点**:3.14 0.0
|
||||
* **布尔**:true false
|
||||
* **字符串**:未来版本保留;当前规范未定义。
|
||||
* **整型**: 123 0 -42
|
||||
* **浮点**: 3.14 0.0
|
||||
* **布尔**: true false
|
||||
* **字符串**: 未来版本保留;当前规范未定义。
|
||||
|
||||
### 1.5 注释
|
||||
|
||||
* **单行注释**:以 // 起,至当行行尾。
|
||||
* **多行注释**:/* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。
|
||||
* **单行注释**: 以 // 起,至当行行尾。
|
||||
* **多行注释**: /* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。
|
||||
|
||||
---
|
||||
|
||||
### 1.6 换行与缩进
|
||||
|
||||
* **只有换行有语义**:以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。
|
||||
* **缩进没有语义**:缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。
|
||||
* **只有换行有语义**: 以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。
|
||||
* **缩进没有语义**: 缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。
|
||||
* 块体通过显式关闭关键字(如 end module、end function 等)结束。
|
||||
* 若关闭关键字与开始关键字之间的缩进不一致,不会报错,仍以关闭关键字为准。
|
||||
|
||||
@ -82,7 +82,7 @@ end module
|
||||
* **允许** 不同文件夹下声明同名模块,但模块全名(含包路径,用点分隔)在全项目中必须唯一。
|
||||
* 若项目中出现重复的模块全名,编译阶段将报重定义错误。
|
||||
|
||||
例如:
|
||||
例如:
|
||||
> src/util/math.snow // module: util.math
|
||||
> src/core/math.snow // module: core.math
|
||||
>
|
||||
@ -95,15 +95,15 @@ import: <ModuleA>⟦ as <AliasA>⟧, <ModuleB>⟦ as <AliasB>⟧, …
|
||||
```
|
||||
|
||||
* **别名 (Alias)** 可为任何合法标识符,放在 as 关键字之后。
|
||||
* **重复导入**:对同一模块多次导入(无论是否带 alias)只解析一次,其余忽略告警。
|
||||
* **循环依赖**:当前规范未定义,若出现编译器可拒绝或延迟解析。
|
||||
* **重复导入**: 对同一模块多次导入(无论是否带 alias)只解析一次,其余忽略告警。
|
||||
* **循环依赖**: 当前规范未定义,若出现编译器可拒绝或延迟解析。
|
||||
* **子模块**(诸如 A.B)暂不支持。
|
||||
|
||||
### 2.3 全路径引用
|
||||
|
||||
* 跨模块引用必须使用 _Prefix_._Name_,其中 *Prefix* 是模块名或导入时的别名。
|
||||
例如:Math.Point 或 M.sin。
|
||||
* **解析顺序**:未加前缀的标识符只在本模块查找;找不到则视为编译错误,不会隐式搜索导入模块。
|
||||
例如: Math.Point 或 M.sin。
|
||||
* **解析顺序**: 未加前缀的标识符只在本模块查找;找不到则视为编译错误,不会隐式搜索导入模块。
|
||||
|
||||
---
|
||||
|
||||
@ -111,27 +111,27 @@ import: <ModuleA>⟦ as <AliasA>⟧, <ModuleB>⟦ as <AliasB>⟧, …
|
||||
|
||||
### 3.1 作用域层级
|
||||
|
||||
1. **模块顶层**:全局变量、结构体、模块级函数。
|
||||
2. **结构体内部**:字段、方法、构造函数。
|
||||
3. **函数/方法**:形参与局部变量。
|
||||
1. **模块顶层**: 全局变量、结构体、模块级函数。
|
||||
2. **结构体内部**: 字段、方法、构造函数。
|
||||
3. **函数/方法**: 形参与局部变量。
|
||||
4. **局部嵌套块** (if / loop 等) 的局部变量。
|
||||
|
||||
### 3.2 唯一性规则
|
||||
|
||||
* **模块顶层唯一**:同一模块的 *结构体名*、*模块级函数名*、*全局变量名* **不得重名**。
|
||||
* **结构体内部**:字段名与方法名不得相同;**允许有多个与结构体名同名的函数(即构造函数重载),但其参数签名必须互不相同。**
|
||||
* **构造函数重载**:结构体内部可以声明多个与结构体名同名的函数作为构造函数,参数类型与数量必须不同,否则属于 DuplicateName 错误。
|
||||
* **跨层级遮蔽**:内层可定义与外层同名标识符(除关键字限制外),遵循最近作用域原则。
|
||||
* **模块顶层唯一**: 同一模块的 *结构体名*、*模块级函数名*、*全局变量名* **不得重名**。
|
||||
* **结构体内部**: 字段名与方法名不得相同;**允许有多个与结构体名同名的函数(即构造函数重载),但其参数签名必须互不相同。**
|
||||
* **构造函数重载**: 结构体内部可以声明多个与结构体名同名的函数作为构造函数,参数类型与数量必须不同,否则属于 DuplicateName 错误。
|
||||
* **跨层级遮蔽**: 内层可定义与外层同名标识符(除关键字限制外),遵循最近作用域原则。
|
||||
|
||||
### 3.3 访问控制约定
|
||||
|
||||
* **私有成员与方法**:以单个下划线 `_` 开头的变量名、字段名或方法名,**仅在其所属结构体或模块内部可见**。外部不可访问,编译器应报错 `AccessDenied`。
|
||||
* **私有成员与方法**: 以单个下划线 `_` 开头的变量名、字段名或方法名,**仅在其所属结构体或模块内部可见**。外部不可访问,编译器应报错 `AccessDenied`。
|
||||
- 例如 `_foo`, `_barMethod`。
|
||||
* **公有成员与方法**:非下划线开头的变量、字段、方法,默认为公有。可在模块外部通过模块名/别名前缀访问。
|
||||
* **公有成员与方法**: 非下划线开头的变量、字段、方法,默认为公有。可在模块外部通过模块名/别名前缀访问。
|
||||
|
||||
#### 影响范围
|
||||
- **模块级变量与函数**:`globals` 和 `function` 语句声明的以 `_` 开头者,仅限本模块访问。
|
||||
- **结构体字段与方法**:声明为 `_name`、`_doSomething` 的,仅结构体本身或其方法体可访问。
|
||||
- **模块级变量与函数**: `globals` 和 `function` 语句声明的以 `_` 开头者,仅限本模块访问。
|
||||
- **结构体字段与方法**: 声明为 `_name`、`_doSomething` 的,仅结构体本身或其方法体可访问。
|
||||
---
|
||||
|
||||
#### 访问示例
|
||||
@ -220,7 +220,7 @@ struct: StructName
|
||||
end struct
|
||||
```
|
||||
|
||||
**实例化**:
|
||||
**实例化**:
|
||||
|
||||
* declare p: Point = Point(1, 2)
|
||||
* declare p2: Point = Point(3)
|
||||
@ -243,7 +243,7 @@ function: FuncName
|
||||
end function
|
||||
```
|
||||
|
||||
* **返回检查**:若 returns: 指定类型非 void,所有控制流路径必须显式 return 该类型值。
|
||||
* **返回检查**: 若 returns: 指定类型非 void,所有控制流路径必须显式 return 该类型值。
|
||||
* 在 loop 内或经 break 跳出后能到达的路径亦计入检查;若缺失,编译错误。
|
||||
|
||||
---
|
||||
@ -287,7 +287,7 @@ loop:
|
||||
end loop
|
||||
```
|
||||
|
||||
* **作用域**:init 块声明的变量仅在本 loop 的 init/cond/step/body 有效。
|
||||
* **作用域**: init 块声明的变量仅在本 loop 的 init/cond/step/body 有效。
|
||||
* break 立即终止当前循环;continue 跳过剩余 body,执行 step → cond。
|
||||
|
||||
---
|
||||
@ -296,7 +296,7 @@ end loop
|
||||
|
||||
### 6.1 数值类型
|
||||
|
||||
Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等:
|
||||
Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等:
|
||||
|
||||
| 类型名 | 关键字 | 位数 | 描述 |
|
||||
|----------|--------|----|---------------------------|
|
||||
@ -315,7 +315,7 @@ Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体
|
||||
|
||||
#### 数值字面量后缀
|
||||
|
||||
为指定具体类型,可在数值字面量后加后缀字母(大小写均可):
|
||||
为指定具体类型,可在数值字面量后加后缀字母(大小写均可):
|
||||
|
||||
| 后缀 | 类型 | 例子 |
|
||||
|----|--------|----------|
|
||||
@ -329,7 +329,7 @@ Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体
|
||||
- 没有后缀的整数字面量自动为 `int`。
|
||||
- 没有后缀的浮点字面量自动为 `double`。
|
||||
|
||||
**示例:**
|
||||
**示例: **
|
||||
```snow
|
||||
declare a: int = 7 // int (默认)
|
||||
declare b: long = 9l // long
|
||||
@ -405,17 +405,17 @@ declare a: Point = Point(1, 2)
|
||||
|
||||
## 7 · 名字解析算法(概览)
|
||||
|
||||
1. **输入**:未限定前缀的标识符 N,当前作用域 S。
|
||||
1. **输入**: 未限定前缀的标识符 N,当前作用域 S。
|
||||
2. 自内向外遍历作用域链查找 N;首次匹配即确定绑定。
|
||||
3. 若遍历至模块顶层仍未匹配,编译错误 *UnresolvedIdentifier*。
|
||||
4. 限定名 Prefix.N:直接在模块表中查 Prefix(包括别名),成功后在该模块顶层查找 N;找不到即 *UnresolvedQualifiedIdentifier*。
|
||||
4. 限定名 Prefix.N: 直接在模块表中查 Prefix(包括别名),成功后在该模块顶层查找 N;找不到即 *UnresolvedQualifiedIdentifier*。
|
||||
|
||||
---
|
||||
|
||||
## 8 · 编译单位与入口
|
||||
|
||||
* **单一入口**:编译器需指定某模块某函数作为启动入口。
|
||||
* **模块初始化**:globals 块中的带初值变量在程序启动时自顶向下按出现顺序初始化;不同模块按依赖拓扑顺序初始化(循环依赖未定义)。
|
||||
* **单一入口**: 编译器需指定某模块某函数作为启动入口。
|
||||
* **模块初始化**: globals 块中的带初值变量在程序启动时自顶向下按出现顺序初始化;不同模块按依赖拓扑顺序初始化(循环依赖未定义)。
|
||||
|
||||
---
|
||||
|
||||
@ -445,7 +445,7 @@ module: RectExample
|
||||
declare x: int
|
||||
declare y: int
|
||||
|
||||
// 构造函数1:两个参数
|
||||
// 构造函数1: 两个参数
|
||||
function: Point
|
||||
params:
|
||||
declare x: int
|
||||
@ -456,7 +456,7 @@ module: RectExample
|
||||
end body
|
||||
end function
|
||||
|
||||
// 构造函数2:一个参数
|
||||
// 构造函数2: 一个参数
|
||||
function: Point
|
||||
params:
|
||||
declare xy: int
|
||||
@ -553,7 +553,7 @@ end module
|
||||
|
||||
## 11 · 构造函数重载示例
|
||||
|
||||
**示例:**
|
||||
**示例: **
|
||||
|
||||
````snow
|
||||
struct: Point
|
||||
|
||||
@ -31,14 +31,14 @@ end module
|
||||
|
||||
### 数据类型
|
||||
|
||||
bool 类型:
|
||||
bool 类型:
|
||||
|
||||
两种值:`true` 和 `false`
|
||||
两种值: `true` 和 `false`
|
||||
|
||||
|
||||
|
||||
|
||||
数值类型:
|
||||
数值类型:
|
||||
|
||||
| Number | keyword |
|
||||
|----------|---------|
|
||||
@ -51,7 +51,7 @@ bool 类型:
|
||||
|
||||
默认整数的类型为 int,浮点数的类型为 double。
|
||||
|
||||
数值字面量后缀:
|
||||
数值字面量后缀:
|
||||
|
||||
| 数值字面量后缀 | 例子 |
|
||||
|---------|----|
|
||||
@ -64,7 +64,7 @@ bool 类型:
|
||||
|
||||
|
||||
### 变量
|
||||
定义变量的形式如下,中括号表示可选:
|
||||
定义变量的形式如下,中括号表示可选:
|
||||
|
||||
```snow
|
||||
declare name: type [= initial_value]
|
||||
@ -72,24 +72,24 @@ declare name: type [= initial_value]
|
||||
|
||||
其中 `name` 是变量名,`type` 是变量类型,`initial_value` 是初始值
|
||||
|
||||
例:
|
||||
例:
|
||||
|
||||
```snow
|
||||
declare x: int
|
||||
declare y: long = 123456789
|
||||
```
|
||||
|
||||
读取变量值的方法,直接写变量的名字即可:
|
||||
读取变量值的方法,直接写变量的名字即可:
|
||||
```snow
|
||||
x
|
||||
```
|
||||
|
||||
设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可:
|
||||
设置变量值的方法,先写变量名,后面接 `=`,最后写一个表达式即可:
|
||||
```snow
|
||||
x = 10
|
||||
```
|
||||
|
||||
于是可以通过这种方式让变量参与计算并保存结果:
|
||||
于是可以通过这种方式让变量参与计算并保存结果:
|
||||
```snow
|
||||
x = y + 1
|
||||
```
|
||||
@ -99,7 +99,7 @@ x = y + 1
|
||||
|
||||
## 流程控制
|
||||
### if
|
||||
if 语句的形式如下,else 是可选的:
|
||||
if 语句的形式如下,else 是可选的:
|
||||
|
||||
```snow
|
||||
if cond then
|
||||
@ -111,7 +111,7 @@ end if
|
||||
|
||||
cond 可以是表达式(结果为 bool 类型)或者 bool 字面量
|
||||
|
||||
例:
|
||||
例:
|
||||
|
||||
```snow
|
||||
module: Main
|
||||
@ -131,7 +131,7 @@ end module
|
||||
```
|
||||
|
||||
### loop
|
||||
loop 语句的形式如下:
|
||||
loop 语句的形式如下:
|
||||
```snow
|
||||
loop:
|
||||
init:
|
||||
@ -150,7 +150,7 @@ loop:
|
||||
end loop
|
||||
```
|
||||
|
||||
例子(求 1 ~ 100 的和):
|
||||
例子(求 1 ~ 100 的和):
|
||||
```snow
|
||||
module: Main
|
||||
function: main
|
||||
@ -176,7 +176,7 @@ end module
|
||||
```
|
||||
|
||||
## 函数
|
||||
函数的形式如下:
|
||||
函数的形式如下:
|
||||
```snow
|
||||
function: add
|
||||
parameter:
|
||||
@ -197,7 +197,7 @@ end function
|
||||
通过 import 语句导入模块,
|
||||
snow 会自动将同名模块的函数合并。
|
||||
|
||||
在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下:
|
||||
在我们最初的例子中,就用了 module 这个关键字。让我们回忆一下:
|
||||
|
||||
```snow
|
||||
module: Main
|
||||
@ -213,7 +213,7 @@ end module
|
||||
|
||||
可以看到模块名是 Main,里面有函数 main。
|
||||
|
||||
假如现在有一个模块 Math,代码如下:
|
||||
假如现在有一个模块 Math,代码如下:
|
||||
```snow
|
||||
// Math.snow
|
||||
module: Math
|
||||
@ -229,7 +229,7 @@ module: Math
|
||||
end module
|
||||
```
|
||||
|
||||
可以使用 import 来导入 Math 模块:
|
||||
可以使用 import 来导入 Math 模块:
|
||||
```snow
|
||||
// main.snow
|
||||
module: Main
|
||||
@ -244,7 +244,7 @@ module: Main
|
||||
end module
|
||||
```
|
||||
|
||||
可以同时导入多个模块,用逗号(半角)分隔模块名即可:
|
||||
可以同时导入多个模块,用逗号(半角)分隔模块名即可:
|
||||
```snow
|
||||
// main.snow
|
||||
module: Main
|
||||
|
||||
@ -1,17 +1,8 @@
|
||||
module: Main
|
||||
function: main
|
||||
return_type: int
|
||||
body:
|
||||
foo()
|
||||
|
||||
return 0
|
||||
end body
|
||||
end function
|
||||
|
||||
function: foo
|
||||
return_type: void
|
||||
body:
|
||||
|
||||
declare 1sum :int =1
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
8
pom.xml
8
pom.xml
@ -31,7 +31,7 @@
|
||||
|
||||
<plugins>
|
||||
<!--
|
||||
Java 编译插件:
|
||||
Java 编译插件:
|
||||
- 使用 Maven 自带的 maven-compiler-plugin 进行源码编译
|
||||
- <fork>true</fork> 表示在单独的进程中执行 javac,提高兼容性
|
||||
-->
|
||||
@ -45,7 +45,7 @@
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
Jar 打包插件:
|
||||
Jar 打包插件:
|
||||
- 使用 maven-jar-plugin 将编译产物打包成可执行 JAR
|
||||
- 在 MANIFEST 中指定主类,支持命令行直接 java -jar 调用
|
||||
-->
|
||||
@ -71,7 +71,7 @@
|
||||
|
||||
<profiles>
|
||||
<!--
|
||||
原生镜像构建:Linux 平台
|
||||
原生镜像构建: Linux 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成静态链接的可执行文件
|
||||
- 依赖 musl libc,需提前安装并配置 musl-gcc 工具链
|
||||
-->
|
||||
@ -133,7 +133,7 @@
|
||||
</profile>
|
||||
|
||||
<!--
|
||||
原生镜像构建:Windows 平台
|
||||
原生镜像构建: Windows 平台
|
||||
- 使用 GraalVM 的 native-image 工具,生成 Windows 可执行文件
|
||||
- Windows 上不使用 musl,因此不配置静态链接
|
||||
-->
|
||||
|
||||
@ -13,13 +13,13 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:构建当前项目(包含依赖解析、编译、打包)。
|
||||
* CLI 命令: 构建当前项目(包含依赖解析、编译、打包)。
|
||||
* <p>
|
||||
* 该命令会依次执行依赖解析、源码编译和产物打包阶段。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow build
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -6,13 +6,13 @@ import org.jcnc.snow.pkg.lifecycle.LifecyclePhase;
|
||||
import org.jcnc.snow.pkg.tasks.CleanTask;
|
||||
|
||||
/**
|
||||
* CLI 命令:清理构建输出和本地缓存目录。
|
||||
* CLI 命令: 清理构建输出和本地缓存目录。
|
||||
* <p>
|
||||
* 用于清除项目生成的 build、dist 等中间产物,保持工作区整洁。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow clean
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -13,17 +13,17 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* CLI 命令:编译当前项目。
|
||||
* CLI 命令: 编译当前项目。
|
||||
*
|
||||
* <p>工作模式说明:</p>
|
||||
* <p>工作模式说明: </p>
|
||||
* <ul>
|
||||
* <li><strong>Cloud 模式</strong>
|
||||
* - 项目根目录存在 {@code project.cloud} 时触发;
|
||||
* - 解析 build 区块,自动推导源码目录与输出文件名;
|
||||
* - 用法:{@code snow compile [run]}</li>
|
||||
* - 用法: {@code snow compile [run]}</li>
|
||||
* <li><strong>Local 模式</strong>
|
||||
* - 未检测到 {@code project.cloud} 时回退;
|
||||
* - 保持向后兼容:{@code snow compile [run] [-o <name>] [-d <srcDir>] [file.snow …]}</li>
|
||||
* - 保持向后兼容: {@code snow compile [run] [-o <name>] [-d <srcDir>] [file.snow …]}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>两种模式均将最终参数交由 {@link CompileTask} 处理。</p>
|
||||
@ -67,12 +67,12 @@ public final class CompileCommand implements CLICommand {
|
||||
}
|
||||
}
|
||||
|
||||
/* 源码目录:build.srcDir -> 默认 src */
|
||||
/* 源码目录: build.srcDir -> 默认 src */
|
||||
String srcDir = project.getBuild().get("srcDir", "src");
|
||||
argList.add("-d");
|
||||
argList.add(srcDir);
|
||||
|
||||
/* 输出名称:build.output -> fallback to artifact */
|
||||
/* 输出名称: build.output -> fallback to artifact */
|
||||
String output = project.getBuild().get("output", project.getArtifact());
|
||||
argList.add("-o");
|
||||
argList.add(output);
|
||||
|
||||
@ -12,19 +12,19 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:根据 project.cloud 生成项目目录结构。
|
||||
* CLI 命令: 根据 project.cloud 生成项目目录结构。
|
||||
* <p>
|
||||
* 负责解析云项目描述文件,并通过 {@link GenerateTask}
|
||||
* 在 INIT 生命周期阶段内生成基础目录结构。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow generate
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 注意事项:
|
||||
* 注意事项:
|
||||
* - 若当前目录不存在 project.cloud,则提示用户先执行 `snow init`。
|
||||
* - 执行成功后,会输出已创建的目录/文件。
|
||||
* </p>
|
||||
|
||||
@ -8,13 +8,13 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:初始化项目配置文件。
|
||||
* CLI 命令: 初始化项目配置文件。
|
||||
* <p>
|
||||
* 用于快速生成 DSL 配置文件(project.cloud)。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow init
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -8,13 +8,13 @@ import org.jcnc.snow.pkg.resolver.DependencyResolver;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:解析并下载项目依赖到本地缓存。
|
||||
* CLI 命令: 解析并下载项目依赖到本地缓存。
|
||||
* <p>
|
||||
* 适用于离线使用和依赖预热场景,会自动读取项目描述文件并处理依赖缓存。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow install
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -10,14 +10,14 @@ import org.jcnc.snow.pkg.tasks.PublishTask;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* CLI 命令:将已构建的项目包发布到远程仓库。
|
||||
* CLI 命令: 将已构建的项目包发布到远程仓库。
|
||||
* <p>
|
||||
* 用于持续集成、交付或分发场景。
|
||||
* 支持自动读取 DSL 项目描述文件,并注册和执行发布生命周期阶段的任务。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow publish
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -4,14 +4,14 @@ import org.jcnc.snow.cli.api.CLICommand;
|
||||
import org.jcnc.snow.pkg.tasks.RunTask;
|
||||
|
||||
/**
|
||||
* CLI 命令:运行已编译的 VM 字节码文件(.water)。
|
||||
* CLI 命令: 运行已编译的 VM 字节码文件(.water)。
|
||||
* <p>
|
||||
* 仅解析参数并委托给 {@link RunTask},
|
||||
* 将 VM 运行逻辑下沉至 pkg 层,保持 CLI 无状态、薄封装。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow run main.water
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -4,13 +4,13 @@ import org.jcnc.snow.cli.SnowCLI;
|
||||
import org.jcnc.snow.cli.api.CLICommand;
|
||||
|
||||
/**
|
||||
* CLI 子命令:输出当前 Snow 工具的版本号。
|
||||
* CLI 子命令: 输出当前 Snow 工具的版本号。
|
||||
* <p>
|
||||
* 用于显示当前 CLI 工具版本,便于诊断、升级、兼容性确认等场景。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* 用法示例:
|
||||
* 用法示例:
|
||||
* $ snow version
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@ -15,7 +15,7 @@ import java.util.Map;
|
||||
* 各虚拟寄存器实际对应的物理寄存器或栈槽号。采用简单的线性扫描分配策略。
|
||||
* </p>
|
||||
* <p>
|
||||
* 分配过程如下:
|
||||
* 分配过程如下:
|
||||
* <ol>
|
||||
* <li>优先为函数参数分配槽号,从 0 开始,按参数顺序递增。</li>
|
||||
* <li>遍历函数体的每条指令,为尚未分配的目标寄存器及其操作数分配新的槽号。</li>
|
||||
@ -28,8 +28,8 @@ public final class RegisterAllocator {
|
||||
/**
|
||||
* 虚拟寄存器到槽号的分配映射表。
|
||||
* <p>
|
||||
* 键:虚拟寄存器 {@link IRVirtualRegister};
|
||||
* 值:对应分配的槽编号 {@link Integer}。
|
||||
* 键: 虚拟寄存器 {@link IRVirtualRegister};
|
||||
* 值: 对应分配的槽编号 {@link Integer}。
|
||||
* </p>
|
||||
*/
|
||||
private final Map<IRVirtualRegister, Integer> map = new HashMap<>();
|
||||
@ -37,7 +37,7 @@ public final class RegisterAllocator {
|
||||
/**
|
||||
* 为指定 IR 函数分配所有虚拟寄存器的槽号。
|
||||
* <p>
|
||||
* 分配顺序说明:
|
||||
* 分配顺序说明:
|
||||
* <ol>
|
||||
* <li>首先为所有参数分配槽号。</li>
|
||||
* <li>然后线性遍历函数体,为每个指令涉及的虚拟寄存器(目标或操作数)分配槽号,
|
||||
|
||||
@ -16,7 +16,7 @@ import java.util.stream.Collectors;
|
||||
* 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。
|
||||
* </p>
|
||||
* <p>
|
||||
* 工作流程简述:
|
||||
* 工作流程简述:
|
||||
* <ol>
|
||||
* <li>接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。</li>
|
||||
* <li>遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。</li>
|
||||
@ -28,8 +28,8 @@ public final class VMCodeGenerator {
|
||||
/**
|
||||
* 指令类型到生成器的注册表(调度表)。
|
||||
* <p>
|
||||
* 键:IR 指令类型(Class对象),
|
||||
* 值:对应的指令生成器实例。
|
||||
* 键: IR 指令类型(Class对象),
|
||||
* 值: 对应的指令生成器实例。
|
||||
* </p>
|
||||
*/
|
||||
private final Map<Class<? extends IRInstruction>, InstructionGenerator<? extends IRInstruction>> registry;
|
||||
|
||||
@ -5,7 +5,7 @@ import org.jcnc.snow.vm.engine.VMOpCode;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* VMProgramBuilder:构建线性 VM 程序(即按顺序存放所有 VM 指令)。
|
||||
* VMProgramBuilder: 构建线性 VM 程序(即按顺序存放所有 VM 指令)。
|
||||
* <p>
|
||||
* 本类用于编译器后端,将所有生成的 VM 指令(包括分支和调用指令)统一存储、管理。
|
||||
* 支持符号(如函数入口、标签地址)的延迟解析与回填(fix-up)机制,
|
||||
@ -22,7 +22,7 @@ public final class VMProgramBuilder {
|
||||
/** 未解析目标的分支指令(JUMP/IC_* 等待修补) */
|
||||
private record BranchFix(int index, String label) {}
|
||||
|
||||
/** 占位符:用于表示尚未确定的符号地址 */
|
||||
/** 占位符: 用于表示尚未确定的符号地址 */
|
||||
private static final String PLACEHOLDER = "-1";
|
||||
|
||||
/** 按顺序存放的 VM 指令文本 */
|
||||
@ -102,7 +102,7 @@ public final class VMProgramBuilder {
|
||||
|
||||
/**
|
||||
* 生成 CALL 指令。
|
||||
* 支持延迟修补:若目标已知,直接写入地址;否则写入占位并登记 fix-up。
|
||||
* 支持延迟修补: 若目标已知,直接写入地址;否则写入占位并登记 fix-up。
|
||||
* @param target 目标函数名
|
||||
* @param nArgs 参数个数
|
||||
*/
|
||||
|
||||
@ -5,22 +5,22 @@
|
||||
## 项目简介
|
||||
|
||||
**后端模块(Backend)** 是 [Snow 编译器]() 的核心组成部分之一,承接中间表示(IR)与运行时虚拟机(VM)之间的桥梁。
|
||||
它主要完成以下工作:
|
||||
它主要完成以下工作:
|
||||
|
||||
1. **寄存器分配**:将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
|
||||
2. **指令生成与调度**:为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
|
||||
3. **程序构建**:管理函数入口、标签定义、延迟修补(fix-up)CALL/JUMP 等控制流指令地址;
|
||||
4. **操作码与常量映射**:提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
|
||||
1. **寄存器分配**: 将 IR 中的虚拟寄存器映射为物理槽号或栈槽;
|
||||
2. **指令生成与调度**: 为每条 IR 指令分配对应的 VM 指令生成器,并负责调用它们输出指令文本;
|
||||
3. **程序构建**: 管理函数入口、标签定义、延迟修补(fix-up)CALL/JUMP 等控制流指令地址;
|
||||
4. **操作码与常量映射**: 提供 IR 操作码到 VM 操作码的映射工具,以及根据常量类型选择 PUSH/STORE 指令。
|
||||
|
||||
后端模块设计注重可扩展性:各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
|
||||
后端模块设计注重可扩展性: 各类 IR → VM 的转换逻辑被拆分到不同的 `*Generator` 类中,新增指令只需注册新的生成器;寄存器分配和程序构建也各司其职,职责清晰,便于维护和测试。
|
||||
|
||||
## 核心功能
|
||||
|
||||
* **线性扫描寄存器分配**:`RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。
|
||||
* **指令生成器体系**:`InstructionGenerator<T>` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。
|
||||
* **生成器调度**:`VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。
|
||||
* **程序构建与延迟修补**:`VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。
|
||||
* **操作码与常量映射**:`IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量,并根据值类型(I/L/F…)选择合适的 PUSH/STORE 操作码。
|
||||
* **线性扫描寄存器分配**: `RegisterAllocator` 按参数优先、指令顺序为 IR 虚拟寄存器分配连续槽号。
|
||||
* **指令生成器体系**: `InstructionGenerator<T>` 接口 + 多个 `*Generator` 实现,支持二元运算、跳转、调用、标签、常量加载、一元运算、返回等指令。
|
||||
* **生成器调度**: `VMCodeGenerator` 建立类型到生成器的映射,遍历 IR 函数体并分发调用,实现多态化指令生成。
|
||||
* **程序构建与延迟修补**: `VMProgramBuilder` 维护指令流、符号地址表及待修补列表,实现对 `CALL`/`JUMP` 等指令的延迟地址填充。
|
||||
* **操作码与常量映射**: `IROpCodeMapper` 提供 IR 操作码到 VM 指令名的静态映射;`OpHelper` 基于反射获取 VMOpCode 常量,并根据值类型(I/L/F…)选择合适的 PUSH/STORE 操作码。
|
||||
|
||||
## 模块结构
|
||||
|
||||
@ -51,6 +51,6 @@ backend/
|
||||
|
||||
* JDK 24 或更高版本
|
||||
* Maven 构建管理
|
||||
* 推荐 IDE:IntelliJ IDEA
|
||||
* 推荐 IDE: IntelliJ IDEA
|
||||
|
||||
---
|
||||
|
||||
@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* 并自动进行类型提升。
|
||||
* 同时实现 "+0 → MOV" 的 Peephole 优化,避免多余的 PUSH/ADD 序列。
|
||||
* </p>
|
||||
* <p>类型提升优先级:D > F > L > I > S > B</p>
|
||||
* <p>类型提升优先级: D > F > L > I > S > B</p>
|
||||
*/
|
||||
public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationInstruction> {
|
||||
|
||||
@ -143,11 +143,11 @@ public class BinaryOpGenerator implements InstructionGenerator<BinaryOperationIn
|
||||
// ① 条件跳转;成立 → lblTrue
|
||||
out.emitBranch(branchOp, lblTrue);
|
||||
|
||||
// ② 不成立:压 0
|
||||
// ② 不成立: 压 0
|
||||
out.emit(OpHelper.opcode("I_PUSH") + " 0");
|
||||
out.emitBranch(OpHelper.opcode("JUMP"), lblEnd);
|
||||
|
||||
// ③ 成立分支:压 1
|
||||
// ③ 成立分支: 压 1
|
||||
out.emit(lblTrue + ":");
|
||||
out.emit(OpHelper.opcode("I_PUSH") + " 1");
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ public class CmpJumpGenerator implements InstructionGenerator<IRCompareJumpInstr
|
||||
* </ol>
|
||||
*
|
||||
* @param ins IR 条件比较跳转指令
|
||||
* @param out VMProgramBuilder:用于发出 VM 指令
|
||||
* @param out VMProgramBuilder: 用于发出 VM 指令
|
||||
* @param slotMap 虚拟寄存器到 VM 槽位的映射表
|
||||
* @param currentFn 当前处理的函数名(调试用,当前未使用)
|
||||
*/
|
||||
|
||||
@ -20,8 +20,8 @@ public final class IROpCodeMapper {
|
||||
/**
|
||||
* IR 操作码到 VM 指令名的静态映射表。
|
||||
* <ul>
|
||||
* <li>键:IR 操作码({@link IROpCode} 枚举项)</li>
|
||||
* <li>值:对应虚拟机指令名(字符串)</li>
|
||||
* <li>键: IR 操作码({@link IROpCode} 枚举项)</li>
|
||||
* <li>值: 对应虚拟机指令名(字符串)</li>
|
||||
* </ul>
|
||||
* 使用 {@link EnumMap},查找和存储高效。
|
||||
*/
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
package org.jcnc.snow.compiler.backend.utils;
|
||||
|
||||
/**
|
||||
* 工具类:提供基本数值类型的提升与类型转换辅助功能。
|
||||
* 工具类: 提供基本数值类型的提升与类型转换辅助功能。
|
||||
* <p>
|
||||
* 在进行数值类型运算、比较等操作时,低优先级的类型会被提升为高优先级类型参与运算。
|
||||
* 例如 int + long 运算,int 会被提升为 long,最终运算结果类型为 long。
|
||||
* <p>
|
||||
* 类型优先级从高到低依次为:
|
||||
* D(double):6
|
||||
* F(float) :5
|
||||
* L(long) :4
|
||||
* I(int) :3
|
||||
* S(short) :2
|
||||
* B(byte) :1
|
||||
* 未识别类型 :0
|
||||
* 类型优先级从高到低依次为:
|
||||
* D(double): 6
|
||||
* F(float) : 5
|
||||
* L(long) : 4
|
||||
* I(int) : 3
|
||||
* S(short) : 2
|
||||
* B(byte) : 1
|
||||
* 未识别类型 : 0
|
||||
*/
|
||||
public class TypePromoteUtils {
|
||||
|
||||
/**
|
||||
* 返回数值类型的宽度优先级,数值越大类型越宽。
|
||||
* 类型及优先级映射如下:
|
||||
* 类型及优先级映射如下:
|
||||
* D(double): 6
|
||||
* F(float) : 5
|
||||
* L(long) : 4
|
||||
@ -69,8 +69,8 @@ public class TypePromoteUtils {
|
||||
* 获取类型转换指令名(例如 "I2L", "F2D"),表示从源类型到目标类型的转换操作。
|
||||
* 如果源类型和目标类型相同,则返回 null,表示无需转换。
|
||||
* <p>
|
||||
* 支持的类型标记字符包括:B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
|
||||
* 所有可能的类型转换均已覆盖,如下所示:
|
||||
* 支持的类型标记字符包括: B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
|
||||
* 所有可能的类型转换均已覆盖,如下所示:
|
||||
* B → S/I/L/F/D
|
||||
* S → B/I/L/F/D
|
||||
* I → B/S/L/F/D
|
||||
|
||||
@ -19,7 +19,7 @@ import java.util.*;
|
||||
* 该类负责将抽象语法树(AST)的表达式节点转换为中间表示(IR)指令和虚拟寄存器,
|
||||
* 是编译器IR生成阶段的核心工具。
|
||||
* <br/>
|
||||
* 主要职责包括:
|
||||
* 主要职责包括:
|
||||
* <ul>
|
||||
* <li>将数字字面量、标识符、二元表达式、函数调用等AST表达式节点,翻译为对应的IR指令序列</li>
|
||||
* <li>管理并分配虚拟寄存器,保证IR操作的数据流正确</li>
|
||||
@ -31,19 +31,19 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
/**
|
||||
* 构建并返回某个表达式节点对应的虚拟寄存器。
|
||||
*
|
||||
* <p>会根据节点的实际类型分别处理:
|
||||
* <p>会根据节点的实际类型分别处理:
|
||||
* <ul>
|
||||
* <li>数字字面量:新建常量寄存器</li>
|
||||
* <li>布尔字面量:生成值为 0 或 1 的常量寄存器</li>
|
||||
* <li>标识符:查找当前作用域中的寄存器</li>
|
||||
* <li>二元表达式:递归处理子表达式并进行相应运算</li>
|
||||
* <li>一元运算符:
|
||||
* <li>数字字面量: 新建常量寄存器</li>
|
||||
* <li>布尔字面量: 生成值为 0 或 1 的常量寄存器</li>
|
||||
* <li>标识符: 查找当前作用域中的寄存器</li>
|
||||
* <li>二元表达式: 递归处理子表达式并进行相应运算</li>
|
||||
* <li>一元运算符:
|
||||
* <ul>
|
||||
* <li><code>-x</code>(取负,生成 <code>NEG_I32</code> 指令)与</li>
|
||||
* <li>code>!x</code>(逻辑非,转换为 <code>x == 0</code> 比较指令)</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>函数调用:生成对应的Call指令</li>
|
||||
* <li>函数调用: 生成对应的Call指令</li>
|
||||
* <li>其它类型不支持,抛出异常</li>
|
||||
* </ul>
|
||||
*
|
||||
|
||||
@ -19,7 +19,7 @@ public class FunctionBuilder {
|
||||
/**
|
||||
* 将 AST 中的 FunctionNode 构建为可执行的 IRFunction。
|
||||
* <p>
|
||||
* 构建过程包括:
|
||||
* 构建过程包括:
|
||||
* <ol>
|
||||
* <li>初始化 IRFunction 实例和上下文</li>
|
||||
* <li>根据函数返回类型,设置默认类型后缀,便于表达式推断</li>
|
||||
@ -37,7 +37,7 @@ public class FunctionBuilder {
|
||||
GlobalFunctionTable.register(functionNode.name(), functionNode.returnType());
|
||||
|
||||
|
||||
// 0) 基本初始化:创建 IRFunction 实例与对应上下文
|
||||
// 0) 基本初始化: 创建 IRFunction 实例与对应上下文
|
||||
IRFunction irFunction = new IRFunction(functionNode.name());
|
||||
IRContext irContext = new IRContext(irFunction);
|
||||
|
||||
@ -53,14 +53,14 @@ public class FunctionBuilder {
|
||||
ExpressionUtils.setDefaultSuffix(_returnSuffix);
|
||||
|
||||
try {
|
||||
// 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域
|
||||
// 2) 声明形参: 为每个参数分配虚拟寄存器并声明到作用域
|
||||
for (ParameterNode p : functionNode.parameters()) {
|
||||
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
|
||||
irContext.getScope().declare(p.name(), p.type(), reg); // 变量名→寄存器绑定
|
||||
irFunction.addParameter(reg); // 添加到函数参数列表
|
||||
}
|
||||
|
||||
// 3) 生成函数体 IR:遍历每条语句,逐一转化
|
||||
// 3) 生成函数体 IR: 遍历每条语句,逐一转化
|
||||
StatementBuilder stmtBuilder = new StatementBuilder(irContext);
|
||||
for (StatementNode stmt : functionNode.body()) {
|
||||
stmtBuilder.build(stmt);
|
||||
|
||||
@ -9,7 +9,7 @@ import java.util.Map;
|
||||
/**
|
||||
* IRBuilderScope 用于管理单个函数内变量名与虚拟寄存器的映射关系。
|
||||
*
|
||||
* <p>主要功能包括:
|
||||
* <p>主要功能包括:
|
||||
* <ul>
|
||||
* <li>维护在当前作用域中已声明变量的寄存器分配信息;</li>
|
||||
* <li>支持将已有虚拟寄存器与变量名重新绑定;</li>
|
||||
|
||||
@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
* 以及与之配套的作用域管理(IRBuilderScope),
|
||||
* 并简化虚拟寄存器分配与 IR 指令添加操作。
|
||||
*
|
||||
* <p>本类提供以下核心功能:
|
||||
* <p>本类提供以下核心功能:
|
||||
* <ul>
|
||||
* <li>持有并操作当前 IRFunction 对象;</li>
|
||||
* <li>管理变量名与虚拟寄存器的映射关系;</li>
|
||||
@ -62,7 +62,7 @@ public class IRContext {
|
||||
/**
|
||||
* 获取当前函数的变量与寄存器映射作用域。
|
||||
*
|
||||
* <p>包内可见:仅限 builder 包内部使用。
|
||||
* <p>包内可见: 仅限 builder 包内部使用。
|
||||
*
|
||||
* @return IRBuilderScope 实例
|
||||
*/
|
||||
|
||||
@ -13,7 +13,7 @@ import java.util.List;
|
||||
/**
|
||||
* 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram。
|
||||
*
|
||||
* <p>主要职责:
|
||||
* <p>主要职责:
|
||||
* <ul>
|
||||
* <li>遍历输入的顶层节点,识别 ModuleNode、FunctionNode 及脚本式顶层 StatementNode;</li>
|
||||
* <li>对 ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram;</li>
|
||||
@ -36,13 +36,13 @@ public final class IRProgramBuilder {
|
||||
for (Node node : roots) {
|
||||
switch (node) {
|
||||
case ModuleNode moduleNode ->
|
||||
// 模块节点:批量构建并添加模块内所有函数
|
||||
// 模块节点: 批量构建并添加模块内所有函数
|
||||
moduleNode.functions().forEach(f -> irProgram.add(buildFunction(f)));
|
||||
case FunctionNode functionNode ->
|
||||
// 顶层函数节点:直接构建并添加
|
||||
// 顶层函数节点: 直接构建并添加
|
||||
irProgram.add(buildFunction(functionNode));
|
||||
case StatementNode statementNode ->
|
||||
// 脚本式顶层语句:封装为“_start”函数后构建并添加
|
||||
// 脚本式顶层语句: 封装为“_start”函数后构建并添加
|
||||
irProgram.add(buildFunction(wrapTopLevel(statementNode)));
|
||||
default ->
|
||||
// 严格校验节点类型,遇不支持者立即失败
|
||||
@ -65,7 +65,7 @@ public final class IRProgramBuilder {
|
||||
/**
|
||||
* 将单个脚本式顶层 StatementNode 封装为名称固定的“_start”函数节点。
|
||||
*
|
||||
* <p>封装规则:
|
||||
* <p>封装规则:
|
||||
* <ul>
|
||||
* <li>函数名固定为“_start”;</li>
|
||||
* <li>返回类型设为 null,由后续流程处理;</li>
|
||||
|
||||
@ -80,7 +80,7 @@ public class InstructionFactory {
|
||||
/**
|
||||
* Move 指令(src → dest)。若寄存器相同也安全。
|
||||
* <p>
|
||||
* 实现方式:dest = src + 0(即加上常量 0)。
|
||||
* 实现方式: dest = src + 0(即加上常量 0)。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 当前 IR 上下文
|
||||
@ -92,7 +92,7 @@ public class InstructionFactory {
|
||||
if (src == dest) {
|
||||
return;
|
||||
}
|
||||
// 回退实现:dest = src + 0
|
||||
// 回退实现: dest = src + 0
|
||||
IRVirtualRegister zero = loadConst(ctx, 0);
|
||||
ctx.addInstruction(new BinaryOperationInstruction(IROpCode.ADD_I32, dest, src, zero));
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ public class StatementBuilder {
|
||||
|
||||
/**
|
||||
* 构建循环语句(for/while)。
|
||||
* 处理流程:初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
||||
* 处理流程: 初始语句 → 条件判断 → 循环体 → 更新语句 → 跳回条件。
|
||||
*
|
||||
* @param loop 循环节点
|
||||
*/
|
||||
@ -176,7 +176,7 @@ public class StatementBuilder {
|
||||
|
||||
/**
|
||||
* 构建分支语句(if/else)。
|
||||
* 处理流程:条件判断 → then 分支 → else 分支(可选)。
|
||||
* 处理流程: 条件判断 → then 分支 → else 分支(可选)。
|
||||
*
|
||||
* @param ifNode if 语句节点
|
||||
*/
|
||||
|
||||
@ -22,8 +22,8 @@ public final class GlobalFunctionTable {
|
||||
/**
|
||||
* 存储全局函数返回类型映射表。
|
||||
* <ul>
|
||||
* <li>Key:函数名(不含模块限定)</li>
|
||||
* <li>Value:返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}</li>
|
||||
* <li>Key: 函数名(不含模块限定)</li>
|
||||
* <li>Value: 返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}</li>
|
||||
* </ul>
|
||||
*/
|
||||
private static final Map<String, String> RETURN_TYPES = new ConcurrentHashMap<>();
|
||||
|
||||
@ -112,7 +112,7 @@ public class IRFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 以IR代码表示,示例:
|
||||
* 以IR代码表示,示例:
|
||||
* <pre>
|
||||
* func 名称(%0, %1, ...) {
|
||||
* 指令0
|
||||
|
||||
@ -24,95 +24,95 @@ public enum IROpCode {
|
||||
CONV_D64_TO_F32,
|
||||
|
||||
|
||||
/* ───── 算术运算(8位整数:byte)───── */
|
||||
ADD_B8, // 8位整型加法:a = b + c
|
||||
SUB_B8, // 8位整型减法:a = b - c
|
||||
MUL_B8, // 8位整型乘法:a = b * c
|
||||
DIV_B8, // 8位整型除法:a = b / c
|
||||
NEG_B8, // 8位整型取负:a = -b
|
||||
/* ───── 算术运算(8位整数: byte)───── */
|
||||
ADD_B8, // 8位整型加法: a = b + c
|
||||
SUB_B8, // 8位整型减法: a = b - c
|
||||
MUL_B8, // 8位整型乘法: a = b * c
|
||||
DIV_B8, // 8位整型除法: a = b / c
|
||||
NEG_B8, // 8位整型取负: a = -b
|
||||
|
||||
/* ───── 算术运算(16位整数:short)───── */
|
||||
/* ───── 算术运算(16位整数: short)───── */
|
||||
ADD_S16, // 16位整型加法
|
||||
SUB_S16, // 16位整型减法
|
||||
MUL_S16, // 16位整型乘法
|
||||
DIV_S16, // 16位整型除法
|
||||
NEG_S16, // 16位整型取负
|
||||
|
||||
/* ───── 算术运算(32位整数:int)───── */
|
||||
/* ───── 算术运算(32位整数: int)───── */
|
||||
ADD_I32, // 32位整型加法
|
||||
SUB_I32, // 32位整型减法
|
||||
MUL_I32, // 32位整型乘法
|
||||
DIV_I32, // 32位整型除法
|
||||
NEG_I32, // 32位整型取负
|
||||
|
||||
/* ───── 算术运算(64位整数:long)───── */
|
||||
/* ───── 算术运算(64位整数: long)───── */
|
||||
ADD_L64, // 64位整型加法
|
||||
SUB_L64, // 64位整型减法
|
||||
MUL_L64, // 64位整型乘法
|
||||
DIV_L64, // 64位整型除法
|
||||
NEG_L64, // 64位整型取负
|
||||
|
||||
/* ───── 算术运算(32位浮点数:float)───── */
|
||||
/* ───── 算术运算(32位浮点数: float)───── */
|
||||
ADD_F32, // 32位浮点加法
|
||||
SUB_F32, // 32位浮点减法
|
||||
MUL_F32, // 32位浮点乘法
|
||||
DIV_F32, // 32位浮点除法
|
||||
NEG_F32, // 32位浮点取负
|
||||
|
||||
/* ───── 算术运算(64位浮点数:double)───── */
|
||||
/* ───── 算术运算(64位浮点数: double)───── */
|
||||
ADD_D64, // 64位浮点加法
|
||||
SUB_D64, // 64位浮点减法
|
||||
MUL_D64, // 64位浮点乘法
|
||||
DIV_D64, // 64位浮点除法
|
||||
NEG_D64, // 64位浮点取负
|
||||
|
||||
/* ───── 逻辑与比较运算指令(8位整数:byte) ───── */
|
||||
CMP_BEQ, // 8位整数相等比较:a == b
|
||||
CMP_BNE, // 8位整数不等比较:a != b
|
||||
CMP_BLT, // 8位整数小于比较:a < b
|
||||
CMP_BGT, // 8位整数大于比较:a > b
|
||||
CMP_BLE, // 8位整数小于等于:a <= b
|
||||
CMP_BGE, // 8位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(8位整数: byte) ───── */
|
||||
CMP_BEQ, // 8位整数相等比较: a == b
|
||||
CMP_BNE, // 8位整数不等比较: a != b
|
||||
CMP_BLT, // 8位整数小于比较: a < b
|
||||
CMP_BGT, // 8位整数大于比较: a > b
|
||||
CMP_BLE, // 8位整数小于等于: a <= b
|
||||
CMP_BGE, // 8位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(16位整数:int) ───── */
|
||||
CMP_SEQ, // 16位整数相等比较:a == b
|
||||
CMP_SNE, // 16位整数不等比较:a != b
|
||||
CMP_SLT, // 16位整数小于比较:a < b
|
||||
CMP_SGT, // 16位整数大于比较:a > b
|
||||
CMP_SLE, // 16位整数小于等于:a <= b
|
||||
CMP_SGE, // 16位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(16位整数: int) ───── */
|
||||
CMP_SEQ, // 16位整数相等比较: a == b
|
||||
CMP_SNE, // 16位整数不等比较: a != b
|
||||
CMP_SLT, // 16位整数小于比较: a < b
|
||||
CMP_SGT, // 16位整数大于比较: a > b
|
||||
CMP_SLE, // 16位整数小于等于: a <= b
|
||||
CMP_SGE, // 16位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(32位整数:int) ───── */
|
||||
CMP_IEQ, // 32位整数相等比较:a == b
|
||||
CMP_INE, // 32位整数不等比较:a != b
|
||||
CMP_ILT, // 32位整数小于比较:a < b
|
||||
CMP_IGT, // 32位整数大于比较:a > b
|
||||
CMP_ILE, // 32位整数小于等于:a <= b
|
||||
CMP_IGE, // 32位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(32位整数: int) ───── */
|
||||
CMP_IEQ, // 32位整数相等比较: a == b
|
||||
CMP_INE, // 32位整数不等比较: a != b
|
||||
CMP_ILT, // 32位整数小于比较: a < b
|
||||
CMP_IGT, // 32位整数大于比较: a > b
|
||||
CMP_ILE, // 32位整数小于等于: a <= b
|
||||
CMP_IGE, // 32位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(64位整数:long) ───── */
|
||||
CMP_LEQ, // 64位整数相等比较:a == b
|
||||
CMP_LNE, // 64位整数不等比较:a != b
|
||||
CMP_LLT, // 64位整数小于比较:a < b
|
||||
CMP_LGT, // 64位整数大于比较:a > b
|
||||
CMP_LLE, // 64位整数小于等于:a <= b
|
||||
CMP_LGE, // 64位整数大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(64位整数: long) ───── */
|
||||
CMP_LEQ, // 64位整数相等比较: a == b
|
||||
CMP_LNE, // 64位整数不等比较: a != b
|
||||
CMP_LLT, // 64位整数小于比较: a < b
|
||||
CMP_LGT, // 64位整数大于比较: a > b
|
||||
CMP_LLE, // 64位整数小于等于: a <= b
|
||||
CMP_LGE, // 64位整数大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(32位浮点数:float) ───── */
|
||||
CMP_FEQ, // 32位浮点相等比较:a == b
|
||||
CMP_FNE, // 32位浮点不等比较:a != b
|
||||
CMP_FLT, // 32位浮点小于比较:a < b
|
||||
CMP_FGT, // 32位浮点大于比较:a > b
|
||||
CMP_FLE, // 32位浮点小于等于:a <= b
|
||||
CMP_FGE, // 32位浮点大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(32位浮点数: float) ───── */
|
||||
CMP_FEQ, // 32位浮点相等比较: a == b
|
||||
CMP_FNE, // 32位浮点不等比较: a != b
|
||||
CMP_FLT, // 32位浮点小于比较: a < b
|
||||
CMP_FGT, // 32位浮点大于比较: a > b
|
||||
CMP_FLE, // 32位浮点小于等于: a <= b
|
||||
CMP_FGE, // 32位浮点大于等于: a >= b
|
||||
|
||||
/* ───── 逻辑与比较运算指令(64位浮点数:double) ───── */
|
||||
CMP_DEQ, // 64位浮点相等比较:a == b
|
||||
CMP_DNE, // 64位浮点不等比较:a != b
|
||||
CMP_DLT, // 64位浮点小于比较:a < b
|
||||
CMP_DGT, // 64位浮点大于比较:a > b
|
||||
CMP_DLE, // 64位浮点小于等于:a <= b
|
||||
CMP_DGE, // 64位浮点大于等于:a >= b
|
||||
/* ───── 逻辑与比较运算指令(64位浮点数: double) ───── */
|
||||
CMP_DEQ, // 64位浮点相等比较: a == b
|
||||
CMP_DNE, // 64位浮点不等比较: a != b
|
||||
CMP_DLT, // 64位浮点小于比较: a < b
|
||||
CMP_DGT, // 64位浮点大于比较: a > b
|
||||
CMP_DLE, // 64位浮点小于等于: a <= b
|
||||
CMP_DGE, // 64位浮点大于等于: a >= b
|
||||
|
||||
/* ───── 数据访问与常量操作 ───── */
|
||||
LOAD, // 从内存加载数据至寄存器
|
||||
|
||||
@ -11,11 +11,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
* 实现该接口的类型可以作为 {@link IRInstruction} 中的操作数出现。
|
||||
* </p>
|
||||
*
|
||||
* <p>当前支持的 IR 值类型包括:</p>
|
||||
* <p>当前支持的 IR 值类型包括: </p>
|
||||
* <ul>
|
||||
* <li>{@link IRVirtualRegister}:虚拟寄存器,表示计算结果或中间变量</li>
|
||||
* <li>{@link IRConstant}:常量值,表示不可变的字面量或数值</li>
|
||||
* <li>{@link IRLabel}:标签,表示跳转指令的目标地址</li>
|
||||
* <li>{@link IRVirtualRegister}: 虚拟寄存器,表示计算结果或中间变量</li>
|
||||
* <li>{@link IRConstant}: 常量值,表示不可变的字面量或数值</li>
|
||||
* <li>{@link IRLabel}: 标签,表示跳转指令的目标地址</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
|
||||
@ -7,12 +7,12 @@ import org.jcnc.snow.compiler.ir.instruction.*;
|
||||
* <p>
|
||||
* 它定义了访问者模式的核心机制,通过对每种 {@link IRInstruction} 子类
|
||||
* 提供独立的 {@code visit} 方法,实现对指令的分发与处理。
|
||||
* 不同的访问者实现可用于执行不同任务,例如:
|
||||
* 不同的访问者实现可用于执行不同任务,例如:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@code IRPrinter}:打印指令内容</li>
|
||||
* <li>{@code IROptimizer}:分析与重写 IR 以优化性能</li>
|
||||
* <li>{@code IRCodeGenerator}:生成平台相关的机器码或汇编代码</li>
|
||||
* <li>{@code IRPrinter}: 打印指令内容</li>
|
||||
* <li>{@code IROptimizer}: 分析与重写 IR 以优化性能</li>
|
||||
* <li>{@code IRCodeGenerator}: 生成平台相关的机器码或汇编代码</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
|
||||
@ -11,27 +11,27 @@ IR 模块以类 SSA(Static Single Assignment)形式设计,通过统一的
|
||||
|
||||
## 核心功能
|
||||
|
||||
* **统一的中间表示模型**:表达控制流与数据流,支持函数、指令、值等核心结构
|
||||
* **IR 构建器体系**:模块化构建函数、表达式与语句 IR,简化前端对接
|
||||
* **灵活的指令层级结构**:支持二元操作、跳转、返回等多种基本指令
|
||||
* **寄存器与常量模型**:统一管理虚拟寄存器、常量、标签等值类型
|
||||
* **IR 打印与调试支持**:辅助输出 IR 文本格式,支持可视化与调试
|
||||
* **统一的中间表示模型**: 表达控制流与数据流,支持函数、指令、值等核心结构
|
||||
* **IR 构建器体系**: 模块化构建函数、表达式与语句 IR,简化前端对接
|
||||
* **灵活的指令层级结构**: 支持二元操作、跳转、返回等多种基本指令
|
||||
* **寄存器与常量模型**: 统一管理虚拟寄存器、常量、标签等值类型
|
||||
* **IR 打印与调试支持**: 辅助输出 IR 文本格式,支持可视化与调试
|
||||
|
||||
## 模块结构
|
||||
|
||||
```
|
||||
ir/
|
||||
├── builder/ // 构建器模块:负责构造表达式、函数与语句的 IR
|
||||
├── core/ // 核心定义:IR 基础结构,如函数、指令、程序、访问器等
|
||||
├── instruction/ // 指令实现:具体的 IR 指令类型(如加法、跳转、返回等)
|
||||
├── utils/ // 工具模块:提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等)
|
||||
└── value/ // 值模型:常量、标签、虚拟寄存器等
|
||||
├── builder/ // 构建器模块: 负责构造表达式、函数与语句的 IR
|
||||
├── core/ // 核心定义: IR 基础结构,如函数、指令、程序、访问器等
|
||||
├── instruction/ // 指令实现: 具体的 IR 指令类型(如加法、跳转、返回等)
|
||||
├── utils/ // 工具模块: 提供 IR 操作相关的辅助函数(如表达式工具、操作码工具等)
|
||||
└── value/ // 值模型: 常量、标签、虚拟寄存器等
|
||||
```
|
||||
|
||||
## 开发环境
|
||||
|
||||
* JDK 24 或更高版本
|
||||
* Maven 构建管理
|
||||
* 推荐 IDE:IntelliJ IDEA
|
||||
* 推荐 IDE: IntelliJ IDEA
|
||||
|
||||
---
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BinaryOperationInstruction —— 表示一个二元运算指令,格式为:dest = lhs OP rhs
|
||||
* BinaryOperationInstruction —— 表示一个二元运算指令,格式为: dest = lhs OP rhs
|
||||
* <p>
|
||||
* 该类用于描述形如 a = b + c 或 a = x * y 的二元运算指令。
|
||||
* 运算类型(OP)由 {@link IROpCode} 指定,包括加法、减法、乘法、除法等。
|
||||
@ -76,7 +76,7 @@ public final class BinaryOperationInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 转换为字符串格式,便于调试与打印。
|
||||
* 例:v1 = ADD_I32 v2, v3
|
||||
* 例: v1 = ADD_I32 v2, v3
|
||||
*
|
||||
* @return 指令的字符串表示形式
|
||||
*/
|
||||
|
||||
@ -46,7 +46,7 @@ public class CallInstruction extends IRInstruction {
|
||||
return isVoidReturn() ? null : dest;
|
||||
}
|
||||
|
||||
/** 操作数列表:void 调用不包含 dest */
|
||||
/** 操作数列表: void 调用不包含 dest */
|
||||
@Override
|
||||
public List<IRValue> operands() {
|
||||
List<IRValue> ops = new ArrayList<>();
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IRAddInstruction —— 表示一个加法指令,形如:dest = lhs + rhs
|
||||
* IRAddInstruction —— 表示一个加法指令,形如: dest = lhs + rhs
|
||||
* <p>
|
||||
* 本类是一个具体的 IRInstruction 子类,表示将两个值相加,并将结果写入目标寄存器的操作。
|
||||
* 虽然功能与通用的 {@link BinaryOperationInstruction} 类似,但它作为更简化明确的指令实现,
|
||||
@ -40,7 +40,7 @@ public class IRAddInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回该指令的操作码:ADD_I32。
|
||||
* 返回该指令的操作码: ADD_I32。
|
||||
*
|
||||
* @return 加法操作码
|
||||
*/
|
||||
@ -81,7 +81,7 @@ public class IRAddInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 返回指令的字符串形式,方便调试。
|
||||
* 例如:v1 = v2 + v3
|
||||
* 例如: v1 = v2 + v3
|
||||
*
|
||||
* @return 字符串表示形式
|
||||
*/
|
||||
|
||||
@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.ir.core.IRVisitor;
|
||||
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
|
||||
/**
|
||||
* “比较 + 条件跳转” 复合指令:
|
||||
* “比较 + 条件跳转” 复合指令:
|
||||
* if ( left <cmpOp> right ) jump targetLabel;
|
||||
* <p>
|
||||
* 其中 cmpOp 只能是 IROpCode.CMP_* 六种比较操作码。
|
||||
|
||||
@ -25,7 +25,7 @@ public class IRJumpInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该指令对应的操作码:JUMP。
|
||||
* 获取该指令对应的操作码: JUMP。
|
||||
*
|
||||
* @return IROpCode.JUMP
|
||||
*/
|
||||
@ -55,7 +55,7 @@ public class IRJumpInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 将指令转为字符串形式,便于打印与调试。
|
||||
* 例如:jump L1
|
||||
* 例如: jump L1
|
||||
*
|
||||
* @return 指令的字符串表示
|
||||
*/
|
||||
|
||||
@ -29,7 +29,7 @@ public class IRReturnInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该指令的操作码:RET。
|
||||
* 获取该指令的操作码: RET。
|
||||
*
|
||||
* @return IROpCode.RET,表示返回操作
|
||||
*/
|
||||
@ -60,7 +60,7 @@ public class IRReturnInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 转换为字符串形式,便于调试与打印。
|
||||
* 示例:ret v1
|
||||
* 示例: ret v1
|
||||
*
|
||||
* @return 字符串形式的返回指令
|
||||
*/
|
||||
|
||||
@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LoadConstInstruction —— 表示一个常量加载指令,格式为:dest = CONST k
|
||||
* LoadConstInstruction —— 表示一个常量加载指令,格式为: dest = CONST k
|
||||
* <p>
|
||||
* 该指令的功能是将一个常量(字面量或编译期已知值)加载到一个虚拟寄存器中,
|
||||
* 供后续指令使用。例如,在表达式计算、参数传递、初始化等场景中常用。
|
||||
@ -66,7 +66,7 @@ public final class LoadConstInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 返回该指令的字符串形式,便于调试或打印。
|
||||
* 例如:v1 = CONST 42
|
||||
* 例如: v1 = CONST 42
|
||||
*
|
||||
* @return 指令的字符串表示
|
||||
*/
|
||||
|
||||
@ -9,11 +9,11 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ReturnInstruction —— 表示函数返回指令,格式:RET 或 RET <value>
|
||||
* ReturnInstruction —— 表示函数返回指令,格式: RET 或 RET <value>
|
||||
* <p>
|
||||
* 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
|
||||
* - 无返回值(void):生成无参的 RET 指令
|
||||
* - 有返回值:将指定虚拟寄存器中的值返回给调用者
|
||||
* 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
|
||||
* - 无返回值(void): 生成无参的 RET 指令
|
||||
* - 有返回值: 将指定虚拟寄存器中的值返回给调用者
|
||||
* <p>
|
||||
* 与 {@link IRReturnInstruction} 类似,但更通用,适配多种函数返回风格。
|
||||
*/
|
||||
@ -36,7 +36,7 @@ public final class ReturnInstruction extends IRInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回该指令的操作码类型:RET。
|
||||
* 返回该指令的操作码类型: RET。
|
||||
*
|
||||
* @return IROpCode.RET
|
||||
*/
|
||||
@ -68,8 +68,8 @@ public final class ReturnInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 转换为字符串形式,便于调试与输出。
|
||||
* - 无返回值:RET
|
||||
* - 有返回值:RET v1
|
||||
* - 无返回值: RET
|
||||
* - 有返回值: RET v1
|
||||
*
|
||||
* @return 字符串表示的返回指令
|
||||
*/
|
||||
|
||||
@ -9,14 +9,14 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* UnaryOperationInstruction —— 表示一个一元运算指令,格式:dest = OP val
|
||||
* UnaryOperationInstruction —— 表示一个一元运算指令,格式: dest = OP val
|
||||
* <p>
|
||||
* 用于对单个操作数 val 执行指定的一元运算 OP(例如取负 NEG),
|
||||
* 并将结果写入目标虚拟寄存器 dest。
|
||||
* <p>
|
||||
* 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
|
||||
* 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
|
||||
* <ul>
|
||||
* <li>NEG_I32 —— 整数取负:dest = -val</li>
|
||||
* <li>NEG_I32 —— 整数取负: dest = -val</li>
|
||||
* <li>(可扩展)逻辑非、按位非等</li>
|
||||
* </ul>
|
||||
*/
|
||||
@ -76,7 +76,7 @@ public final class UnaryOperationInstruction extends IRInstruction {
|
||||
|
||||
/**
|
||||
* 将该指令格式化为字符串,便于打印与调试。
|
||||
* 形式:dest = OP val,例如:v1 = NEG v2
|
||||
* 形式: dest = OP val,例如: v1 = NEG v2
|
||||
*
|
||||
* @return 字符串形式的指令
|
||||
*/
|
||||
|
||||
@ -16,11 +16,11 @@ import java.util.Map;
|
||||
* 支持自动类型提升,保证 int、long、float、double 等类型的比较均能得到正确的 IR 指令。
|
||||
* </p>
|
||||
*
|
||||
* 类型判定支持:
|
||||
* 类型判定支持:
|
||||
* <ul>
|
||||
* <li>字面量后缀:支持 B/S/I/L/F/D(大小写均可)</li>
|
||||
* <li>浮点数支持:如无后缀但有小数点,视为 double</li>
|
||||
* <li>变量类型:根据传入变量表推断类型,未识别则默认 int</li>
|
||||
* <li>字面量后缀: 支持 B/S/I/L/F/D(大小写均可)</li>
|
||||
* <li>浮点数支持: 如无后缀但有小数点,视为 double</li>
|
||||
* <li>变量类型: 根据传入变量表推断类型,未识别则默认 int</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class ComparisonUtils {
|
||||
@ -39,7 +39,7 @@ public final class ComparisonUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
|
||||
* 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
|
||||
* - D (double): 6
|
||||
* - F (float): 5
|
||||
* - L (long): 4
|
||||
@ -106,7 +106,7 @@ public final class ComparisonUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部工具方法:根据表达式节点和变量表推断类型标记字符。
|
||||
* 内部工具方法: 根据表达式节点和变量表推断类型标记字符。
|
||||
* 字面量支持 B/S/I/L/F/D(大小写均可),浮点数默认 double;
|
||||
* 标识符类型按变量表映射,未知则默认 int。
|
||||
*
|
||||
|
||||
@ -14,7 +14,7 @@ import java.util.Map;
|
||||
/**
|
||||
* 表达式分析与操作符选择工具类。
|
||||
* <p>
|
||||
* 主要功能:
|
||||
* 主要功能:
|
||||
* - 解析字面量常量,自动推断类型
|
||||
* - 自动匹配并选择适合的算术/比较操作码
|
||||
* - 表达式类型的合并与类型提升
|
||||
@ -138,7 +138,7 @@ public final class ExpressionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容旧逻辑:仅凭操作符直接返回 int32 比较指令。
|
||||
* 兼容旧逻辑: 仅凭操作符直接返回 int32 比较指令。
|
||||
*
|
||||
* @param op 比较操作符
|
||||
* @return int32 类型的比较操作码
|
||||
@ -148,7 +148,7 @@ public final class ExpressionUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 推荐调用:根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码。
|
||||
* 推荐调用: 根据左右表达式类型自动选择 int/long/float/double 等合适的比较操作码。
|
||||
*
|
||||
* @param variables 变量名到类型的映射
|
||||
* @param op 比较符号
|
||||
@ -196,7 +196,7 @@ public final class ExpressionUtils {
|
||||
|
||||
/**
|
||||
* 返回两个类型后缀中的最大类型(宽度优先)。
|
||||
* 优先级:d > f > l > i > s > b > '\0'
|
||||
* 优先级: d > f > l > i > s > b > '\0'
|
||||
*
|
||||
* @param l 类型后缀1
|
||||
* @param r 类型后缀2
|
||||
|
||||
@ -9,18 +9,18 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
|
||||
* 与 {@link IRVirtualRegister} 不同,常量不需要通过寄存器存储,
|
||||
* 可直接作为 IR 指令的操作数使用。
|
||||
* <p>
|
||||
* 典型应用:
|
||||
* - 加载常量指令:v1 = CONST 42
|
||||
* - 计算表达式:v2 = ADD v1, 100
|
||||
* 典型应用:
|
||||
* - 加载常量指令: v1 = CONST 42
|
||||
* - 计算表达式: v2 = ADD v1, 100
|
||||
*/
|
||||
public record IRConstant(Object value) implements IRValue {
|
||||
|
||||
/**
|
||||
* 将常量值转换为字符串,用于打印 IR 指令或调试输出。
|
||||
* <p>
|
||||
* 例如:
|
||||
* - 整数常量:42
|
||||
* - 字符串常量:"hello"
|
||||
* 例如:
|
||||
* - 整数常量: 42
|
||||
* - 字符串常量: "hello"
|
||||
*
|
||||
* @return 常量的字符串表示
|
||||
*/
|
||||
|
||||
@ -8,11 +8,11 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
|
||||
* 在 IR 系统中,虚拟寄存器用于存储每个中间计算结果,是 SSA(Static Single Assignment)形式的核心。
|
||||
* 每个虚拟寄存器在程序中只被赋值一次,其值来源于一条明确的指令输出。
|
||||
* <p>
|
||||
* 特点:
|
||||
* 特点:
|
||||
* <ul>
|
||||
* <li>每个寄存器有唯一编号 {@code id},由 {@code IRFunction.newRegister()} 自动生成</li>
|
||||
* <li>实现 {@link IRValue} 接口,可作为 IRInstruction 的操作数</li>
|
||||
* <li>具备良好的打印与调试格式:%id</li>
|
||||
* <li>具备良好的打印与调试格式: %id</li>
|
||||
* </ul>
|
||||
*
|
||||
* 适用于表达式求值、参数传递、函数返回值、临时变量等所有中间值场景。
|
||||
@ -23,7 +23,7 @@ public record IRVirtualRegister(int id) implements IRValue {
|
||||
|
||||
/**
|
||||
* 将虚拟寄存器转换为字符串格式,方便输出和调试。
|
||||
* 格式为:%<id>,例如 %3 表示编号为 3 的虚拟寄存器。
|
||||
* 格式为: %<id>,例如 %3 表示编号为 3 的虚拟寄存器。
|
||||
*
|
||||
* @return 格式化的字符串表示
|
||||
*/
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.lexer.base.TokenScanner;
|
||||
* 是 {@link TokenScanner} 实现进行词法识别的基础设施。
|
||||
* </p>
|
||||
* <p>
|
||||
* 设计要点:
|
||||
* 设计要点:
|
||||
* <ul>
|
||||
* <li>构造时统一将 Windows 换行符 (<code>\r\n</code>) 转换为 Unix 风格 (<code>\n</code>)。</li>
|
||||
* <li>所有坐标均以 <strong>1</strong> 为起始行/列号,更贴合人类直觉。</li>
|
||||
|
||||
@ -12,7 +12,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Snow 语言词法分析器核心实现。
|
||||
* <p>采用“<b>先扫描 → 后批量校验 → 统一报告</b>”策略:
|
||||
* <p>采用“<b>先扫描 → 后批量校验 → 统一报告</b>”策略:
|
||||
* <ol>
|
||||
* <li>{@link #scanAllTokens()}— 用扫描器链把字符流拆成 {@link Token}</li>
|
||||
* <li>{@link #validateTokens()}— 基于 token 序列做轻量上下文校验</li>
|
||||
@ -68,7 +68,7 @@ public class LexerEngine {
|
||||
System.out.println("\n## 词法分析通过,没有发现错误\n");
|
||||
return;
|
||||
}
|
||||
System.err.println("\n词法分析发现 " + errors.size() + " 个错误:");
|
||||
System.err.println("\n词法分析发现 " + errors.size() + " 个错误: ");
|
||||
errors.forEach(e -> System.err.println(" " + e));
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ public class LexerEngine {
|
||||
public List<LexicalError> getErrors() { return List.copyOf(errors); }
|
||||
|
||||
/**
|
||||
* 逐字符扫描:依次尝试各扫描器;扫描器抛出的
|
||||
* 逐字符扫描: 依次尝试各扫描器;扫描器抛出的
|
||||
* {@link LexicalException} 被捕获并转为 {@link LexicalError}。
|
||||
*/
|
||||
private void scanAllTokens() {
|
||||
@ -105,7 +105,7 @@ public class LexerEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 目前包含三条规则:<br>
|
||||
* 目前包含三条规则: <br>
|
||||
* 1. Dot-Prefix'.' 不能作标识符前缀<br>
|
||||
* 2. Declare-Ident declare 后必须紧跟合法标识符,并且只能一个<br>
|
||||
* 3. Double-Ident declare 后若出现第二个 IDENTIFIER 视为多余<br>
|
||||
@ -149,6 +149,6 @@ public class LexerEngine {
|
||||
|
||||
/** 构造统一的 LexicalError */
|
||||
private LexicalError err(Token t, String msg) {
|
||||
return new LexicalError(absPath, t.getLine(), t.getCol(), "非法的标记序列:" + msg);
|
||||
return new LexicalError(absPath, t.getLine(), t.getCol(), "非法的标记序列: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@ package org.jcnc.snow.compiler.lexer.core;
|
||||
* <li>完全禁止 Java 堆栈信息输出,使命令行输出保持整洁。</li>
|
||||
* </ul>
|
||||
* <pre>
|
||||
* 例:
|
||||
* Main.snow: 行 7, 列 20: 词法错误:非法字符序列 '@'
|
||||
* 例:
|
||||
* Main.snow: 行 7, 列 20: 词法错误: 非法字符序列 '@'
|
||||
* </pre>
|
||||
*/
|
||||
public class LexicalException extends RuntimeException {
|
||||
@ -24,7 +24,7 @@ public class LexicalException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* 构造词法异常
|
||||
* @param reason 错误原因(如:非法字符描述)
|
||||
* @param reason 错误原因(如: 非法字符描述)
|
||||
* @param line 出错行号
|
||||
* @param column 出错列号
|
||||
*/
|
||||
|
||||
@ -11,11 +11,11 @@
|
||||
|
||||
## 核心功能
|
||||
|
||||
- **词法分析引擎**:从源代码提取标准化 Token 流
|
||||
- **模块化扫描器体系**:按需扩展不同类型的 Token 识别
|
||||
- **灵活的上下文管理**:跟踪源代码位置,支持错误处理
|
||||
- **统一的 Token 工厂**:集中创建 Token 实例
|
||||
- **工具支持**:Token 打印与调试辅助
|
||||
- **词法分析引擎**: 从源代码提取标准化 Token 流
|
||||
- **模块化扫描器体系**: 按需扩展不同类型的 Token 识别
|
||||
- **灵活的上下文管理**: 跟踪源代码位置,支持错误处理
|
||||
- **统一的 Token 工厂**: 集中创建 Token 实例
|
||||
- **工具支持**: Token 打印与调试辅助
|
||||
|
||||
## 模块结构
|
||||
|
||||
@ -33,6 +33,6 @@ lexer/
|
||||
|
||||
* JDK 24 或更高版本
|
||||
* Maven 构建管理
|
||||
* 推荐 IDE:IntelliJ IDEA
|
||||
* 推荐 IDE: IntelliJ IDEA
|
||||
|
||||
---
|
||||
|
||||
@ -35,7 +35,7 @@ public abstract class AbstractTokenScanner implements TokenScanner {
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法:由子类实现具体的扫描逻辑。
|
||||
* 抽象方法: 由子类实现具体的扫描逻辑。
|
||||
* <p>
|
||||
* 实现应消费一定字符并根据规则构造 Token。
|
||||
* 若无需生成 Token,可返回 null。
|
||||
@ -49,7 +49,7 @@ public abstract class AbstractTokenScanner implements TokenScanner {
|
||||
protected abstract Token scanToken(LexerContext ctx, int line, int col);
|
||||
|
||||
/**
|
||||
* 工具方法:连续读取字符直到遇到不满足指定条件的字符。
|
||||
* 工具方法: 连续读取字符直到遇到不满足指定条件的字符。
|
||||
*
|
||||
* @param ctx 当前词法上下文
|
||||
* @param predicate 字符匹配条件
|
||||
|
||||
@ -8,17 +8,17 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
/**
|
||||
* {@code CommentTokenScanner} —— 注释解析器,基于有限状态机(FSM)。
|
||||
*
|
||||
* <p>负责将源码中的两种注释形式切分为 {@link TokenType#COMMENT COMMENT} token:</p>
|
||||
* <p>负责将源码中的两种注释形式切分为 {@link TokenType#COMMENT COMMENT} token: </p>
|
||||
* <ol>
|
||||
* <li>单行注释:以 {@code //} 开头,直至行尾或文件末尾。</li>
|
||||
* <li>多行注释:以 {@code /*} 开头,以 <code>*/</code> 结束,可跨多行。</li>
|
||||
* <li>单行注释: 以 {@code //} 开头,直至行尾或文件末尾。</li>
|
||||
* <li>多行注释: 以 {@code /*} 开头,以 <code>*/</code> 结束,可跨多行。</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>本扫描器遵循“发现即捕获”原则:注释文本被完整保留在 Token 中,供后续的文档提取、源映射等分析使用。</p>
|
||||
* <p>本扫描器遵循“发现即捕获”原则: 注释文本被完整保留在 Token 中,供后续的文档提取、源映射等分析使用。</p>
|
||||
*
|
||||
* <p>错误处理策略</p>
|
||||
* <ul>
|
||||
* <li>未终止的多行注释:若文件结束时仍未遇到 <code>*/</code>,抛出 {@link LexicalException}。</li>
|
||||
* <li>未终止的多行注释: 若文件结束时仍未遇到 <code>*/</code>,抛出 {@link LexicalException}。</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class CommentTokenScanner extends AbstractTokenScanner {
|
||||
@ -61,7 +61,7 @@ public class CommentTokenScanner extends AbstractTokenScanner {
|
||||
break;
|
||||
|
||||
case SINGLE_LINE:
|
||||
// 单行注释处理:读取直到行尾
|
||||
// 单行注释处理: 读取直到行尾
|
||||
if (ctx.isAtEnd() || ctx.peek() == '\n') {
|
||||
// 如果遇到换行符,停止读取并返回注释内容
|
||||
return new Token(TokenType.COMMENT, literal.toString(), line, col);
|
||||
|
||||
@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
/**
|
||||
* {@code IdentifierTokenScanner} —— 标识符扫描器,负责识别源代码中的标识符(如变量名、函数名等)。
|
||||
*
|
||||
* <p>标识符的识别遵循以下规则:</p>
|
||||
* <p>标识符的识别遵循以下规则: </p>
|
||||
* <ul>
|
||||
* <li>标识符必须以字母(A-Z,a-z)或下划线(_)开头。</li>
|
||||
* <li>标识符的后续字符可以是字母、数字(0-9)或下划线。</li>
|
||||
|
||||
@ -5,7 +5,7 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
|
||||
/**
|
||||
* 换行符扫描器:将源代码中的换行符(\n)识别为 {@code NEWLINE} 类型的 Token。
|
||||
* 换行符扫描器: 将源代码中的换行符(\n)识别为 {@code NEWLINE} 类型的 Token。
|
||||
* <p>
|
||||
* 用于记录行的分界,辅助语法分析阶段进行行敏感的判断或保持结构清晰。
|
||||
*/
|
||||
|
||||
@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
/**
|
||||
* NumberTokenScanner —— 基于有限状态机(FSM)的数字字面量解析器。
|
||||
* <p>
|
||||
* 该扫描器负责将源码中的数字字符串切分为 NUMBER_LITERAL token,当前支持:
|
||||
* 该扫描器负责将源码中的数字字符串切分为 NUMBER_LITERAL token,当前支持:
|
||||
* <ol>
|
||||
* <li>十进制整数(如 0,42,123456)</li>
|
||||
* <li>十进制小数(如 3.14,0.5)</li>
|
||||
@ -18,7 +18,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
* 如果后续需要支持科学计数法、下划线分隔符、不同进制等,只需扩展现有状态机的转移规则。
|
||||
*
|
||||
* <pre>
|
||||
* 状态机简述:
|
||||
* 状态机简述:
|
||||
* INT_PART --'.'--> DEC_POINT
|
||||
* | |
|
||||
* | v
|
||||
@ -27,28 +27,28 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
* v
|
||||
* DEC_POINT --digit--> FRAC_PART
|
||||
* </pre>
|
||||
* 状态说明:
|
||||
* 状态说明:
|
||||
* <ul>
|
||||
* <li>INT_PART :读取整数部分,遇到 '.' 进入 DEC_POINT,否则结束。</li>
|
||||
* <li>DEC_POINT :已读到小数点,必须下一个字符是数字,否则报错。</li>
|
||||
* <li>FRAC_PART :读取小数部分,遇非法字符则结束主体。</li>
|
||||
* <li>END :主体扫描结束,进入后缀/尾随字符判定。</li>
|
||||
* <li>INT_PART : 读取整数部分,遇到 '.' 进入 DEC_POINT,否则结束。</li>
|
||||
* <li>DEC_POINT : 已读到小数点,必须下一个字符是数字,否则报错。</li>
|
||||
* <li>FRAC_PART : 读取小数部分,遇非法字符则结束主体。</li>
|
||||
* <li>END : 主体扫描结束,进入后缀/尾随字符判定。</li>
|
||||
* </ul>
|
||||
*
|
||||
* 错误处理策略:
|
||||
* 错误处理策略:
|
||||
* <ol>
|
||||
* <li>数字后跟未知字母(如 42X)—— 抛出 LexicalException</li>
|
||||
* <li>数字与合法后缀间有空白(如 3 L)—— 抛出 LexicalException</li>
|
||||
* <li>小数点后缺失数字(如 1.)—— 抛出 LexicalException</li>
|
||||
* </ol>
|
||||
*
|
||||
* 支持的单字符类型后缀包括:b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set<String>。
|
||||
* 支持的单字符类型后缀包括: b, s, l, f, d 及其大写形式。若需支持多字符后缀,可将该集合扩展为 Set<String>。
|
||||
*/
|
||||
public class NumberTokenScanner extends AbstractTokenScanner {
|
||||
|
||||
/**
|
||||
* 支持的单字符类型后缀集合。
|
||||
* 包含:b, s, l, f, d 及其大写形式。
|
||||
* 包含: b, s, l, f, d 及其大写形式。
|
||||
* 对于多字符后缀,可扩展为 Set<String> 并在扫描尾部做贪婪匹配。
|
||||
*/
|
||||
private static final String SUFFIX_CHARS = "bslfdBSLFD";
|
||||
|
||||
@ -8,14 +8,14 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
* 运算符扫描器(OperatorTokenScanner)
|
||||
*
|
||||
* <p>负责在词法分析阶段识别由 <b>= ! < > | & %</b> 等字符
|
||||
* 起始的单字符或双字符运算符,并生成相应 {@link Token}:</p>
|
||||
* 起始的单字符或双字符运算符,并生成相应 {@link Token}: </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>赋值 / 比较:{@code =}, {@code ==}, {@code !=}</li>
|
||||
* <li>关系运算:{@code >}, {@code >=}, {@code <}, {@code <=}</li>
|
||||
* <li>逻辑运算:{@code &&}, {@code ||}</li>
|
||||
* <li>取模运算:{@code %}</li>
|
||||
* <li>逻辑非:{@code !}</li>
|
||||
* <li>赋值 / 比较: {@code =}, {@code ==}, {@code !=}</li>
|
||||
* <li>关系运算: {@code >}, {@code >=}, {@code <}, {@code <=}</li>
|
||||
* <li>逻辑运算: {@code &&}, {@code ||}</li>
|
||||
* <li>取模运算: {@code %}</li>
|
||||
* <li>逻辑非: {@code !}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>如果无法匹配到合法组合,将返回 {@link TokenType#UNKNOWN}。</p>
|
||||
|
||||
@ -5,9 +5,9 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
|
||||
/**
|
||||
* 字符串扫描器:处理双引号包裹的字符串字面量,支持基本的转义字符。
|
||||
* 字符串扫描器: 处理双引号包裹的字符串字面量,支持基本的转义字符。
|
||||
* <p>
|
||||
* 支持格式示例:
|
||||
* 支持格式示例:
|
||||
* <ul>
|
||||
* <li>"hello"</li>
|
||||
* <li>"line\\nbreak"</li>
|
||||
|
||||
@ -5,13 +5,13 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
|
||||
/**
|
||||
* 符号扫描器:识别常见的单字符符号,如冒号、逗号、括号和算术符号。
|
||||
* 符号扫描器: 识别常见的单字符符号,如冒号、逗号、括号和算术符号。
|
||||
* <p>
|
||||
* 支持的符号包括:
|
||||
* 支持的符号包括:
|
||||
* <ul>
|
||||
* <li>标点符号:: , .</li>
|
||||
* <li>括号:( )</li>
|
||||
* <li>算术运算符:+ - *</li>
|
||||
* <li>标点符号: : , .</li>
|
||||
* <li>括号: ( )</li>
|
||||
* <li>算术运算符: + - *</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 生成的 Token 类型根据字符分别对应 {@link TokenType} 枚举中的定义。
|
||||
|
||||
@ -11,7 +11,7 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
* 由本类处理并抛出 {@link LexicalException},终止词法分析流程。
|
||||
* </p>
|
||||
* <p>
|
||||
* 主要作用:保证所有非法、不可识别的字符(如@、$等)不会被静默跳过或误当作合法 Token,
|
||||
* 主要作用: 保证所有非法、不可识别的字符(如@、$等)不会被静默跳过或误当作合法 Token,
|
||||
* 而是在词法阶段立刻定位并报错,有助于尽早发现源代码问题。
|
||||
* </p>
|
||||
*/
|
||||
@ -50,6 +50,6 @@ public class UnknownTokenScanner extends AbstractTokenScanner {
|
||||
if (lexeme.isEmpty())
|
||||
lexeme = String.valueOf(ctx.advance());
|
||||
// 抛出词法异常,并带上错误片段与具体位置
|
||||
throw new LexicalException("词法错误:非法字符序列 '" + lexeme + "'", line, col);
|
||||
throw new LexicalException("词法错误: 非法字符序列 '" + lexeme + "'", line, col);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import org.jcnc.snow.compiler.lexer.core.LexerContext;
|
||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
|
||||
/**
|
||||
* 空白符扫描器:跳过非换行的空白字符,不生成任何 Token。
|
||||
* 空白符扫描器: 跳过非换行的空白字符,不生成任何 Token。
|
||||
* <p>
|
||||
* 支持的空白字符包括空格、制表符(Tab)等,但不包括换行符(由 {@link NewlineTokenScanner} 处理)。
|
||||
* <p>
|
||||
|
||||
@ -12,7 +12,7 @@ import java.util.Set;
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 主要功能与特性:
|
||||
* 主要功能与特性:
|
||||
* <ul>
|
||||
* <li>统一管理语言关键字和类型名集合,便于扩展与维护。</li>
|
||||
* <li>自动推断 Token 类型,无需外部干预。</li>
|
||||
@ -35,7 +35,7 @@ public class TokenFactory {
|
||||
/**
|
||||
* 创建一个根据内容自动推断类型的 {@link Token} 实例。
|
||||
* <p>
|
||||
* 优先级顺序为:类型(TYPE) > 关键字(KEYWORD) > 标识符(IDENTIFIER) > 未知(UNKNOWN)。
|
||||
* 优先级顺序为: 类型(TYPE) > 关键字(KEYWORD) > 标识符(IDENTIFIER) > 未知(UNKNOWN)。
|
||||
* 若原始字符串同时属于多类,则按优先级最高者处理。
|
||||
* </p>
|
||||
*
|
||||
@ -52,7 +52,7 @@ public class TokenFactory {
|
||||
/**
|
||||
* 判断并推断给定字符串的 {@link TokenType} 类型。
|
||||
* <p>
|
||||
* 优先级依次为:TYPE > KEYWORD > IDENTIFIER > UNKNOWN。
|
||||
* 优先级依次为: TYPE > KEYWORD > IDENTIFIER > UNKNOWN。
|
||||
* </p>
|
||||
*
|
||||
* @param raw 原始词素字符串
|
||||
@ -106,7 +106,7 @@ public class TokenFactory {
|
||||
* <p>
|
||||
* 合法标识符需以字母(a-z/A-Z)或下划线(_)开头,
|
||||
* 后续可包含字母、数字或下划线。
|
||||
* 例如:_abc, a1b2, name_123 均为合法标识符。
|
||||
* 例如: _abc, a1b2, name_123 均为合法标识符。
|
||||
* </p>
|
||||
*
|
||||
* @param raw 输入的字符串
|
||||
|
||||
@ -17,7 +17,7 @@ public class TokenPrinter {
|
||||
/**
|
||||
* 将给定的 Token 列表打印到标准输出(控制台)。
|
||||
* <p>
|
||||
* 输出格式:
|
||||
* 输出格式:
|
||||
* <pre>
|
||||
* line col type lexeme
|
||||
* ----------------------------------------------------
|
||||
@ -33,7 +33,7 @@ public class TokenPrinter {
|
||||
* 都应包含有效的行号、列号、类型和词素信息
|
||||
*/
|
||||
public static void print(List<Token> tokens) {
|
||||
// 打印表头:列名对齐,宽度分别为 6、6、16
|
||||
// 打印表头: 列名对齐,宽度分别为 6、6、16
|
||||
System.out.printf("%-6s %-6s %-16s %s%n", "line", "col", "type", "lexeme");
|
||||
System.out.println("----------------------------------------------------");
|
||||
|
||||
@ -45,7 +45,7 @@ public class TokenPrinter {
|
||||
.replace("\t", "\\t")
|
||||
.replace("\r", "\\r");
|
||||
|
||||
// 按照固定格式输出:行号、列号、类型、词素
|
||||
// 按照固定格式输出: 行号、列号、类型、词素
|
||||
System.out.printf("%-6d %-6d %-16s %s%n",
|
||||
token.getLine(),
|
||||
token.getCol(),
|
||||
|
||||
@ -25,7 +25,7 @@ public record BinaryExpressionNode(
|
||||
/**
|
||||
* 返回该二元运算表达式的字符串表示形式。
|
||||
* <p>
|
||||
* 输出格式为:{@code left + " " + operator + " " + right},
|
||||
* 输出格式为: {@code left + " " + operator + " " + right},
|
||||
* 适用于调试或打印语法树结构。
|
||||
* </p>
|
||||
*
|
||||
|
||||
@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||
* {@code ExpressionStatementNode} 表示抽象语法树(AST)中的表达式语句节点。
|
||||
* <p>
|
||||
* 表达式语句通常由一个单独的表达式组成,并以语句形式出现。
|
||||
* 例如:{@code foo();}、{@code x = 1;}、{@code print("hello");} 等。
|
||||
* 例如: {@code foo();}、{@code x = 1;}、{@code print("hello");} 等。
|
||||
* </p>
|
||||
*
|
||||
* @param expression 表达式主体,通常为函数调用、赋值、方法链式调用等可求值表达式。
|
||||
|
||||
@ -11,7 +11,7 @@ import java.util.List;
|
||||
* <p>
|
||||
* 函数定义通常包含函数名、形参列表、返回类型以及函数体,
|
||||
* 在语义分析、类型检查与代码生成等阶段具有核心地位。
|
||||
* 示例:{@code int add(int a, int b) { return a + b; }}
|
||||
* 示例: {@code int add(int a, int b) { return a + b; }}
|
||||
* </p>
|
||||
*
|
||||
* @param name 函数名称标识符
|
||||
|
||||
@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||
/**
|
||||
* {@code ImportNode} 表示抽象语法树(AST)中的 import 语句节点。
|
||||
* <p>
|
||||
* import 语句用于引入外部模块或库文件,其语法形式一般为:
|
||||
* import 语句用于引入外部模块或库文件,其语法形式一般为:
|
||||
* {@code import my.module;}
|
||||
* </p>
|
||||
* <p>
|
||||
|
||||
@ -12,7 +12,7 @@ import java.util.Optional;
|
||||
* return 语句用于从当前函数中返回控制权,并可携带一个可选的返回值表达式。
|
||||
* </p>
|
||||
* <p>
|
||||
* 示例:
|
||||
* 示例:
|
||||
* <ul>
|
||||
* <li>{@code return;}</li>
|
||||
* <li>{@code return x + 1;}</li>
|
||||
|
||||
@ -6,10 +6,10 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
|
||||
/**
|
||||
* {@code UnaryExpressionNode} —— 前缀一元运算 AST 节点。
|
||||
*
|
||||
* <p>代表两种受支持的一元前缀表达式:
|
||||
* <p>代表两种受支持的一元前缀表达式:
|
||||
* <ul>
|
||||
* <li><b>取负</b>:{@code -x}</li>
|
||||
* <li><b>逻辑非</b>:{@code !x}</li>
|
||||
* <li><b>取负</b>: {@code -x}</li>
|
||||
* <li><b>逻辑非</b>: {@code !x}</li>
|
||||
* </ul>
|
||||
*
|
||||
* {@link #equals(Object)}、{@link #hashCode()} 等方法。</p>
|
||||
|
||||
@ -3,12 +3,12 @@ package org.jcnc.snow.compiler.parser.ast.base;
|
||||
/**
|
||||
* {@code Node} 是抽象语法树(AST)中所有语法节点的统一根接口。
|
||||
* <p>
|
||||
* 作为标记接口(Marker Interface),该接口定义 3 个方法:line()、column() 和 file() 用于定位错误,
|
||||
* 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
|
||||
* 作为标记接口(Marker Interface),该接口定义 3 个方法: line()、column() 和 file() 用于定位错误,
|
||||
* 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link ExpressionNode}:表达式节点,如常量、变量引用、函数调用等</li>
|
||||
* <li>{@link StatementNode}:语句节点,如声明、赋值、条件控制、循环、返回语句等</li>
|
||||
* <li>{@link ExpressionNode}: 表达式节点,如常量、变量引用、函数调用等</li>
|
||||
* <li>{@link StatementNode}: 语句节点,如声明、赋值、条件控制、循环、返回语句等</li>
|
||||
* <li>模块、函数、参数等高层结构节点</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
|
||||
@ -70,7 +70,7 @@ public record ParserEngine(ParserContext ctx) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步:跳过当前行或直到遇到显式注册的顶层关键字。
|
||||
* 同步: 跳过当前行或直到遇到显式注册的顶层关键字。
|
||||
* <p>
|
||||
* 该机制用于语法出错后恢复到下一个可能的有效解析点,防止指针停滞导致死循环或重复抛错。
|
||||
* 同步过程中会优先跳过本行所有未识别 token,并在遇到换行或注册关键字时停止,随后跳过连续空行。
|
||||
|
||||
@ -11,13 +11,13 @@
|
||||
|
||||
## 核心功能
|
||||
|
||||
- **抽象语法树(AST)生成**:定义丰富的 AST 节点类型
|
||||
- **表达式解析器**:基于 Pratt 解析,支持优先级、调用、成员访问等
|
||||
- **语句解析器**:支持 Snow 语言中的声明、控制流等
|
||||
- **模块解析器**:处理 `import` 导入声明
|
||||
- **函数解析器**:支持函数定义与调用
|
||||
- **灵活的解析上下文管理**:错误处理与流式 Token 管理
|
||||
- **工具支持**:AST JSON 序列化,便于调试与前后端通信
|
||||
- **抽象语法树(AST)生成**: 定义丰富的 AST 节点类型
|
||||
- **表达式解析器**: 基于 Pratt 解析,支持优先级、调用、成员访问等
|
||||
- **语句解析器**: 支持 Snow 语言中的声明、控制流等
|
||||
- **模块解析器**: 处理 `import` 导入声明
|
||||
- **函数解析器**: 支持函数定义与调用
|
||||
- **灵活的解析上下文管理**: 错误处理与流式 Token 管理
|
||||
- **工具支持**: AST JSON 序列化,便于调试与前后端通信
|
||||
|
||||
## 模块结构
|
||||
|
||||
@ -39,7 +39,7 @@ parser/
|
||||
|
||||
* JDK 24 或更高版本
|
||||
* Maven 构建管理
|
||||
* 推荐 IDE:IntelliJ IDEA
|
||||
* 推荐 IDE: IntelliJ IDEA
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -10,10 +10,10 @@ import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
|
||||
/**
|
||||
* {@code UnaryOperatorParselet} —— 前缀一元运算符的 Pratt 解析器。
|
||||
*
|
||||
* <p>当前 parselet 负责解析两种前缀运算:
|
||||
* <p>当前 parselet 负责解析两种前缀运算:
|
||||
* <ul>
|
||||
* <li><b>取负</b>:{@code -x}</li>
|
||||
* <li><b>逻辑非</b>:{@code !x}</li>
|
||||
* <li><b>取负</b>: {@code -x}</li>
|
||||
* <li><b>逻辑非</b>: {@code !x}</li>
|
||||
* </ul>
|
||||
*
|
||||
* 解析过程:
|
||||
@ -25,7 +25,7 @@ import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
|
||||
* <li>最终生成 {@link UnaryExpressionNode} AST 节点,记录运算符与操作数。</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>此类仅负责<strong>语法结构</strong>的构建:
|
||||
* <p>此类仅负责<strong>语法结构</strong>的构建:
|
||||
* <ul>
|
||||
* <li>类型正确性在 {@code UnaryExpressionAnalyzer} 中校验;</li>
|
||||
* <li>IR 生成在 {@code ExpressionBuilder.buildUnary} 中完成。</li>
|
||||
|
||||
@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||
* 构建一个有效的 {@link ExpressionNode} 抽象语法树结构。
|
||||
* </p>
|
||||
* <p>
|
||||
* 不同的实现可以采用不同的解析技术:
|
||||
* 不同的实现可以采用不同的解析技术:
|
||||
* <ul>
|
||||
* <li>递归下降(Recursive Descent)</li>
|
||||
* <li>Pratt Parser(前缀/中缀优先级驱动)</li>
|
||||
|
||||
@ -11,7 +11,7 @@ import org.jcnc.snow.compiler.parser.expression.Precedence;
|
||||
* 是 Pratt 解析器架构中处理中缀操作的关键组件。
|
||||
* </p>
|
||||
* <p>
|
||||
* 每个中缀解析器负责:
|
||||
* 每个中缀解析器负责:
|
||||
* <ul>
|
||||
* <li>根据左侧已解析的表达式,结合当前运算符继续解析右侧部分</li>
|
||||
* <li>提供运算符优先级,用于判断是否继续嵌套解析</li>
|
||||
|
||||
@ -8,7 +8,7 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
* {@code PrefixParselet} 是用于解析前缀表达式的通用接口。
|
||||
* <p>
|
||||
* 前缀表达式是以某个词法单元(Token)作为起始的表达式结构,
|
||||
* 常见类型包括:
|
||||
* 常见类型包括:
|
||||
* <ul>
|
||||
* <li>数字字面量(如 {@code 42})</li>
|
||||
* <li>标识符(如 {@code foo})</li>
|
||||
|
||||
@ -18,7 +18,7 @@ import java.util.HashMap;
|
||||
*/
|
||||
public class StatementParserFactory {
|
||||
|
||||
/** 注册表:语句关键字 -> 对应语句解析器 */
|
||||
/** 注册表: 语句关键字 -> 对应语句解析器 */
|
||||
private static final Map<String, StatementParser> registry = new HashMap<>();
|
||||
|
||||
static {
|
||||
@ -28,7 +28,7 @@ public class StatementParserFactory {
|
||||
registry.put("loop", new LoopStatementParser());
|
||||
registry.put("return", new ReturnStatementParser());
|
||||
|
||||
// 默认处理器:表达式语句
|
||||
// 默认处理器: 表达式语句
|
||||
registry.put("", new ExpressionStatementParser());
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ public class TopLevelParserFactory {
|
||||
/** 关键字 → 解析器注册表 */
|
||||
private static final Map<String, TopLevelParser> registry = new HashMap<>();
|
||||
|
||||
/** 缺省解析器:脚本模式(单条语句可执行) */
|
||||
/** 缺省解析器: 脚本模式(单条语句可执行) */
|
||||
private static final TopLevelParser DEFAULT = new ScriptTopLevelParser();
|
||||
|
||||
static {
|
||||
|
||||
@ -22,7 +22,7 @@ import java.util.*;
|
||||
* 实现 {@link TopLevelParser} 接口,用于将源代码中的函数块解析为抽象语法树(AST)中的 {@link FunctionNode}。
|
||||
*
|
||||
* <p>
|
||||
* 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分:
|
||||
* 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
@ -110,7 +110,7 @@ public class FunctionParser implements TopLevelParser {
|
||||
* 构造函数定义中各区块的解析规则(parameter、return_type、body)。
|
||||
*
|
||||
* <p>
|
||||
* 每个 {@link SectionDefinition} 包含两个部分:区块起始判断器(基于关键字)与具体的解析逻辑。
|
||||
* 每个 {@link SectionDefinition} 包含两个部分: 区块起始判断器(基于关键字)与具体的解析逻辑。
|
||||
* </p>
|
||||
*
|
||||
* @param params 参数节点收集容器,解析结果将存入此列表。
|
||||
@ -180,7 +180,7 @@ public class FunctionParser implements TopLevelParser {
|
||||
* 解析函数参数列表。
|
||||
*
|
||||
* <p>
|
||||
* 支持声明后附加注释,格式示例:
|
||||
* 支持声明后附加注释,格式示例:
|
||||
* <pre>
|
||||
* parameter:
|
||||
* declare x: int // 说明文字
|
||||
|
||||
@ -11,7 +11,7 @@ import java.util.List;
|
||||
/**
|
||||
* {@code ImportParser} 类用于解析源码中的 import 导入语句。
|
||||
* <p>
|
||||
* 支持以下格式的语法:
|
||||
* 支持以下格式的语法:
|
||||
* <pre>
|
||||
* import: module1, module2, module3
|
||||
* </pre>
|
||||
@ -23,7 +23,7 @@ public class ImportParser {
|
||||
/**
|
||||
* 解析 import 语句,并返回表示被导入模块的语法树节点列表。
|
||||
* <p>
|
||||
* 该方法会依次执行以下操作:
|
||||
* 该方法会依次执行以下操作:
|
||||
* <ol>
|
||||
* <li>确认当前语句以关键字 {@code import} 开头。</li>
|
||||
* <li>确认后跟一个冒号 {@code :}。</li>
|
||||
|
||||
@ -22,7 +22,7 @@ import java.util.List;
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 典型模块语法结构:
|
||||
* 典型模块语法结构:
|
||||
* <pre>
|
||||
* module: mymod
|
||||
* import ...
|
||||
@ -37,7 +37,7 @@ public class ModuleParser implements TopLevelParser {
|
||||
/**
|
||||
* 解析一个模块定义块,返回完整的 {@link ModuleNode} 语法树节点。
|
||||
* <p>
|
||||
* 解析过程包括:
|
||||
* 解析过程包括:
|
||||
* <ol>
|
||||
* <li>匹配模块声明起始 {@code module: IDENTIFIER}。</li>
|
||||
* <li>收集模块体内所有 import 和 function 语句,允许穿插空行。</li>
|
||||
|
||||
@ -10,12 +10,12 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
||||
/**
|
||||
* {@code DeclarationStatementParser} 类负责解析变量声明语句,是语句级解析器的一部分。
|
||||
* <p>
|
||||
* 本解析器支持以下两种形式的声明语法:
|
||||
* 本解析器支持以下两种形式的声明语法:
|
||||
* <pre>{@code
|
||||
* declare myVar:Integer
|
||||
* declare myVar:Integer = 42 + 3
|
||||
* }</pre>
|
||||
* 其中:
|
||||
* 其中:
|
||||
* <ul>
|
||||
* <li>{@code myVar} 为变量名(必须为标识符类型);</li>
|
||||
* <li>{@code Integer} 为类型标注(必须为类型标记);</li>
|
||||
@ -29,7 +29,7 @@ public class DeclarationStatementParser implements StatementParser {
|
||||
/**
|
||||
* 解析一条 {@code declare} 声明语句,并返回对应的抽象语法树节点 {@link DeclarationNode}。
|
||||
* <p>
|
||||
* 解析流程如下:
|
||||
* 解析流程如下:
|
||||
* <ol>
|
||||
* <li>匹配关键字 {@code declare};</li>
|
||||
* <li>读取变量名称(标识符类型);</li>
|
||||
|
||||
@ -14,7 +14,7 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
||||
/**
|
||||
* {@code ExpressionStatementParser} 用于解析通用表达式语句(赋值或普通表达式)。
|
||||
* <p>
|
||||
* 支持以下两种语法结构:
|
||||
* 支持以下两种语法结构:
|
||||
* <pre>{@code
|
||||
* x = 1 + 2 // 赋值语句
|
||||
* doSomething() // 一般表达式语句
|
||||
@ -51,7 +51,7 @@ public class ExpressionStatementParser implements StatementParser {
|
||||
int column = ts.peek().getCol();
|
||||
String file = ctx.getSourceName();
|
||||
|
||||
// 赋值语句:IDENTIFIER = expr
|
||||
// 赋值语句: IDENTIFIER = expr
|
||||
if (ts.peek().getType() == TokenType.IDENTIFIER && "=".equals(ts.peek(1).getLexeme())) {
|
||||
String varName = ts.next().getLexeme();
|
||||
ts.expect("=");
|
||||
|
||||
@ -15,7 +15,7 @@ import java.util.List;
|
||||
/**
|
||||
* {@code IfStatementParser} 类负责解析 if 条件语句,是语句级解析器中的条件分支处理器。
|
||||
* <p>
|
||||
* 本解析器支持以下结构的条件语法:
|
||||
* 本解析器支持以下结构的条件语法:
|
||||
* <pre>{@code
|
||||
* if <condition> then
|
||||
* <then-statements>
|
||||
@ -23,7 +23,7 @@ import java.util.List;
|
||||
* <else-statements>]
|
||||
* end if
|
||||
* }</pre>
|
||||
* 其中:
|
||||
* 其中:
|
||||
* <ul>
|
||||
* <li>{@code <condition>} 为任意可解析的布尔或数值表达式,使用 {@link PrattExpressionParser} 解析;</li>
|
||||
* <li>{@code <then-statements>} 与 {@code <else-statements>} 可包含多条语句,自动跳过空行;</li>
|
||||
@ -119,7 +119,7 @@ public class IfStatementParser implements StatementParser {
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// 统一结束处理:end if
|
||||
// 统一结束处理: end if
|
||||
// -------------------------
|
||||
ts.expect("end");
|
||||
ts.expect("if");
|
||||
|
||||
@ -21,7 +21,7 @@ import java.util.Map;
|
||||
/**
|
||||
* {@code LoopStatementParser} 类负责解析自定义结构化的 {@code loop} 语句块。
|
||||
* <p>
|
||||
* 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块:
|
||||
* 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块:
|
||||
* <pre>{@code
|
||||
* loop:
|
||||
* init:
|
||||
@ -36,12 +36,12 @@ import java.util.Map;
|
||||
* end loop
|
||||
* }</pre>
|
||||
*
|
||||
* 各区块说明:
|
||||
* 各区块说明:
|
||||
* <ul>
|
||||
* <li>{@code init}:初始化语句,通常为变量声明。</li>
|
||||
* <li>{@code cond}:循环判断条件,必须为布尔或数值表达式。</li>
|
||||
* <li>{@code step}:每轮执行后更新逻辑,通常为赋值语句。</li>
|
||||
* <li>{@code body}:主执行语句块,支持任意多条语句。</li>
|
||||
* <li>{@code init}: 初始化语句,通常为变量声明。</li>
|
||||
* <li>{@code cond}: 循环判断条件,必须为布尔或数值表达式。</li>
|
||||
* <li>{@code step}: 每轮执行后更新逻辑,通常为赋值语句。</li>
|
||||
* <li>{@code body}: 主执行语句块,支持任意多条语句。</li>
|
||||
* </ul>
|
||||
* 本类依赖 {@link FlexibleSectionParser} 实现各区块的统一处理,确保结构明确、可扩展。
|
||||
*/
|
||||
@ -50,7 +50,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
/**
|
||||
* 解析 {@code loop} 语句块,构建出对应的 {@link LoopNode} 抽象语法树节点。
|
||||
* <p>
|
||||
* 本方法会按顺序检查各个命名区块(可乱序书写),并分别绑定其对应语义解析器:
|
||||
* 本方法会按顺序检查各个命名区块(可乱序书写),并分别绑定其对应语义解析器:
|
||||
* <ul>
|
||||
* <li>通过 {@link ParserUtils#matchHeader} 匹配区块开头;</li>
|
||||
* <li>通过 {@link FlexibleSectionParser} 派发区块逻辑;</li>
|
||||
@ -83,7 +83,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
// 定义各命名区块的识别与处理逻辑
|
||||
Map<String, FlexibleSectionParser.SectionDefinition> sections = new HashMap<>();
|
||||
|
||||
// init 区块:仅支持一条语句,通常为 declare
|
||||
// init 区块: 仅支持一条语句,通常为 declare
|
||||
sections.put("init", new FlexibleSectionParser.SectionDefinition(
|
||||
ts1 -> ts1.peek().getLexeme().equals("init"),
|
||||
(ctx1, ts1) -> {
|
||||
@ -93,7 +93,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
}
|
||||
));
|
||||
|
||||
// cond 区块:支持任意可解析为布尔的表达式
|
||||
// cond 区块: 支持任意可解析为布尔的表达式
|
||||
sections.put("cond", new FlexibleSectionParser.SectionDefinition(
|
||||
ts1 -> ts1.peek().getLexeme().equals("cond"),
|
||||
(ctx1, ts1) -> {
|
||||
@ -104,7 +104,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
}
|
||||
));
|
||||
|
||||
// step 区块:目前仅支持单一变量赋值语句
|
||||
// step 区块: 目前仅支持单一变量赋值语句
|
||||
sections.put("step", new FlexibleSectionParser.SectionDefinition(
|
||||
ts1 -> ts1.peek().getLexeme().equals("step"),
|
||||
(ctx1, ts1) -> {
|
||||
@ -122,7 +122,7 @@ public class LoopStatementParser implements StatementParser {
|
||||
}
|
||||
));
|
||||
|
||||
// body 区块:支持多条语句,直到遇到 end body
|
||||
// body 区块: 支持多条语句,直到遇到 end body
|
||||
sections.put("body", new FlexibleSectionParser.SectionDefinition(
|
||||
ts1 -> ts1.peek().getLexeme().equals("body"),
|
||||
(ctx1, ts1) -> {
|
||||
|
||||
@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
||||
/**
|
||||
* {@code ReturnStatementParser} 负责解析 return 语句,是语句级解析器的一部分。
|
||||
* <p>
|
||||
* 支持以下两种 return 语句形式:
|
||||
* 支持以下两种 return 语句形式:
|
||||
* <pre>{@code
|
||||
* return // 无返回值
|
||||
* return expression // 带返回值
|
||||
@ -23,7 +23,7 @@ public class ReturnStatementParser implements StatementParser {
|
||||
/**
|
||||
* 解析一条 return 语句,并返回对应的 {@link ReturnNode} 抽象语法树节点。
|
||||
* <p>
|
||||
* 解析逻辑如下:
|
||||
* 解析逻辑如下:
|
||||
* <ol>
|
||||
* <li>匹配起始关键字 {@code return}。</li>
|
||||
* <li>判断其后是否为 {@code NEWLINE},若否则表示存在返回值表达式。</li>
|
||||
|
||||
@ -14,7 +14,7 @@ import java.util.*;
|
||||
* 并可借助 {@code JSONParser.toJson(Object)} 方法将其序列化为 JSON 字符串,用于调试、
|
||||
* 可视化或跨语言数据传输。
|
||||
* <p>
|
||||
* 支持的节点类型包括(新增对 {@code BoolLiteralNode}、{@code UnaryExpressionNode} 的完整支持):
|
||||
* 支持的节点类型包括(新增对 {@code BoolLiteralNode}、{@code UnaryExpressionNode} 的完整支持):
|
||||
* <ul>
|
||||
* <li>{@link ModuleNode}</li>
|
||||
* <li>{@link FunctionNode}</li>
|
||||
@ -213,7 +213,7 @@ public class ASTJsonSerializer {
|
||||
"object", exprToMap(object),
|
||||
"member", member
|
||||
);
|
||||
// 默认兜底处理:只写类型
|
||||
// 默认兜底处理: 只写类型
|
||||
default -> Map.of("type", expr.getClass().getSimpleName());
|
||||
};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user