feat: 添加 continue 语句支持

- 新增 ContinueNode、ContinueAnalyzer 和 ContinueStatementParser 类
- 在 AnalyzerRegistrar 中注册 continue 语句分析器
- 在 StatementBuilder 中添加 continue 语句的处理逻辑
- 更新 StatementParserFactory 和 TokenFactory 以支持 continue 关键字
This commit is contained in:
Luke 2025-07-29 11:20:46 +08:00
parent 187ec7e0e9
commit 7395256b5a
7 changed files with 126 additions and 3 deletions

View File

@ -32,6 +32,10 @@ public class StatementBuilder {
* break 目标标签栈保存每层循环的结束标签 * break 目标标签栈保存每层循环的结束标签
*/ */
private final ArrayDeque<String> breakTargets = new ArrayDeque<>(); private final ArrayDeque<String> breakTargets = new ArrayDeque<>();
/**
* continue 目标标签栈保存每层循环的 step 起始标签
*/
private final ArrayDeque<String> continueTargets = new ArrayDeque<>();
/** /**
* 构造方法 * 构造方法
@ -133,6 +137,14 @@ public class StatementBuilder {
InstructionFactory.jmp(ctx, breakTargets.peek()); InstructionFactory.jmp(ctx, breakTargets.peek());
return; return;
} }
if (stmt instanceof ContinueNode) {
// continue 语句跳转到当前最近一层循环的 step 起始标签
if (continueTargets.isEmpty()) {
throw new IllegalStateException("`continue` appears outside of a loop");
}
InstructionFactory.jmp(ctx, continueTargets.peek());
return;
}
// 不支持的语句类型 // 不支持的语句类型
throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName() + ": " + stmt); throw new IllegalStateException("Unsupported statement: " + stmt.getClass().getSimpleName() + ": " + stmt);
} }
@ -178,17 +190,22 @@ public class StatementBuilder {
emitConditionalJump(loop.cond(), lblEnd); emitConditionalJump(loop.cond(), lblEnd);
// 在进入循环体前记录本层循环的结束标签 break 使用 // 在进入循环体前记录本层循环的结束标签 break 使用
breakTargets.push(lblEnd); breakTargets.push(lblEnd);
// 记录本层循环的 step 起始标签 continue 使用
String lblStep = ctx.newLabel();
continueTargets.push(lblStep);
try { try {
// 构建循环体 // 构建循环体
buildStatements(loop.body()); buildStatements(loop.body());
} finally { } finally {
// 离开循环体时弹出标签避免影响外层 // 离开循环体时弹出标签避免影响外层
breakTargets.pop(); breakTargets.pop();
continueTargets.pop();
} }
// 更新部分 for i++ // step 起始标签(所有 continue 会跳到这里)
InstructionFactory.label(ctx, lblStep);
if (loop.step() != null) build(loop.step()); if (loop.step() != null) build(loop.step());
// 跳回循环起点 // 回到 cond 检查
InstructionFactory.jmp(ctx, lblStart); InstructionFactory.jmp(ctx, lblStart);
// 循环结束标签 // 循环结束标签
InstructionFactory.label(ctx, lblEnd); InstructionFactory.label(ctx, lblEnd);

View File

@ -25,7 +25,10 @@ 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","break"); 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", "continue");
/** /**
* 内置类型名称集合 intstring * 内置类型名称集合 intstring

View File

@ -0,0 +1,19 @@
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 ContinueNode} 表示循环体中的 continue 语句节点
* <p>
* continue 语句用于跳过当前循环剩余部分直接进入下一次循环的 stepcond 阶段
* 该节点仅作为语法树中的一种语句类型出现
* </p>
*/
public record ContinueNode(NodeContext context) implements StatementNode {
@Override
public String toString() {
return "continue";
}
}

View File

@ -28,6 +28,7 @@ public class StatementParserFactory {
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("break", new BreakStatementParser());
registry.put("continue",new ContinueStatementParser());
// 默认处理器: 表达式语句 // 默认处理器: 表达式语句
registry.put("", new ExpressionStatementParser()); registry.put("", new ExpressionStatementParser());

View File

@ -0,0 +1,40 @@
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.ContinueNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* {@code ContinueStatementParser} 用于解析 continue 语句
* <p>
* continue 语句语法格式简单仅包含关键字本身随后以换行结束
* 语义跳过本次剩余循环体继续执行 step cond
* </p>
*/
public class ContinueStatementParser implements StatementParser {
/**
* 解析 continue 语句节点
* <p>
* 期望格式为'continue' NEWLINE
* </p>
*
* @param ctx 解析上下文
* @return ContinueNode AST 节点
*/
@Override
public ContinueNode parse(ParserContext ctx) {
// 记录当前位置作为 NodeContext
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
String file = ctx.getSourceName();
// 消耗 'continue'
ctx.getTokens().expect("continue");
// 行结束
ctx.getTokens().expectType(TokenType.NEWLINE);
return new ContinueNode(new NodeContext(line, column, file));
}
}

View File

@ -0,0 +1,42 @@
package org.jcnc.snow.compiler.semantic.analyzers.statement;
import org.jcnc.snow.compiler.parser.ast.ContinueNode;
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 ContinueAnalyzer} continue 语句的语义分析器
* <p>
* 当前实现不做任何额外检查continue 是否出现在有效的循环体内
* IR 构建阶段 StatementBuilder负责判定与错误提示
* </p>
* <p>
* 用于 AST {@link ContinueNode} 语句节点
* </p>
*/
public class ContinueAnalyzer implements StatementAnalyzer<ContinueNode> {
/**
* 分析 continue 语句节点的语义
* <p>
* 该方法为 no-op相关语义约束由后续阶段处理
* </p>
*
* @param ctx 语义分析上下文
* @param mi 当前模块信息
* @param fn 当前所在函数节点
* @param locals 当前作用域下的符号表
* @param stmt 需要分析的 continue 语句节点
*/
@Override
public void analyze(Context ctx,
ModuleInfo mi,
FunctionNode fn,
SymbolTable locals,
ContinueNode stmt) {
// no-op: continue 语句的合法性由 IR 构建阶段检查
}
}

View File

@ -41,6 +41,7 @@ public final class AnalyzerRegistrar {
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()); registry.registerStatementAnalyzer(BreakNode.class, new BreakAnalyzer());
registry.registerStatementAnalyzer(ContinueNode.class, new ContinueAnalyzer());
// 特殊处理: 表达式语句 "foo();"作为语句包装表达式 // 特殊处理: 表达式语句 "foo();"作为语句包装表达式
registry.registerStatementAnalyzer(ExpressionStatementNode.class, registry.registerStatementAnalyzer(ExpressionStatementNode.class,