!5 feature: 支持boolean类型与适配loop和if条件为新的boolean
Merge pull request !5 from Luke/feat/add-boolean-type
This commit is contained in:
commit
cc29e40cb1
17
.run/Demo1.run.xml
Normal file
17
.run/Demo1.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo1" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo1" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Demo2.run.xml
Normal file
17
.run/Demo2.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo2" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo2" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Demo3.run.xml
Normal file
17
.run/Demo3.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo3" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo3" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Demo4.run.xml
Normal file
17
.run/Demo4.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo4" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo4" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Demo5.run.xml
Normal file
17
.run/Demo5.run.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Demo5" type="Application" factoryName="Application" folderName="Demo" activateToolWindowBeforeRun="false">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground/Demo5" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@ -1,7 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run" type="CompoundRunConfigurationType">
|
||||
<toRun name="build_project2tar.ps1" type="PowerShellRunType" />
|
||||
<toRun name="SnowCompiler" type="Application" />
|
||||
<toRun name="Demo1" type="Application" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@ -1,32 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="SnowCompiler" type="Application" factoryName="Application" activateToolWindowBeforeRun="false" nameIsGenerated="true">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="SCompiler" />
|
||||
<option name="PROGRAM_PARAMETERS" value="test" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="false" name="SnowCompiler" type="Application" factoryName="Application" activateToolWindowBeforeRun="false" nameIsGenerated="true">
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="graalvm-ce-23" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.compiler.cli.SnowCompiler" />
|
||||
<module name="Snow" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-d playground" />
|
||||
<extension name="coverage">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jcnc.snow.compiler.parser.preprocessor.lexer.impl.api.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@ -329,12 +329,9 @@ end module
|
||||
|
||||
[Git 管理规范](doc/Git-Management/Git-Management.md)
|
||||
|
||||
## 开发计划 / TODO
|
||||
## 开发计划
|
||||
|
||||
* 扩展标准库支持和更多内置模块,如字符串,文件操作等常用功能。
|
||||
* 增强类型系统和错误检查,完善编译时诊断信息。
|
||||
* 优化 IR 和虚拟机性能,实现更多优化策略(如常量折叠等)。
|
||||
* 增加更多示例程序试,丰富项目文档和用例。
|
||||
[Snow 语言现状和下一阶段开发路线图-2025-06-11](doc/Snow's-current-language-situation-and-the-development-roadmap-for-the-next-stage/Snow's-current-language-situation-and-the-development-roadmap-for-the-next-stage.md)
|
||||
|
||||
## 加入我们
|
||||
* 微信: `xuxiaolankaka`
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
# Snow 语言现状和下一阶段开发路线图
|
||||
|
||||
> 日期:2025-06-11
|
||||
|
||||
## 1. 代码结构与职责
|
||||
| 层次 | 主要包/目录 | 说明 |
|
||||
|--------|--------------------------|--------------------------------------------------------|
|
||||
| 词法分析 | `snow/compiler/lexer` | 扫描器(Scanner)+ `TokenFactory`,可识别关键字、运算符、数字/字符串字面量等 |
|
||||
| 语法分析 | `snow/compiler/parser` | Pratt 表达式解析器 + 各类语句解析器(声明、`if`、`loop`、`return`…)生成 AST |
|
||||
| 语义分析 | `snow/compiler/semantic` | 符号表、类型系统(`BuiltinType`/`FunctionType`)与各节点分析器 |
|
||||
| IR 构建 | `snow/compiler/ir` | SSA-风格中间表示、指令集、构建器 |
|
||||
| 后端生成 | `snow/compiler/backend` | IR ➜ VM 指令的 `*Generator` 体系、寄存器分配 |
|
||||
| 运行时 VM | `snow/vm` | 指令集实现(栈/寄存器/内存/控制流/函数)+ 启动器 |
|
||||
|
||||
### 2 编译流程
|
||||
|
||||
1. **Lexer** 将源码映射为 `TokenStream`
|
||||
2. **Parser** 生成 AST(19 种节点)
|
||||
3. **Semantic**
|
||||
|
||||
* 类型推断 / 兼容性校验
|
||||
* 符号绑定与引用解析
|
||||
4. **IR**
|
||||
|
||||
* 虚拟寄存器 + 基本块 + 统一指令(算术、比较、跳转、调用、返回…)
|
||||
5. **Backend**
|
||||
|
||||
* 线性扫描寄存器分配
|
||||
* 指令生成器把 IR 转为 VM 指令
|
||||
6. **VM**
|
||||
|
||||
* 栈-基 / 寄存器混合架构
|
||||
* 96 条已实现指令(按数据宽度泛化:B/S/I/L/F/D)
|
||||
* 运行时启动器 `VMLauncher`
|
||||
|
||||
|
||||
## 3. 测试中存在的问题记录
|
||||
|
||||
| 模块 | 现状 |
|
||||
|----------------|---------------------------------------------------------------|
|
||||
| **布尔类型** | 词法已识别 `bool`,但 `BuiltinType` 中缺失;比较运算目前回落为 `int` 0/1 |
|
||||
| **一元/前缀运算** | VM 与 IR 有 `UnaryOperationInstruction`,Parser 未注册 `-x`, `!x` 等 |
|
||||
| **数组/切片/Map** | 无 AST/Type/IR 支持 |
|
||||
| **结构体 / 面向对象** | 无 结构体、对象 节点 |
|
||||
| **异常处理** | 无 try/catch 指令或语义 |
|
||||
| **优化 Pass** | 未见常量折叠 / 死代码删除等 |
|
||||
| **标准库 & I/O** | 仅语言核心,无文件/网络/控制台 API |
|
||||
| **测试矩阵** | 单元测试缺失,e2e 样例有限 |
|
||||
| **CLI/包管理** | 缺少 `snowc` 命令与包版本语义 |
|
||||
|
||||
## 4. 下一阶段开发路线图
|
||||
|
||||
> 优先级:P0 = 当前版本必须,P1 = 下一个小版本,P2 = 中长期
|
||||
|
||||
| 优先级 | 功能 | 关键任务 |
|
||||
|--------|------------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
| **P0** | **布尔类型落地** | \* 在 `BuiltinType` 中补充 `BOOL`<br>\* 更新 `TokenFactory.TYPES` 映射<br>\* 比较/逻辑运算返回 `bool` 类型<br>\* VM 增加布尔专用指令或重用 `byte` |
|
||||
| **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 虚表 |
|
||||
| **P2** | **优化管线** | \* 常量折叠、公共子表达式消除<br>\* 简易死代码清除 |
|
||||
| **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**:异常系统、稳定包管理、文档完善 |
|
||||
@ -8,4 +8,4 @@ module: Math
|
||||
return n1+n2
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
end module
|
||||
9
playground/Demo2/Main.snow
Normal file
9
playground/Demo2/Main.snow
Normal file
@ -0,0 +1,9 @@
|
||||
module: Main
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
return (1+2) / 3 * 4 + 2 *2
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
17
playground/Demo3/Main.snow
Normal file
17
playground/Demo3/Main.snow
Normal file
@ -0,0 +1,17 @@
|
||||
module: Main
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
declare n1: int =1
|
||||
declare n2: int =2
|
||||
declare n3: int =1
|
||||
if n1 ==1 then
|
||||
if n2 ==2 then
|
||||
n3 =3
|
||||
end if
|
||||
end if
|
||||
return n3
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
12
playground/Demo4/Main.snow
Normal file
12
playground/Demo4/Main.snow
Normal file
@ -0,0 +1,12 @@
|
||||
module: Main
|
||||
function: main
|
||||
parameter:
|
||||
return_type: boolean
|
||||
body:
|
||||
declare b1: boolean =true
|
||||
|
||||
|
||||
return b1
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
21
playground/Demo5/Main.snow
Normal file
21
playground/Demo5/Main.snow
Normal file
@ -0,0 +1,21 @@
|
||||
module: Main
|
||||
function: main
|
||||
parameter:
|
||||
return_type: int
|
||||
body:
|
||||
declare b1: boolean = true
|
||||
loop:
|
||||
initializer:
|
||||
declare i:int = 0
|
||||
condition:
|
||||
b1
|
||||
update:
|
||||
i = i + 1
|
||||
body:
|
||||
|
||||
end body
|
||||
end loop
|
||||
return 0
|
||||
end body
|
||||
end function
|
||||
end module
|
||||
6
pom.xml
6
pom.xml
@ -41,7 +41,13 @@
|
||||
<phase>test</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<buildArgs>
|
||||
<buildArg>--emit build-report</buildArg>
|
||||
</buildArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
|
||||
@ -64,6 +64,7 @@ public class LoadConstGenerator implements InstructionGenerator<LoadConstInstruc
|
||||
case Byte _ -> 'B'; // 字节型
|
||||
case Double _ -> 'D'; // 双精度浮点型
|
||||
case Float _ -> 'F'; // 单精度浮点型
|
||||
case Boolean _ -> 'I'; // 布尔(作为 0/1 整型存储)
|
||||
case null, default ->
|
||||
throw new IllegalStateException("Unknown const type: " + (value != null ? value.getClass() : null));
|
||||
};
|
||||
|
||||
@ -82,7 +82,7 @@ public final class IROpCodeMapper {
|
||||
opcodeMap.put(IROpCode.NEG_D64, "D_NEG");
|
||||
|
||||
// 比较运算映射
|
||||
opcodeMap.put(IROpCode.CMP_EQ, "IC_EQ"); // 相等
|
||||
opcodeMap.put(IROpCode.CMP_EQ, "IC_E"); // 相等
|
||||
opcodeMap.put(IROpCode.CMP_NE, "IC_NE"); // 不等
|
||||
opcodeMap.put(IROpCode.CMP_LT, "IC_L"); // 小于
|
||||
opcodeMap.put(IROpCode.CMP_GT, "IC_G"); // 大于
|
||||
|
||||
@ -44,23 +44,27 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
*/
|
||||
public IRVirtualRegister build(ExpressionNode expr) {
|
||||
return switch (expr) {
|
||||
// 数字字面量,如 "123", "1.0f"
|
||||
// 数字字面量
|
||||
case NumberLiteralNode n -> buildNumberLiteral(n.value());
|
||||
// 标识符,如变量x,直接查作用域
|
||||
// 布尔字面量
|
||||
case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
|
||||
// 标识符
|
||||
case IdentifierNode id -> {
|
||||
IRVirtualRegister reg = ctx.getScope().lookup(id.name());
|
||||
if (reg == null) throw new IllegalStateException("未定义标识符: " + id.name());
|
||||
if (reg == null)
|
||||
throw new IllegalStateException("未定义标识符: " + id.name());
|
||||
yield reg;
|
||||
}
|
||||
// 二元表达式,如 "a + b"
|
||||
// 二元表达式
|
||||
case BinaryExpressionNode bin -> buildBinary(bin);
|
||||
// 函数调用,如 foo(a, b)
|
||||
// 函数调用
|
||||
case CallExpressionNode call -> buildCall(call);
|
||||
// 其它不支持
|
||||
default -> throw new IllegalStateException("不支持的表达式类型: " + expr.getClass().getSimpleName());
|
||||
default -> throw new IllegalStateException(
|
||||
"不支持的表达式类型: " + expr.getClass().getSimpleName());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 直接将表达式计算结果写入指定的目标寄存器(dest)。
|
||||
* <p>
|
||||
@ -91,8 +95,6 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 内部私有方法 =====================
|
||||
|
||||
/**
|
||||
* 构建二元表达式的IR,生成新寄存器存储结果。
|
||||
* <p>
|
||||
@ -179,4 +181,12 @@ public record ExpressionBuilder(IRContext ctx) {
|
||||
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
||||
return reg;
|
||||
}
|
||||
|
||||
/** 布尔字面量 → CONST (true=1,false=0)*/
|
||||
private IRVirtualRegister buildBoolLiteral(boolean value) {
|
||||
IRConstant constant = new IRConstant(value ? 1 : 0);
|
||||
IRVirtualRegister reg = ctx.newRegister();
|
||||
ctx.addInstruction(new LoadConstInstruction(reg, constant));
|
||||
return reg;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,19 +28,12 @@ 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", "initializer", "condition", "update");
|
||||
|
||||
/**
|
||||
* 内置类型名称集合,如 int、string 等。
|
||||
*/
|
||||
private static final Set<String> TYPES = Set.of(
|
||||
"int", "string", "float", "bool", "void", "double", "long", "short", "byte"
|
||||
);
|
||||
private static final Set<String> TYPES = Set.of("int", "string", "float", "boolean", "void", "double", "long", "short", "byte");
|
||||
|
||||
/**
|
||||
* 创建一个根据内容自动推断类型的 {@link Token} 实例。
|
||||
@ -69,15 +62,30 @@ public class TokenFactory {
|
||||
* @return 推断出的 {@link TokenType} 类型
|
||||
*/
|
||||
private static TokenType determineTokenType(String raw) {
|
||||
if (isABoolean(raw)) return TokenType.BOOL_LITERAL;
|
||||
if (isType(raw)) return TokenType.TYPE;
|
||||
if (isKeyword(raw)) return TokenType.KEYWORD;
|
||||
if (isIdentifier(raw)) return TokenType.IDENTIFIER;
|
||||
return TokenType.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定字符串是否为布尔字面量("true" 或 "false")。
|
||||
*
|
||||
* <p>本方法通过字符串比较,判断输入是否严格等于 "true" 或 "false"。</p>
|
||||
*
|
||||
* @param raw 待判断的字符串
|
||||
* @return 若为布尔字面量,则返回 {@code true};否则返回 {@code false}
|
||||
*/
|
||||
private static boolean isABoolean(String raw) {
|
||||
return "true".equals(raw) || "false".equals(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定字符串是否为内置类型标识。
|
||||
*
|
||||
* <p>本方法用于辅助语义分析或类型识别,判断输入字符串是否存在于预定义的类型集合 {@code TYPES} 中。</p>
|
||||
*
|
||||
* @param raw 输入的字符串
|
||||
* @return 若为类型名则返回 {@code true},否则返回 {@code false}
|
||||
*/
|
||||
@ -85,6 +93,7 @@ public class TokenFactory {
|
||||
return TYPES.contains(raw);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断指定字符串是否为语言保留关键字。
|
||||
*
|
||||
|
||||
@ -19,6 +19,8 @@ public enum TokenType {
|
||||
/** 内置类型名称(如 int、string、bool 等) */
|
||||
TYPE,
|
||||
|
||||
/** 布尔字面量 (true / false) */
|
||||
BOOL_LITERAL,
|
||||
/** 字符串字面量(如 "hello") */
|
||||
STRING_LITERAL,
|
||||
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package org.jcnc.snow.compiler.parser.ast;
|
||||
|
||||
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
|
||||
/**
|
||||
* 表示布尔字面量(boolean literal)的抽象语法树(AST)节点。
|
||||
* <p>
|
||||
* 本类实现了 {@link ExpressionNode} 接口,用于在编译器前端构建语法分析过程中,
|
||||
* 表达布尔类型的字面量常量(如 "true" 或 "false")。
|
||||
* </p>
|
||||
*/
|
||||
public class BoolLiteralNode implements ExpressionNode {
|
||||
/**
|
||||
* 字面量的布尔值。
|
||||
*/
|
||||
private final boolean value;
|
||||
|
||||
/**
|
||||
* 使用布尔字面量字符串构造一个 {@code BoolLiteralNode} 实例。
|
||||
* <p>
|
||||
* 本构造方法接受一个字符串词素(lexeme),并通过 {@link Boolean#parseBoolean(String)} 解析为布尔值。
|
||||
* 如果传入的字符串为 "true"(忽略大小写),则解析结果为 {@code true};否则为 {@code false}。
|
||||
* </p>
|
||||
*
|
||||
* @param lexeme 布尔字面量的字符串表示
|
||||
*/
|
||||
public BoolLiteralNode(String lexeme) {
|
||||
this.value = Boolean.parseBoolean(lexeme);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此布尔字面量节点的值。
|
||||
*
|
||||
* @return 布尔值,代表源代码中的布尔字面量
|
||||
*/
|
||||
public boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package org.jcnc.snow.compiler.parser.expression;
|
||||
|
||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||
import org.jcnc.snow.compiler.parser.ast.BoolLiteralNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||
import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
|
||||
|
||||
/**
|
||||
* {@code BoolLiteralParselet} 是用于解析布尔字面量的前缀解析子(prefix parselet)。
|
||||
* <p>
|
||||
* 本类实现了 {@link PrefixParselet} 接口,用于在语法分析阶段将布尔类型的词法单元(如 "true" 或 "false")
|
||||
* 转换为相应的抽象语法树(AST)节点 {@link BoolLiteralNode}。
|
||||
*/
|
||||
public class BoolLiteralParselet implements PrefixParselet {
|
||||
|
||||
/**
|
||||
* 解析布尔字面量的词法单元,并返回对应的布尔字面量节点。
|
||||
* <p>
|
||||
* 本方法被语法分析器在遇到布尔字面量词法单元时调用。
|
||||
* 它将词法单元的词素(lexeme)传递给 {@link BoolLiteralNode} 构造器,
|
||||
* 并返回构造得到的 AST 节点。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 当前的语法分析上下文,用于提供所需的解析信息
|
||||
* @param token 代表布尔字面量的词法单元
|
||||
* @return 对应的 {@link BoolLiteralNode} 实例
|
||||
*/
|
||||
@Override
|
||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||
return new BoolLiteralNode(token.getLexeme());
|
||||
}
|
||||
}
|
||||
@ -43,6 +43,7 @@ public class PrattExpressionParser implements ExpressionParser {
|
||||
prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet());
|
||||
prefixes.put(TokenType.LPAREN.name(), new GroupingParselet());
|
||||
prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet());
|
||||
prefixes.put(TokenType.BOOL_LITERAL.name(), new BoolLiteralParselet());
|
||||
|
||||
// 注册中缀解析器
|
||||
infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true));
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package org.jcnc.snow.compiler.semantic.analyzers;
|
||||
|
||||
import org.jcnc.snow.compiler.semantic.type.BuiltinType;
|
||||
import org.jcnc.snow.compiler.semantic.type.Type;
|
||||
|
||||
/**
|
||||
* 实用类型辅助工具类,提供与类型相关的静态方法。
|
||||
* <p>
|
||||
* 本类为静态工具类,无法被实例化,仅用于类型判断等功能。
|
||||
* </p>
|
||||
*/
|
||||
public final class TypeUtils {
|
||||
/**
|
||||
* 私有构造方法,防止实例化工具类。
|
||||
*/
|
||||
private TypeUtils() {
|
||||
// 工具类不允许被实例化
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定类型是否为“逻辑类型”。
|
||||
* <p>
|
||||
* 当前的实现仅判断类型是否不是布尔类型(BOOLEAN)。
|
||||
* 如果类型不是 BOOLEAN,则认为是“逻辑类型”。
|
||||
* </p>
|
||||
*
|
||||
* @param t 需要检查的类型对象
|
||||
* @return 如果 t 不是 {@link BuiltinType#BOOLEAN},则返回 {@code true},否则返回 {@code false}
|
||||
*/
|
||||
public static boolean isLogic(Type t) {
|
||||
return t != BuiltinType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package org.jcnc.snow.compiler.semantic.analyzers.expression;
|
||||
|
||||
import org.jcnc.snow.compiler.parser.ast.BoolLiteralNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||
import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer;
|
||||
import org.jcnc.snow.compiler.semantic.core.Context;
|
||||
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
||||
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
||||
import org.jcnc.snow.compiler.semantic.type.BuiltinType;
|
||||
import org.jcnc.snow.compiler.semantic.type.Type;
|
||||
|
||||
/**
|
||||
* {@code BoolLiteralAnalyzer} 是布尔字面量表达式的语义分析器。
|
||||
* <p>
|
||||
* 本类实现 {@link ExpressionAnalyzer} 接口,用于在语义分析阶段对 {@link BoolLiteralNode}
|
||||
* 进行类型推断和校验。在此实现中,所有布尔字面量表达式都被直接视为内建布尔类型 {@link BuiltinType#BOOLEAN}。
|
||||
* </p>
|
||||
* <p>
|
||||
* 该分析器不涉及值检查,仅负责返回类型信息,用于后续的类型检查与代码生成阶段。
|
||||
* </p>
|
||||
*/
|
||||
public class BoolLiteralAnalyzer implements ExpressionAnalyzer<BoolLiteralNode> {
|
||||
|
||||
/**
|
||||
* 分析布尔字面量表达式的语义,并返回其类型。
|
||||
* <p>
|
||||
* 由于布尔字面量具有确定且固定的类型,本方法始终返回 {@link BuiltinType#BOOLEAN}。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 当前的语义分析上下文,包含全局编译状态
|
||||
* @param mi 所在模块的信息对象
|
||||
* @param fn 当前分析所在的函数节点
|
||||
* @param locals 当前作用域下的符号表
|
||||
* @param expr 被分析的布尔字面量表达式节点
|
||||
* @return {@link BuiltinType#BOOLEAN},表示布尔类型
|
||||
*/
|
||||
@Override
|
||||
public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn,
|
||||
SymbolTable locals, BoolLiteralNode expr) {
|
||||
return BuiltinType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,12 @@ package org.jcnc.snow.compiler.semantic.analyzers.statement;
|
||||
|
||||
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.IfNode;
|
||||
import org.jcnc.snow.compiler.semantic.analyzers.TypeUtils;
|
||||
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
|
||||
import org.jcnc.snow.compiler.semantic.core.Context;
|
||||
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
||||
import org.jcnc.snow.compiler.semantic.error.SemanticError;
|
||||
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
||||
import org.jcnc.snow.compiler.semantic.type.BuiltinType;
|
||||
import org.jcnc.snow.compiler.semantic.type.Type;
|
||||
|
||||
/**
|
||||
@ -15,7 +15,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
|
||||
* <p>
|
||||
* 主要职责如下:
|
||||
* <ul>
|
||||
* <li>条件表达式类型检查:确认 if 的条件表达式类型为 int(用于真假判断),否则记录语义错误。</li>
|
||||
* <li>条件表达式类型检查:确认 if 的条件表达式类型为 boolean,否则记录语义错误。</li>
|
||||
* <li>块级作用域:分别为 then 分支和 else 分支创建独立的符号表(SymbolTable),
|
||||
* 支持分支内变量的块级作用域,防止分支内声明的变量污染外部或互相干扰,允许分支内变量同名遮蔽。</li>
|
||||
* <li>分支递归分析:对 then 和 else 分支的每条语句递归调用对应的语义分析器,进行语义检查。</li>
|
||||
@ -48,9 +48,9 @@ public class IfAnalyzer implements StatementAnalyzer<IfNode> {
|
||||
var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ifn.condition());
|
||||
// 对条件表达式执行类型分析
|
||||
Type condType = exprAnalyzer.analyze(ctx, mi, fn, locals, ifn.condition());
|
||||
// 判断条件类型是否为 int(SCompiler 约定 int 表示真假),否则报错
|
||||
if (condType != BuiltinType.INT) {
|
||||
ctx.getErrors().add(new SemanticError(ifn, "if 条件必须为 int 类型(表示真假)"));
|
||||
// 判断条件类型是否为 boolean,否则报错
|
||||
if (TypeUtils.isLogic(condType)) {
|
||||
ctx.getErrors().add(new SemanticError(ifn, "if 条件必须为 boolean"));
|
||||
}
|
||||
|
||||
// 2. 分析 then 分支
|
||||
|
||||
@ -2,12 +2,12 @@ package org.jcnc.snow.compiler.semantic.analyzers.statement;
|
||||
|
||||
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.LoopNode;
|
||||
import org.jcnc.snow.compiler.semantic.analyzers.TypeUtils;
|
||||
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
|
||||
import org.jcnc.snow.compiler.semantic.core.Context;
|
||||
import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
|
||||
import org.jcnc.snow.compiler.semantic.error.SemanticError;
|
||||
import org.jcnc.snow.compiler.semantic.symbol.SymbolTable;
|
||||
import org.jcnc.snow.compiler.semantic.type.BuiltinType;
|
||||
import org.jcnc.snow.compiler.semantic.type.Type;
|
||||
|
||||
/**
|
||||
@ -17,7 +17,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
|
||||
* <ul>
|
||||
* <li>为整个循环体(包括初始化、条件、更新、循环体本身)创建独立的块级符号表(作用域),保证循环内变量与外部隔离。</li>
|
||||
* <li>依次分析初始化语句、条件表达式、更新语句和循环体各语句,并递归检查嵌套的语法结构。</li>
|
||||
* <li>检查条件表达式的类型必须为 int(布尔条件),否则记录语义错误。</li>
|
||||
* <li>检查条件表达式的类型必须为 boolean,否则记录语义错误。</li>
|
||||
* <li>支持所有错误的收集而不中断流程,便于一次性输出全部问题。</li>
|
||||
* </ul>
|
||||
* 该分析器实现了 SCompiler 语言的块级作用域循环与类型健壮性,是健全语义分析的基础部分。
|
||||
@ -53,9 +53,9 @@ public class LoopAnalyzer implements StatementAnalyzer<LoopNode> {
|
||||
// 3. 分析条件表达式(如 for(...; cond; ...) 或 while(cond))
|
||||
var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.condition());
|
||||
Type condType = condAnalyzer.analyze(ctx, mi, fn, loopScope, ln.condition());
|
||||
// 条件类型必须为 int(即 bool),否则记录错误
|
||||
if (condType != BuiltinType.INT) {
|
||||
ctx.getErrors().add(new SemanticError(ln, "loop 条件必须为 int 类型(表示真假)"));
|
||||
// 条件类型必须为 boolean,否则记录错误
|
||||
if (TypeUtils.isLogic(condType)) {
|
||||
ctx.getErrors().add(new SemanticError(ln, "loop 条件必须为 boolean"));
|
||||
}
|
||||
|
||||
// 4. 分析更新语句(如 for(...; ...; update))
|
||||
|
||||
@ -39,6 +39,7 @@ public final class AnalyzerRegistrar {
|
||||
registry.registerStatementAnalyzer(IfNode.class, new IfAnalyzer());
|
||||
registry.registerStatementAnalyzer(LoopNode.class, new LoopAnalyzer());
|
||||
registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer());
|
||||
registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer());
|
||||
|
||||
// 特殊处理:表达式语句(如 "foo();")作为语句包装表达式
|
||||
registry.registerStatementAnalyzer(ExpressionStatementNode.class,
|
||||
|
||||
@ -31,6 +31,7 @@ public final class BuiltinTypeRegistry {
|
||||
"float", BuiltinType.FLOAT,
|
||||
"double", BuiltinType.DOUBLE,
|
||||
"string", BuiltinType.STRING,
|
||||
"boolean", BuiltinType.BOOLEAN,
|
||||
"void", BuiltinType.VOID
|
||||
);
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ package org.jcnc.snow.compiler.semantic.type;
|
||||
* <li>{@link #FLOAT} - 单精度浮点数</li>
|
||||
* <li>{@link #DOUBLE} - 双精度浮点数</li>
|
||||
* <li>{@link #STRING} - 字符串类型</li>
|
||||
* <li>{@link #BOOLEAN} - 布尔类型</li>
|
||||
* <li>{@link #VOID} - 空类型,用于表示无返回值的函数</li>
|
||||
* </ul>
|
||||
*
|
||||
@ -34,6 +35,7 @@ public enum BuiltinType implements Type {
|
||||
FLOAT, // 单精度浮点数
|
||||
DOUBLE, // 双精度浮点数
|
||||
STRING, // 字符串类型
|
||||
BOOLEAN, // 布尔类型
|
||||
VOID; // 空类型,用于表示函数无返回值
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user