diff --git a/.gitignore b/.gitignore index 21e01df..77c9d91 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ target/ ### Snow 虚拟机指令 ### *.water +/.lingma/ diff --git a/README.md b/README.md index 9df5b5f..8593611 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md new file mode 100644 index 0000000..a529bf4 --- /dev/null +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Grammar-Specification.md.md @@ -0,0 +1,585 @@ +# Snow‑Lang 语法规范 + +--- + +## 0 · 符号约定 + +* ⟦ … ⟧:可选项(0 或 1 次) +* { … }\*:可重复项(0 次或多次) + +--- + +## 1 · 词汇结构 + +### 1.1 编码与字符集 + +源文件采用 UTF‑8 编码。除注释外,标识符只允许英文大小写字母 (A‑Z a‑z)、数字 (0‑9) 与下划线 _;首字符不能为数字。 + +```ebnf +identifier ::= [A-Za-z_][A-Za-z0-9_]* ; +``` + +* **区分大小写**:Foo 与 foo 为不同标识符。 +* 保留字 (见 §1.3) **禁止** 用作标识符。 + +### 1.2 分隔符与强制空白 + +相邻两个标记之间 **推荐** 至少以 1 个空白字符分隔,除非记号本身带有定界符 (( ) , : = < > 等)。示例: + +```snow +module: Foo // 推荐 +module:Foo // 不推荐 +``` + +### 1.3 保留关键字 + +``` +module import end module globals struct end struct +function end function params returns body end body +declare if then else end if loop init cond step +end loop break continue self +``` + +以上列表 **均为关键词**,大小写固定,不能作为标识符。 + +### 1.4 文字量 (Literal) + +* **整型**:123 0 -42 +* **浮点**:3.14 0.0 +* **布尔**:true false +* **字符串**:未来版本保留;当前规范未定义。 + +### 1.5 注释 + +* **单行注释**:以 // 起,至当行行尾。 +* **多行注释**:/* … */ 可跨行。**不可嵌套**;嵌套会在最内层 */ 处终止外层,导致编译错误。 + +--- + +### 1.6 换行与缩进 + +* **只有换行有语义**:以行末冒号(:)打开一个块时(如 module:、function:、if、loop: 等),块体**必须另起新行**。 +* **缩进没有语义**:缩进仅用于提高代码可读性,对语法无影响。缩进不一致不会报错。 +* 块体通过显式关闭关键字(如 end module、end function 等)结束。 +* 若关闭关键字与开始关键字之间的缩进不一致,不会报错,仍以关闭关键字为准。 + +> 块体结构完全由行分隔和显式关闭关键字决定,缩进仅为美观,不影响代码执行。 + +--- + +## 2 · 模块与导入 + +### 2.1 模块声明 + +```snow +module: + … +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: ⟦ as ⟧, ⟦ as ⟧, … +``` + +* **别名 (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) // 匹配第二个构造函数 +```` \ No newline at end of file diff --git a/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md b/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md index 265b4b1..2ac5fdd 100644 --- a/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md +++ b/docs/Snow-Lang-Syntax/Snow-Lang-Syntax.md @@ -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 diff --git a/lib/math/factorial/factorial.snow b/lib/math/factorial/factorial.snow index 46749dd..82a6dbf 100644 --- a/lib/math/factorial/factorial.snow +++ b/lib/math/factorial/factorial.snow @@ -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 diff --git a/lib/test/Dead_loop.snow b/lib/test/Dead_loop.snow index 5f73bfb..f2a1a98 100644 --- a/lib/test/Dead_loop.snow +++ b/lib/test/Dead_loop.snow @@ -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: diff --git a/playground/Demo/Demo5/Main.snow b/playground/Demo/Demo5/Main.snow index 75ae75f..c475980 100644 --- a/playground/Demo/Demo5/Main.snow +++ b/playground/Demo/Demo5/Main.snow @@ -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: diff --git a/playground/Demo/Demo9/Main.snow b/playground/Demo/Demo9/Main.snow index 46749dd..82a6dbf 100644 --- a/playground/Demo/Demo9/Main.snow +++ b/playground/Demo/Demo9/Main.snow @@ -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 diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java index 30d672a..7472269 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java @@ -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); diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java index e6463f4..e94c54b 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java @@ -25,7 +25,7 @@ public class TokenFactory { /** * 语言的保留关键字集合。 */ - private static final Set KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "initializer", "condition", "update"); + private static final Set KEYWORDS = Set.of("module", "function", "parameter", "return_type", "body", "end", "if", "then", "else", "loop", "declare", "return", "import", "init", "cond", "step"); /** * 内置类型名称集合,如 int、string 等。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java index 2ba283e..153352c 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java @@ -14,16 +14,16 @@ import java.util.List; * 每一部分均对应为 AST 中的子节点,便于进一步语义分析与代码生成。 *

* - * @param initializer 在循环开始前执行的初始化语句 - * @param condition 每次迭代前评估的条件表达式,控制循环是否继续 - * @param update 每轮迭代完成后执行的更新语句 - * @param body 循环体语句列表,表示循环主体执行逻辑 - * @param context 节点的上下文信息(包含行号、列号、文件名等) + * @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 body, NodeContext context ) implements StatementNode { diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java index c12edb3..91ed077 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java @@ -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 thenBranch, List elseBranch, NodeContext _ + ExpressionNode cond, List thenBranch, List 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 body, + StatementNode init, ExpressionNode cond, StatementNode step, List 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); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java index c1a9c66..7ffeb74 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java @@ -24,23 +24,23 @@ import java.util.Map; * 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块: *
{@code
  * loop:
- *   initializer:
- *     declare i:int = 0
- *   condition:
- *     i < 10
- *   update:
- *     i = i + 1
- *   body:
- *     print(i)
- * end body
+ *     init:
+ *         declare i: int = 0
+ *     cond:
+ *         i < 10
+ *     step:
+ *         i = i + 1
+ *     body:
+ *         …
+ *     end body
  * end loop
  * }
* * 各区块说明: *
    - *
  • {@code initializer}:初始化语句,通常为变量声明。
  • - *
  • {@code condition}:循环判断条件,必须为布尔或数值表达式。
  • - *
  • {@code update}:每轮执行后更新逻辑,通常为赋值语句。
  • + *
  • {@code init}:初始化语句,通常为变量声明。
  • + *
  • {@code cond}:循环判断条件,必须为布尔或数值表达式。
  • + *
  • {@code step}:每轮执行后更新逻辑,通常为赋值语句。
  • *
  • {@code body}:主执行语句块,支持任意多条语句。
  • *
* 本类依赖 {@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 body = new ArrayList<>(); // 定义各命名区块的识别与处理逻辑 Map 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)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java index 278a42c..51ba838 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java @@ -121,7 +121,7 @@ public class ASTJsonSerializer { Map 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 map = newNodeMap("If"); - map.put("condition", exprToMap(i.condition())); + map.put("cond", exprToMap(i.condition())); List 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 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 body = new ArrayList<>(l.body().size()); for (Node stmt : l.body()) body.add(nodeToMap(stmt)); map.put("body", body); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java index f20b7c6..3677caf 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java @@ -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); // 匹配关键字 diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java index a00d993..064d059 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/LoopAnalyzer.java @@ -44,24 +44,24 @@ public class LoopAnalyzer implements StatementAnalyzer { // 新建 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. 分析循环体内的每一条语句 diff --git a/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java b/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java index ffd18d1..7358487 100644 --- a/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java +++ b/src/main/java/org/jcnc/snow/pkg/utils/SnowExample.java @@ -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