!39 refactor: 重构循环语句解析器

Merge pull request !39 from Luke/feature/optimize-the-loop
This commit is contained in:
Luke 2025-07-16 02:15:15 +00:00 committed by Gitee
commit 85d3b129ae
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
17 changed files with 680 additions and 91 deletions

1
.gitignore vendored
View File

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

View File

@ -69,7 +69,10 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
[https://gitee.com/jcnc-org/snow/releases](https://gitee.com/jcnc-org/snow/releases)
## 相关文档
[Snow-Lang 语法](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
[Snow-Lang 指南](docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md)
[Snow-Lang 语法规范](docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md)
[Git 管理规范](docs/Snow-Lang-Git-Management/Snow-Lang-Git-Management.md)
@ -388,11 +391,11 @@ module: Math
body:
declare num1:int = 1
loop:
initializer:
init:
declare counter:int = 1
condition:
cond:
counter <= n
update:
step:
counter = counter + 1
body:
num1 = num1 * counter

View File

@ -0,0 +1,585 @@
# SnowLang 语法规范
---
## 0 · 符号约定
* ⟦ … ⟧可选项0 或 1 次)
* { … }\*可重复项0 次或多次)
---
## 1 · 词汇结构
### 1.1 编码与字符集
源文件采用 UTF8 编码。除注释外,标识符只允许英文大小写字母 (AZ az)、数字 (09) 与下划线 _首字符不能为数字。
```ebnf
identifier ::= [A-Za-z_][A-Za-z0-9_]* ;
```
* **区分大小写**Foo 与 foo 为不同标识符。
* 保留字 (见 §1.3) **禁止** 用作标识符。
### 1.2 分隔符与强制空白
相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例:
```snow
module: Foo // 推荐
module:Foo // 不推荐
```
### 1.3 保留关键字
```
module import end module globals struct end struct
function end function params returns body end body
declare if then else end if loop init cond step
end loop break continue self
```
以上列表 **均为关键词**,大小写固定,不能作为标识符。
### 1.4 文字量 (Literal)
* **整型**123 0 -42
* **浮点**3.14 0.0
* **布尔**true false
* **字符串**:未来版本保留;当前规范未定义。
### 1.5 注释
* **单行注释**:以 // 起,至当行行尾。
* **多行注释**/* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。
---
### 1.6 换行与缩进
* **只有换行有语义**:以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。
* **缩进没有语义**:缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。
* 块体通过显式关闭关键字(如 end module、end function 等)结束。
* 若关闭关键字与开始关键字之间的缩进不一致,不会报错,仍以关闭关键字为准。
> 块体结构完全由行分隔和显式关闭关键字决定,缩进仅为美观,不影响代码执行。
---
## 2 · 模块与导入
### 2.1 模块声明
```snow
module: <ModuleName>
end module
```
* 一个源文件只能出现 **一次** module: 声明,且文件名与模块名无必然关系。
* 模块名可使用点号(.)分隔表示包层级,例如 util.math。
* **允许** 不同文件夹下声明同名模块,但模块全名(含包路径,用点分隔)在全项目中必须唯一。
* 若项目中出现重复的模块全名,编译阶段将报重定义错误。
例如:
> src/util/math.snow // module: util.math
> src/core/math.snow // module: core.math
>
> 两者都声明了 module: math但由于包路径不同util.math 与 core.math互不冲突。
### 2.2 导入
```snow
import: <ModuleA>⟦ as <AliasA>⟧, <ModuleB>⟦ as <AliasB>⟧, …
```
* **别名 (Alias)** 可为任何合法标识符,放在 as 关键字之后。
* **重复导入**:对同一模块多次导入(无论是否带 alias只解析一次其余忽略告警。
* **循环依赖**:当前规范未定义,若出现编译器可拒绝或延迟解析。
* **子模块**(诸如 A.B暂不支持。
### 2.3 全路径引用
* 跨模块引用必须使用 _Prefix_._Name_其中 *Prefix* 是模块名或导入时的别名。
例如Math.Point 或 M.sin。
* **解析顺序**:未加前缀的标识符只在本模块查找;找不到则视为编译错误,不会隐式搜索导入模块。
---
## 3 · 命名与作用域
### 3.1 作用域层级
1. **模块顶层**:全局变量、结构体、模块级函数。
2. **结构体内部**:字段、方法、构造函数。
3. **函数/方法**:形参与局部变量。
4. **局部嵌套块** (if / loop 等) 的局部变量。
### 3.2 唯一性规则
* **模块顶层唯一**:同一模块的 *结构体名*、*模块级函数名*、*全局变量名* **不得重名**
* **结构体内部**:字段名与方法名不得相同;**允许有多个与结构体名同名的函数(即构造函数重载),但其参数签名必须互不相同。**
* **构造函数重载**:结构体内部可以声明多个与结构体名同名的函数作为构造函数,参数类型与数量必须不同,否则属于 DuplicateName 错误。
* **跨层级遮蔽**:内层可定义与外层同名标识符(除关键字限制外),遵循最近作用域原则。
### 3.3 访问控制约定
* **私有成员与方法**:以单个下划线 `_` 开头的变量名、字段名或方法名,**仅在其所属结构体或模块内部可见**。外部不可访问,编译器应报错 `AccessDenied`
- 例如 `_foo`, `_barMethod`
* **公有成员与方法**:非下划线开头的变量、字段、方法,默认为公有。可在模块外部通过模块名/别名前缀访问。
#### 影响范围
- **模块级变量与函数**`globals``function` 语句声明的以 `_` 开头者,仅限本模块访问。
- **结构体字段与方法**:声明为 `_name``_doSomething` 的,仅结构体本身或其方法体可访问。
---
#### 访问示例
```snow
// module: foo
globals:
declare _secret: int = 42 // 仅 foo 模块内部可见
declare visible: int = 1 // 公有
function: _hidden // 仅 foo 模块内部可见
returns: int
body:
return 100
end body
end function
function: publicFunc
returns: int
body:
return _secret + 1 // 合法
end body
end function
// module: bar
import: foo
declare x: int = foo.visible // 合法
declare y: int = foo._secret // 编译错误 AccessDenied
declare z: int = foo._hidden() // 编译错误 AccessDenied
```
## 4 · 声明语法
### 4.1 全局变量
```snow
globals:
declare VarName: Type ⟦= Expr⟧
```
* 后续对该变量赋值时 **不得** 使用 declare。
### 4.2 结构体
```snow
struct: StructName
declare field1: Type1
declare field2: Type2
// ──────────── 构造函数(可以不存在, 可重载) ──────────────
function: StructName
params:
declare p1: Type1
body:
self.field1 = p1
end body
end function
function: StructName
params:
declare q1: TypeQ
declare q2: TypeQ
body:
// ...
end body
end function
// ...可继续声明更多参数签名各异的构造函数...
// ─────────────────────────────────────────────
// ────────── 结构体内函数 (可以不存在) ──────────
function: method1
⟦params:
declare x: TypeX
…⟧
returns: ReturnType
body:
end body
end function
// ─────────────────────────────────────────────
end struct
```
**实例化**
* declare p: Point = Point(1, 2)
* declare p2: Point = Point(3)
- 实参顺序 = 构造函数 params: 声明顺序;与字段声明顺序无关。
- **构造函数重载时**,调用 Point(...) 时根据参数数量和类型匹配唯一的构造函数。若无匹配或多重匹配,则为编译错误。
- 不支持命名实参、缺省实参或字段名字面量初始化。
### 4.3 函数
```snow
function: FuncName
returns: Type // 无返回值的时候写 void
⟦params:
declare x: TypeX // 无参数的时候不写 params
…⟧
body:
end body
end function
```
* **返回检查**:若 returns: 指定类型非 void所有控制流路径必须显式 return 该类型值。
* 在 loop 内或经 break 跳出后能到达的路径亦计入检查;若缺失,编译错误。
---
## 5 · 语句
### 5.1 变量声明与赋值
```snow
declare x: int = 0
x = 1
```
* 同一作用域中 declare 仅能出现一次。
### 5.2 条件语句
```snow
if Condition then
else
end if
```
* Condition 类型必须为 bool。
### 5.3 循环语句
```snow
loop:
init:
declare i: int = 0
cond:
i < 10
step:
i = i + 1
body:
end body
end loop
```
* **作用域**init 块声明的变量仅在本 loop 的 init/cond/step/body 有效。
* break 立即终止当前循环continue 跳过剩余 body执行 step → cond。
---
## 6 · 类型系统
### 6.1 数值类型
Snow-Lang 支持下列**数值类型**,用于声明变量、参数、结构体字段、函数返回等:
| 类型名 | 关键字 | 位数 | 描述 |
|----------|--------|----|---------------------------|
| byte8 | byte | 8 | 8 位有符号整数 |
| short16 | short | 16 | 16 位有符号整数 |
| int32 | int | 32 | 32 位有符号整数(默认整数类型) |
| long64 | long | 64 | 64 位有符号整数 |
| float32 | float | 32 | 32 位 IEEE-754 浮点数 |
| double64 | double | 64 | 64 位 IEEE-754 浮点数(默认浮点类型) |
**说明**
* 没有无符号整型,所有整型均为有符号。
* `int` 为整数常量与变量的默认类型。
* `double` 为浮点常量与变量的默认类型。
* `bool` 类型只表示真/假,不允许与数值类型直接互转。
#### 数值字面量后缀
为指定具体类型,可在数值字面量后加后缀字母(大小写均可):
| 后缀 | 类型 | 例子 |
|----|--------|----------|
| b | byte | 7b, -2B |
| s | short | 123s |
| i | int | 100i |
| l | long | 5l, 123L |
| f | float | 3.14f |
| d | double | 1.0d |
- 没有后缀的整数字面量自动为 `int`
- 没有后缀的浮点字面量自动为 `double`
**示例:**
```snow
declare a: int = 7 // int (默认)
declare b: long = 9l // long
declare c: float = 2.5f // float
declare d: double = 2.5 // double (默认)
declare e: byte = 127b // byte
declare f: short = 100s // short
````
---
### 6.2 布尔类型
* 关键字为 `bool`
* 字面量为 `true``false`
* 仅用于逻辑判断、条件分支,不与整型互转
---
### 6.3 数组类型
支持一维和多维数组。数组类型以 `T[]` 表示元素类型为 T 的一维数组,多维数组以 `T[][]``T[][][]` 依次类推。
#### 声明与初始化
````snow
declare arr: int[] = [1, 2, 3]
declare matrix: double[][] = [
[1.1, 2.2],
[3.3, 4.4]
]
declare cube: bool[][][] = [
[[true, false], [false, true]],
[[false, false], [true, true]]
]
````
#### 访问与赋值
````snow
arr[0] = 10
matrix[1][1] = 5.6
declare x: int = arr[2]
declare y: double = matrix[0][1]
````
---
### 6.4 结构体类型
* 使用 `struct` 关键字声明
* 结构体类型为用户自定义类型,**值类型**(赋值、传参时会拷贝整个结构体)
* 字段类型可以为任何合法类型(包括数组、其它结构体)
````snow
struct: Point
declare x: int
declare y: int
end struct
declare a: Point = Point(1, 2)
````
---
### 6.5 传值说明
* **所有变量、参数、返回值**均为**值传递**(按值拷贝)
* 结构体、数组在赋值与传参时,均会复制整个值;后续修改不会影响原对象
---
## 7 · 名字解析算法(概览)
1. **输入**:未限定前缀的标识符 N当前作用域 S。
2. 自内向外遍历作用域链查找 N首次匹配即确定绑定。
3. 若遍历至模块顶层仍未匹配,编译错误 *UnresolvedIdentifier*
4. 限定名 Prefix.N直接在模块表中查 Prefix包括别名成功后在该模块顶层查找 N找不到即 *UnresolvedQualifiedIdentifier*
---
## 8 · 编译单位与入口
* **单一入口**:编译器需指定某模块某函数作为启动入口。
* **模块初始化**globals 块中的带初值变量在程序启动时自顶向下按出现顺序初始化;不同模块按依赖拓扑顺序初始化(循环依赖未定义)。
---
## 9 · 错误分类
| 编译期错误代码 | 产生条件 |
|----------------------|----------------------------|
| DuplicateName | 违反唯一性规则;结构体内有参数签名完全相同的构造函数 |
| UnresolvedIdentifier | 名字无法解析 |
| ReturnMissing | 非 void 函数缺少 return |
| TypeMismatch | 赋值或返回类型不兼容 |
| ImportCycle | (可选)检测到循环依赖 |
| CtorAmbiguous | 构造函数重载时参数匹配不唯一 |
| CtorNotFound | 构造函数重载时无匹配参数签名 |
| AccessDenied | 访问了以 `_` 开头的私有变量或方法但不在允许范围 |
---
## 10 · 完整示例
````snow
module: RectExample
import: Geometry
struct: Point
declare x: int
declare y: int
// 构造函数1两个参数
function: Point
params:
declare x: int
declare y: int
body:
self.x = x
self.y = y
end body
end function
// 构造函数2一个参数
function: Point
params:
declare xy: int
body:
self.x = xy
self.y = xy
end body
end function
end struct
struct: Rectangle
declare left_top: Point
declare right_bottom: Point
function: Rectangle
params:
declare x1: int
declare y1: int
declare x2: int
declare y2: int
body:
self.left_top = Point(x1, y1)
self.right_bottom = Point(x2, y2)
end body
end function
function: Rectangle
params:
declare width: int
declare height: int
body:
self.left_top = Point(0, 0)
self.right_bottom = Point(width, height)
end body
end function
function: width
returns: int
body:
return self.right_bottom.x - self.left_top.x
end body
end function
function: height
returns: int
body:
return self.right_bottom.y - self.left_top.y
end body
end function
function: area
returns: int
body:
return self.width() * self.height()
end body
end function
end struct
function: main
returns: int
body:
declare rect1: Rectangle = Rectangle(0, 0, 10, 10)
declare rect2: Rectangle = Rectangle(5, 6)
declare result: int = 0
if rect1.area() > 50 then
loop:
init:
declare i: int = 1
cond:
i <= rect1.width()
step:
i = i + 1
body:
if i == 3 then
continue
end if
if i == 8 then
break
end if
result = result + i
end body
end loop
else
result = rect1.area()
end if
return result
end body
end function
end module
````
---
## 11 · 构造函数重载示例
**示例:**
````snow
struct: Point
declare x: int
declare y: int
function: Point
params:
declare x: int
declare y: int
body:
self.x = x
self.y = y
end body
end function
function: Point
params:
declare xy: int
body:
self.x = xy
self.y = xy
end body
end function
end struct
declare a: Point = Point(1, 2) // 匹配第一个构造函数
declare b: Point = Point(5) // 匹配第二个构造函数
````

View File

@ -102,14 +102,14 @@ x = y + 1
if 语句的形式如下else 是可选的:
```snow
if condition then
if cond then
// 条件成立执行的代码
else
// 以上条件不成立执行的代码
end if
```
condition 可以是表达式(结果为 bool 类型)或者 bool 字面量
cond 可以是表达式(结果为 bool 类型)或者 bool 字面量
例:
@ -134,14 +134,14 @@ end module
loop 语句的形式如下:
```snow
loop:
initializer:
init:
// 循环开始前可声明循环变量,有且只能声明一个
declare i: int = 1
condition:
cond:
// 循环条件,成立则执行 body 的代码,
// 不成立则退出循环,有且只能写一条
i <= 100
update:
step:
// 循环体执行完后执行的代码,有且只能写一条
i = i + 1
body:
@ -158,11 +158,11 @@ module: Main
body:
declare sum: int = 0
loop:
initializer:
init:
declare i: int = 1
condition:
cond:
i <= 100
update:
step:
i = i + 1
body:
sum = sum + i

View File

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

View File

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

View File

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

View File

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

View File

@ -155,18 +155,18 @@ public class StatementBuilder {
* @param loop 循环节点
*/
private void buildLoop(LoopNode loop) {
if (loop.initializer() != null) build(loop.initializer());
if (loop.init() != null) build(loop.init());
String lblStart = ctx.newLabel();
String lblEnd = ctx.newLabel();
// 循环开始标签
InstructionFactory.label(ctx, lblStart);
// 条件不满足则跳出循环
emitConditionalJump(loop.condition(), lblEnd);
emitConditionalJump(loop.cond(), lblEnd);
// 构建循环体
buildStatements(loop.body());
// 更新部分 for i++
if (loop.update() != null) build(loop.update());
if (loop.step() != null) build(loop.step());
// 跳回循环起点
InstructionFactory.jmp(ctx, lblStart);

View File

@ -25,7 +25,7 @@ public class TokenFactory {
/**
* 语言的保留关键字集合
*/
private static final Set<String> KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "initializer", "condition", "update");
private static final Set<String> KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "init", "cond", "step");
/**
* 内置类型名称集合 intstring

View File

@ -14,16 +14,16 @@ import java.util.List;
* 每一部分均对应为 AST 中的子节点便于进一步语义分析与代码生成
* </p>
*
* @param initializer 在循环开始前执行的初始化语句
* @param condition 每次迭代前评估的条件表达式控制循环是否继续
* @param update 每轮迭代完成后执行的更新语句
* @param init 在循环开始前执行的初始化语句
* @param cond 每次迭代前评估的条件表达式控制循环是否继续
* @param step 每轮迭代完成后执行的更新语句
* @param body 循环体语句列表表示循环主体执行逻辑
* @param context 节点的上下文信息包含行号列号文件名等
*/
public record LoopNode(
StatementNode initializer,
ExpressionNode condition,
StatementNode update,
StatementNode init,
ExpressionNode cond,
StatementNode step,
List<StatementNode> body,
NodeContext context
) implements StatementNode {

View File

@ -86,9 +86,9 @@ public class ASTPrinter {
case AssignmentNode(String variable, ExpressionNode value, NodeContext _) ->
System.out.println(pad + variable + " = " + value);
case IfNode(
ExpressionNode condition, List<StatementNode> thenBranch, List<StatementNode> elseBranch, NodeContext _
ExpressionNode cond, List<StatementNode> thenBranch, List<StatementNode> elseBranch, NodeContext _
) -> {
System.out.println(pad + "if " + condition);
System.out.println(pad + "if " + cond);
for (StatementNode stmt : thenBranch) {
print(stmt, indent + 1);
}
@ -100,13 +100,13 @@ public class ASTPrinter {
}
}
case LoopNode(
StatementNode initializer, ExpressionNode condition, StatementNode update, List<StatementNode> body,
StatementNode init, ExpressionNode cond, StatementNode step, List<StatementNode> body,
NodeContext _
) -> {
System.out.println(pad + "loop {");
print(initializer, indent + 1);
System.out.println(pad + " condition: " + condition);
System.out.println(pad + " update: " + update);
print(init, indent + 1);
System.out.println(pad + " cond: " + cond);
System.out.println(pad + " step: " + step);
System.out.println(pad + " body {");
for (StatementNode stmt : body) {
print(stmt, indent + 2);

View File

@ -24,23 +24,23 @@ import java.util.Map;
* 该语法结构参考了传统的 for-loop并将其拆解为命名的语义区块
* <pre>{@code
* loop:
* initializer:
* declare i:int = 0
* condition:
* init:
* declare i: int = 0
* cond:
* i < 10
* update:
* step:
* i = i + 1
* body:
* print(i)
*
* end body
* end loop
* }</pre>
*
* 各区块说明
* <ul>
* <li>{@code initializer}初始化语句通常为变量声明</li>
* <li>{@code condition}循环判断条件必须为布尔或数值表达式</li>
* <li>{@code update}每轮执行后更新逻辑通常为赋值语句</li>
* <li>{@code init}初始化语句通常为变量声明</li>
* <li>{@code cond}循环判断条件必须为布尔或数值表达式</li>
* <li>{@code step}每轮执行后更新逻辑通常为赋值语句</li>
* <li>{@code body}主执行语句块支持任意多条语句</li>
* </ul>
* 本类依赖 {@link FlexibleSectionParser} 实现各区块的统一处理确保结构明确可扩展
@ -75,49 +75,49 @@ public class LoopStatementParser implements StatementParser {
ParserUtils.matchHeader(ts, "loop");
// 使用数组模拟引用以便在 lambda 中写入Java 不支持闭包内修改局部变量
final StatementNode[] initializer = new StatementNode[1];
final ExpressionNode[] condition = new ExpressionNode[1];
final AssignmentNode[] update = new AssignmentNode[1];
final StatementNode[] init = new StatementNode[1];
final ExpressionNode[] cond = new ExpressionNode[1];
final AssignmentNode[] step = new AssignmentNode[1];
final List<StatementNode> body = new ArrayList<>();
// 定义各命名区块的识别与处理逻辑
Map<String, FlexibleSectionParser.SectionDefinition> sections = new HashMap<>();
// initializer 区块仅支持一条语句通常为 declare
sections.put("initializer", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("initializer"),
// init 区块仅支持一条语句通常为 declare
sections.put("init", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("init"),
(ctx1, ts1) -> {
ParserUtils.matchHeader(ts1, "initializer");
initializer[0] = StatementParserFactory.get(ts1.peek().getLexeme()).parse(ctx1);
ParserUtils.matchHeader(ts1, "init");
init[0] = StatementParserFactory.get(ts1.peek().getLexeme()).parse(ctx1);
ParserUtils.skipNewlines(ts1);
}
));
// condition 区块支持任意可解析为布尔的表达式
sections.put("condition", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("condition"),
// cond 区块支持任意可解析为布尔的表达式
sections.put("cond", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("cond"),
(ctx1, ts1) -> {
ParserUtils.matchHeader(ts1, "condition");
condition[0] = new PrattExpressionParser().parse(ctx1);
ParserUtils.matchHeader(ts1, "cond");
cond[0] = new PrattExpressionParser().parse(ctx1);
ts1.expectType(TokenType.NEWLINE);
ParserUtils.skipNewlines(ts1);
}
));
// update 区块目前仅支持单一变量赋值语句
sections.put("update", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("update"),
// step 区块目前仅支持单一变量赋值语句
sections.put("step", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("step"),
(ctx1, ts1) -> {
// 获取当前 token 的行号列号
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
ParserUtils.matchHeader(ts1, "update");
ParserUtils.matchHeader(ts1, "step");
String varName = ts1.expectType(TokenType.IDENTIFIER).getLexeme();
ts1.expect("=");
ExpressionNode expr = new PrattExpressionParser().parse(ctx1);
ts1.expectType(TokenType.NEWLINE);
update[0] = new AssignmentNode(varName, expr, new NodeContext(line, column, file));
step[0] = new AssignmentNode(varName, expr, new NodeContext(line, column, file));
ParserUtils.skipNewlines(ts1);
}
));
@ -151,6 +151,6 @@ public class LoopStatementParser implements StatementParser {
ParserUtils.matchFooter(ts, "loop");
// 返回构造完成的 LoopNode
return new LoopNode(initializer[0], condition[0], update[0], body, new NodeContext(loop_line, loop_column, file));
return new LoopNode(init[0], cond[0], step[0], body, new NodeContext(loop_line, loop_column, file));
}
}

View File

@ -121,7 +121,7 @@ public class ASTJsonSerializer {
Map<String, Object> map = newNodeMap("Declaration");
map.put("name", d.getName());
map.put("varType", d.getType());
map.put("initializer", d.getInitializer().map(ASTJsonSerializer::exprToMap).orElse(null));
map.put("init", d.getInitializer().map(ASTJsonSerializer::exprToMap).orElse(null));
yield map;
}
// 赋值语句节点
@ -132,7 +132,7 @@ public class ASTJsonSerializer {
// 条件语句节点
case IfNode i -> {
Map<String, Object> map = newNodeMap("If");
map.put("condition", exprToMap(i.condition()));
map.put("cond", exprToMap(i.condition()));
List<Object> thenList = new ArrayList<>(i.thenBranch().size());
for (Node stmt : i.thenBranch()) thenList.add(nodeToMap(stmt));
map.put("then", thenList);
@ -146,9 +146,9 @@ public class ASTJsonSerializer {
// 循环语句节点
case LoopNode l -> {
Map<String, Object> map = newNodeMap("Loop");
map.put("initializer", l.initializer() != null ? nodeToMap(l.initializer()) : null);
map.put("condition", l.condition() != null ? exprToMap(l.condition()) : null);
map.put("update", l.update() != null ? nodeToMap(l.update()) : null);
map.put("init", l.init() != null ? nodeToMap(l.init()) : null);
map.put("cond", l.cond() != null ? exprToMap(l.cond()) : null);
map.put("step", l.step() != null ? nodeToMap(l.step()) : null);
List<Object> body = new ArrayList<>(l.body().size());
for (Node stmt : l.body()) body.add(nodeToMap(stmt));
map.put("body", body);

View File

@ -25,7 +25,7 @@ public class ParserUtils {
* 若格式不匹配将抛出语法异常
*
* @param ts 当前的 token
* @param keyword 结构起始关键字 "loop", "function", "initializer"
* @param keyword 结构起始关键字 "loop", "function", "init"
*/
public static void matchHeader(TokenStream ts, String keyword) {
ts.expect(keyword); // 匹配关键字

View File

@ -44,24 +44,24 @@ public class LoopAnalyzer implements StatementAnalyzer<LoopNode> {
// 新建 loopScope以支持循环内部变量声明与外部隔离
SymbolTable loopScope = new SymbolTable(locals);
// 2. 分析初始化语句 for(i=0)使用 loopScope 作为作用域
var initAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.initializer());
// 2. 分析初始化语句
var initAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.init());
if (initAnalyzer != null) {
initAnalyzer.analyze(ctx, mi, fn, loopScope, ln.initializer());
initAnalyzer.analyze(ctx, mi, fn, loopScope, ln.init());
}
// 3. 分析条件表达式 for(...; cond; ...) while(cond)
var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.condition());
Type condType = condAnalyzer.analyze(ctx, mi, fn, loopScope, ln.condition());
// 3. 分析条件表达式
var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.cond());
Type condType = condAnalyzer.analyze(ctx, mi, fn, loopScope, ln.cond());
// 条件类型必须为 boolean否则记录错误
if (TypeUtils.isLogic(condType)) {
ctx.getErrors().add(new SemanticError(ln, "loop 条件必须为 boolean"));
}
// 4. 分析更新语句 for(...; ...; update)
var updateAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.update());
// 4. 分析更新语句
var updateAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.step());
if (updateAnalyzer != null) {
updateAnalyzer.analyze(ctx, mi, fn, loopScope, ln.update());
updateAnalyzer.analyze(ctx, mi, fn, loopScope, ln.step());
}
// 5. 分析循环体内的每一条语句

View File

@ -39,11 +39,11 @@ public final class SnowExample {
body:
declare num1: int = 1
loop:
initializer:
init:
declare counter:int = 1
condition:
cond:
counter <= n
update:
step:
counter = counter + 1
body:
num1 = num1 * counter