feat: 添加 continue 语句支持
- 新增 ContinueNode、ContinueAnalyzer 和 ContinueStatementParser 类 - 在 AnalyzerRegistrar 中注册 continue 语句分析器 - 在 StatementBuilder 中添加 continue 语句的处理逻辑 - 更新 StatementParserFactory 和 TokenFactory 以支持 continue 关键字
This commit is contained in:
parent
187ec7e0e9
commit
7395256b5a
@ -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);
|
||||||
|
|||||||
@ -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");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内置类型名称集合,如 int、string 等。
|
* 内置类型名称集合,如 int、string 等。
|
||||||
|
|||||||
@ -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 语句用于跳过当前循环剩余部分,直接进入下一次循环的 step→cond 阶段。
|
||||||
|
* 该节点仅作为语法树中的一种语句类型出现。
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public record ContinueNode(NodeContext context) implements StatementNode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "continue";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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());
|
||||||
|
|||||||
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 构建阶段检查
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user