diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java
index 0552426..fc96b6e 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/IfAnalyzer.java
@@ -11,28 +11,10 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType;
import org.jcnc.snow.compiler.semantic.type.Type;
/**
- * {@code IfAnalyzer} 是用于分析 {@link IfNode} 条件语句的语义分析器。
- *
- * 它负责验证 if 条件表达式的类型合法性,并递归分析 then 分支和 else 分支中的所有子语句。
- * 分析规则如下:
- *
- * - if 条件必须为 {@link BuiltinType#INT} 类型,用于表示布尔真值;
- * - 若条件类型不为 int,将报告语义错误并继续分析;
- * - then 和 else 分支中的语句将分别递归进行语义分析;
- * - 若某个子语句无匹配分析器,将回退到默认处理器或报告不支持。
- *
+ * 改进版 {@code IfAnalyzer},为 then/else 分支提供独立块级作用域。
*/
public class IfAnalyzer implements StatementAnalyzer {
- /**
- * 执行 if 语句的语义分析,包括条件类型检查和分支分析。
- *
- * @param ctx 当前语义分析上下文,提供注册表、错误收集、日志等服务。
- * @param mi 当前模块信息(本实现未直接使用)。
- * @param fn 当前所在函数节点(本实现未直接使用)。
- * @param locals 当前作用域的符号表,提供变量查找支持。
- * @param ifn 要分析的 {@link IfNode} 语法节点,包含条件表达式及两个分支语句块。
- */
@Override
public void analyze(Context ctx,
ModuleInfo mi,
@@ -40,32 +22,35 @@ public class IfAnalyzer implements StatementAnalyzer {
SymbolTable locals,
IfNode ifn) {
- // 1. 分析并校验条件表达式类型
- ctx.log("检查 if 条件");
+ // 1. 条件类型检查
var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ifn.condition());
- Type cond = exprAnalyzer.analyze(ctx, mi, fn, locals, ifn.condition());
- if (cond != BuiltinType.INT) {
- ctx.getErrors().add(new SemanticError(
- ifn,
- "if 条件必须为 int 类型(表示真假)"
- ));
- ctx.log("错误: if 条件类型不为 int");
+ Type condType = exprAnalyzer.analyze(ctx, mi, fn, locals, ifn.condition());
+ if (condType != BuiltinType.INT) {
+ ctx.getErrors().add(new SemanticError(ifn, "if 条件必须为 int 类型(表示真假)"));
}
- // 2. 递归分析 then 分支语句
+ // 2. then 分支
+ SymbolTable thenScope = new SymbolTable(locals);
for (var stmt : ifn.thenBranch()) {
var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt);
if (stAnalyzer != null) {
- stAnalyzer.analyze(ctx, mi, fn, locals, stmt);
+ stAnalyzer.analyze(ctx, mi, fn, thenScope, stmt);
+ } else {
+ ctx.getErrors().add(new SemanticError(stmt, "不支持的语句类型: " + stmt));
}
}
- // 3. 递归分析 else 分支语句(若存在)
- for (var stmt : ifn.elseBranch()) {
- var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt);
- if (stAnalyzer != null) {
- stAnalyzer.analyze(ctx, mi, fn, locals, stmt);
+ // 3. else 分支(可选)
+ if (!ifn.elseBranch().isEmpty()) {
+ SymbolTable elseScope = new SymbolTable(locals);
+ for (var stmt : ifn.elseBranch()) {
+ var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt);
+ if (stAnalyzer != null) {
+ stAnalyzer.analyze(ctx, mi, fn, elseScope, stmt);
+ } else {
+ ctx.getErrors().add(new SemanticError(stmt, "不支持的语句类型: " + stmt));
+ }
}
}
}
-}
+}
\ No newline at end of file
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 6599986..ad5b71a 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
@@ -11,30 +11,10 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType;
import org.jcnc.snow.compiler.semantic.type.Type;
/**
- * {@code LoopAnalyzer} 是用于分析 {@link LoopNode} 循环结构的语义分析器。
- *
- * 支持的循环结构包括典型的 C 风格 for-loop:由初始化语句、条件表达式、更新语句和循环体组成。
- *
- * 分析流程如下:
- *
- * - 分析初始化语句 {@code initializer};
- * - 分析并验证条件表达式 {@code condition} 类型是否为 {@link BuiltinType#INT};
- * - 分析更新语句 {@code update};
- * - 递归分析循环体 {@code body} 中的每个子语句;
- * - 所有阶段若发现语义错误均记录至 {@link Context#getErrors()},并写入日志。
- *
+ * 改进版 {@code LoopAnalyzer},为循环结构提供块级作用域支持。
*/
public class LoopAnalyzer implements StatementAnalyzer {
- /**
- * 执行循环结构的语义分析。
- *
- * @param ctx 当前语义分析上下文,提供模块信息、错误记录、日志输出和分析器注册表等服务。
- * @param mi 当前模块信息(本方法中未直接使用,保留用于接口一致性)。
- * @param fn 当前函数节点(本方法中未直接使用,保留用于可能的上下文分析扩展)。
- * @param locals 当前作用域的符号表,记录变量类型及其可见性。
- * @param ln 待分析的 {@link LoopNode} 节点,包含初始化语句、条件表达式、更新语句和循环体。
- */
@Override
public void analyze(Context ctx,
ModuleInfo mi,
@@ -42,35 +22,35 @@ public class LoopAnalyzer implements StatementAnalyzer {
SymbolTable locals,
LoopNode ln) {
- // 1. 分析初始化语句
- ctx.log("检查 loop 循环");
+ // 1. 整个循环的块级作用域
+ SymbolTable loopScope = new SymbolTable(locals);
+
+ // 2. 初始化语句
var initAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.initializer());
if (initAnalyzer != null) {
- initAnalyzer.analyze(ctx, mi, fn, locals, ln.initializer());
+ initAnalyzer.analyze(ctx, mi, fn, loopScope, ln.initializer());
}
- // 2. 分析条件表达式并检查类型
+ // 3. 条件表达式
var condAnalyzer = ctx.getRegistry().getExpressionAnalyzer(ln.condition());
- Type cond = condAnalyzer.analyze(ctx, mi, fn, locals, ln.condition());
- if (cond != BuiltinType.INT) {
- ctx.getErrors().add(new SemanticError(
- ln,
- "loop 条件必须为 int 类型(表示真假)"
- ));
- ctx.log("错误: loop 条件类型不为 int");
+ Type condType = condAnalyzer.analyze(ctx, mi, fn, loopScope, ln.condition());
+ if (condType != BuiltinType.INT) {
+ ctx.getErrors().add(new SemanticError(ln, "loop 条件必须为 int 类型(表示真假)"));
}
- // 3. 分析更新语句
+ // 4. 更新语句
var updateAnalyzer = ctx.getRegistry().getStatementAnalyzer(ln.update());
if (updateAnalyzer != null) {
- updateAnalyzer.analyze(ctx, mi, fn, locals, ln.update());
+ updateAnalyzer.analyze(ctx, mi, fn, loopScope, ln.update());
}
- // 4. 递归分析循环体中的每个语句
+ // 5. 循环体
for (var stmt : ln.body()) {
var stAnalyzer = ctx.getRegistry().getStatementAnalyzer(stmt);
if (stAnalyzer != null) {
- stAnalyzer.analyze(ctx, mi, fn, locals, stmt);
+ stAnalyzer.analyze(ctx, mi, fn, loopScope, stmt);
+ } else {
+ ctx.getErrors().add(new SemanticError(stmt, "不支持的语句类型: " + stmt));
}
}
}
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
index be862fe..af44dc1 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
@@ -5,51 +5,47 @@ import org.jcnc.snow.compiler.semantic.error.SemanticError;
import java.util.List;
/**
- * {@code SemanticAnalysisReporter} 是语义分析阶段的结果报告工具类。
- *
- * 用于统一处理语义分析阶段产生的错误信息输出与流程终止逻辑。
- * 通常作为语义分析器的收尾阶段调用。
- *
- *
主要职责包括:
+ * {@code SemanticAnalysisReporter} 用于在语义分析结束后汇总并打印所有收集到的
+ * {@link SemanticError}。为了同时满足“完整错误收集”与“按需快速失败”两种使用场景,
+ * 现在提供两个公共 API:
*
- * - 打印所有收集到的 {@link SemanticError};
- * - 若存在错误,使用 {@code System.exit(1)} 终止编译流程;
- * - 若无错误,输出分析通过提示。
+ * - {@link #report(List)} ‑ 仅打印,不终止;
+ * - {@link #reportAndExitIfNecessary(List)} ‑ 若存在错误则 打印并退出。
*
- *
- * 该类为工具类,禁止实例化,方法均为静态调用。
+ * 调用方可根据需求选择合适方法。
*/
public final class SemanticAnalysisReporter {
- // 禁止实例化
- private SemanticAnalysisReporter() {
-
- }
+ private SemanticAnalysisReporter() { }
/**
- * 打印语义分析结果并在必要时终止程序。
- *
- * 如果错误列表非空:
- *
- * - 逐条打印错误信息(含位置与描述);
- * - 使用 {@code System.exit(1)} 退出,表示语义分析失败。
- *
- * 如果错误列表为空:
- *
+ * 打印语义分析结果;不会退出进程。
*
- * @param errors 语义分析阶段收集到的错误列表(允许为 null)
+ * @param errors 语义分析阶段收集到的错误列表(允许为 {@code null})
*/
- public static void reportAndExitIfNecessary(List errors) {
- if (errors != null && !errors.isEmpty()) {
- System.err.println("语义分析发现错误:");
- for (SemanticError error : errors) {
- System.err.println(" " + error);
- }
- System.exit(1); // 非正常退出,阻止后续编译流程
+ public static void report(List errors) {
+ if (hasErrors(errors)) {
+ System.err.println("语义分析发现 " + errors.size() + " 个错误:");
+ errors.forEach(err -> System.err.println(" " + err));
} else {
System.out.println("语义分析通过,没有发现错误。");
}
}
-}
+
+ /**
+ * 打印语义分析结果;如有错误立即以状态码 1 结束进程。
+ * 适用于 CLI 工具需要立即中止后续编译阶段的场景。
+ *
+ * @param errors 语义分析阶段收集到的错误列表(允许为 {@code null})
+ */
+ public static void reportAndExitIfNecessary(List errors) {
+ report(errors);
+ if (hasErrors(errors)) {
+ System.exit(1);
+ }
+ }
+
+ private static boolean hasErrors(List errors) {
+ return errors != null && !errors.isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/test b/test
index 1f3471f..7d0eae5 100644
--- a/test
+++ b/test
@@ -5,20 +5,31 @@ module: CommonTasks
return_type:int
body:
+ declare x : int
+ declare x : string
+ y = 5
+ x = "hello"
- return CommonTasks.test(3,1)
+ if x then
+ declare z : float
+ declare z : int
+ else
+ z = 3.14
+ end if
+
+ return CommonTasks.test(3, "a")
end body
end function
- function:test
+ function: test
parameter:
- declare num1:int
- declare num2:int
+ declare num1 : int
+ declare num2 : int
return_type:int
body:
declare result : int
- result = num1 + num2
+ result = num1 + "hello"
return result
end body
end function