feat: 添加 break 语句支持

- 新增 BreakNode、BreakAnalyzer 和 BreakStatementParser 类
- 在 AnalyzerRegistrar 中注册 break 语句分析器
- 在 ASTPrinter 中添加 break 语句的打印处理
- 在 StatementBuilder 中实现 break 语句的 IR 构建逻辑
- 更新 StatementParserFactory 和 TokenFactory,支持 break 关键字
This commit is contained in:
Luke 2025-07-28 18:00:41 +08:00
parent 0cb2132e80
commit 856d113b53
8 changed files with 100 additions and 5 deletions

View File

@ -9,6 +9,7 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.ArrayDeque;
import java.util.Locale; import java.util.Locale;
/** /**
@ -27,6 +28,10 @@ public class StatementBuilder {
* 表达式 IR 构建器用于将表达式节点转为 IR 指令 * 表达式 IR 构建器用于将表达式节点转为 IR 指令
*/ */
private final ExpressionBuilder expr; private final ExpressionBuilder expr;
/**
* break 目标标签栈保存每层循环的结束标签
*/
private final ArrayDeque<String> breakTargets = new ArrayDeque<>();
/** /**
* 构造方法 * 构造方法
@ -120,6 +125,14 @@ public class StatementBuilder {
} }
return; return;
} }
if (stmt instanceof BreakNode) {
// break 语句跳转到当前最近一层循环的结束标签
if (breakTargets.isEmpty()) {
throw new IllegalStateException("`break` appears outside of a loop");
}
InstructionFactory.jmp(ctx, breakTargets.peek());
return;
}
// 不支持的语句类型 // 不支持的语句类型
throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName() + ": " + stmt); throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName() + ": " + stmt);
} }
@ -163,8 +176,15 @@ public class StatementBuilder {
// 条件不满足则跳出循环 // 条件不满足则跳出循环
emitConditionalJump(loop.cond(), lblEnd); emitConditionalJump(loop.cond(), lblEnd);
// 在进入循环体前记录本层循环的结束标签 break 使用
breakTargets.push(lblEnd);
try {
// 构建循环体 // 构建循环体
buildStatements(loop.body()); buildStatements(loop.body());
} finally {
// 离开循环体时弹出标签避免影响外层
breakTargets.pop();
}
// 更新部分 for i++ // 更新部分 for i++
if (loop.step() != null) build(loop.step()); if (loop.step() != null) build(loop.step());

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", "init", "cond", "step","globals"); 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","globals","break");
/** /**
* 内置类型名称集合 intstring * 内置类型名称集合 intstring

View File

@ -0,0 +1,16 @@
package org.jcnc.snow.compiler.parser.ast;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
* {@code BreakNode} 表示循环体中的 break 语句
* 出现时应立即终止当前最内层循环
*/
public record BreakNode(NodeContext context) implements StatementNode {
@Override
public String toString() {
return "break@" + context;
}
}

View File

@ -27,6 +27,7 @@ public class StatementParserFactory {
registry.put("if", new IfStatementParser()); registry.put("if", new IfStatementParser());
registry.put("loop", new LoopStatementParser()); registry.put("loop", new LoopStatementParser());
registry.put("return", new ReturnStatementParser()); registry.put("return", new ReturnStatementParser());
registry.put("break", new BreakStatementParser());
// 默认处理器: 表达式语句 // 默认处理器: 表达式语句
registry.put("", new ExpressionStatementParser()); registry.put("", new ExpressionStatementParser());

View File

@ -116,6 +116,7 @@ public class ASTPrinter {
} }
case ReturnNode r -> System.out.println(pad + "return" + case ReturnNode r -> System.out.println(pad + "return" +
r.getExpression().map(e -> " " + e).orElse("")); r.getExpression().map(e -> " " + e).orElse(""));
case BreakNode _ -> System.out.println(pad + "break");
case ExpressionStatementNode(ExpressionNode expression, NodeContext _) -> case ExpressionStatementNode(ExpressionNode expression, NodeContext _) ->
System.out.println(pad + expression); System.out.println(pad + expression);
case null, default -> System.out.println(pad + n); // 回退处理 case null, default -> System.out.println(pad + n); // 回退处理

View File

@ -0,0 +1,28 @@
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.BreakNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 解析 break 语句仅包含关键字本身并以换行结束
* 语义立即终止当前最内层循环
*/
public class BreakStatementParser implements StatementParser {
@Override
public BreakNode parse(ParserContext ctx) {
// 记录当前位置作为 NodeContext
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 消耗 'break'
ctx.getTokens().expect("break");
// 行结束
ctx.getTokens().expectType(TokenType.NEWLINE);
return new BreakNode(new NodeContext(line, column, file));
}
}

View File

@ -0,0 +1,28 @@
package org.jcnc.snow.compiler.semantic.analyzers.statement;
import org.jcnc.snow.compiler.parser.ast.BreakNode;
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
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.symbol.SymbolTable;
/**
* {@code BreakAnalyzer} break 语句的语义分析器
* <p>
* 目前不做额外检查是否位于循环体内的限制由 IR 构建阶段StatementBuilder
* 进行安全校验若出现在循环外会抛出清晰的错误
* 如需在语义阶段提前报错可在此处结合循环上下文进行校验
*/
public class BreakAnalyzer implements StatementAnalyzer<BreakNode> {
@Override
public void analyze(Context ctx,
ModuleInfo mi,
FunctionNode fn,
SymbolTable locals,
BreakNode stmt) {
// no-op: break 本身不引入新符号或类型约束
// 在语义阶段校验是否处于循环内需要在 ctx SymbolTable 上增加上下文标记后在此检查
}
}

View File

@ -40,6 +40,7 @@ public final class AnalyzerRegistrar {
registry.registerStatementAnalyzer(LoopNode.class, new LoopAnalyzer()); registry.registerStatementAnalyzer(LoopNode.class, new LoopAnalyzer());
registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer()); registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer());
registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer()); registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer());
registry.registerStatementAnalyzer(BreakNode.class, new BreakAnalyzer());
// 特殊处理: 表达式语句 "foo();"作为语句包装表达式 // 特殊处理: 表达式语句 "foo();"作为语句包装表达式
registry.registerStatementAnalyzer(ExpressionStatementNode.class, registry.registerStatementAnalyzer(ExpressionStatementNode.class,
@ -56,7 +57,7 @@ public final class AnalyzerRegistrar {
registry.registerExpressionAnalyzer(BinaryExpressionNode.class, new BinaryExpressionAnalyzer()); registry.registerExpressionAnalyzer(BinaryExpressionNode.class, new BinaryExpressionAnalyzer());
// ---------- 注册一元表达式分析器 ---------- // ---------- 注册一元表达式分析器 ----------
registry.registerExpressionAnalyzer(UnaryExpressionNode.class,new UnaryExpressionAnalyzer()); registry.registerExpressionAnalyzer(UnaryExpressionNode.class, new UnaryExpressionAnalyzer());
// 对尚未实现的表达式类型使用兜底处理器 // 对尚未实现的表达式类型使用兜底处理器
registry.registerExpressionAnalyzer(MemberExpressionNode.class, registry.registerExpressionAnalyzer(MemberExpressionNode.class,