diff --git a/.run/Demo18.run.xml b/.run/Demo18.run.xml new file mode 100644 index 0000000..c9f4bb6 --- /dev/null +++ b/.run/Demo18.run.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/playground/Demo/Demo18/Main.snow b/playground/Demo/Demo18/Main.snow new file mode 100644 index 0000000..e41610c --- /dev/null +++ b/playground/Demo/Demo18/Main.snow @@ -0,0 +1,43 @@ +module: Main + import: os + function: main + return_type: int + body: + loop: + init: + declare i:int = 1 + cond: + i <= 5 + step: + i = i + 1 + body: + if i % 2 == 0 then + continue + end if + if i > 3 then + break + end if + loop: + init: + declare j:int = 1 + cond: + j <= 5 + step: + j = j + 1 + body: + if j == 4 then + break + end if + if j % 2 == 0 then + continue + end if + print(i) + print(j) + end body + end loop + end body + end loop + return 0 + end body + end function +end module diff --git a/playground/Demo/Demo18/OS.snow b/playground/Demo/Demo18/OS.snow new file mode 100644 index 0000000..6026d43 --- /dev/null +++ b/playground/Demo/Demo18/OS.snow @@ -0,0 +1,11 @@ +module: os + import: os + function: print + parameter: + declare i1: int + return_type: void + body: + syscall("PRINT",i1) + end body + end function +end module \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java index 0c540fa..98ab6ce 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java @@ -32,6 +32,10 @@ public class StatementBuilder { * break 目标标签栈(保存每层循环的结束标签) */ private final ArrayDeque breakTargets = new ArrayDeque<>(); + /** + * continue 目标标签栈(保存每层循环的 step 起始标签) + */ + private final ArrayDeque continueTargets = new ArrayDeque<>(); /** * 构造方法。 @@ -133,6 +137,14 @@ public class StatementBuilder { InstructionFactory.jmp(ctx, breakTargets.peek()); 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); } @@ -178,17 +190,22 @@ public class StatementBuilder { emitConditionalJump(loop.cond(), lblEnd); // 在进入循环体前,记录本层循环的结束标签,供 break 使用 breakTargets.push(lblEnd); + // 记录本层循环的 step 起始标签,供 continue 使用 + String lblStep = ctx.newLabel(); + continueTargets.push(lblStep); try { // 构建循环体 buildStatements(loop.body()); } finally { // 离开循环体时弹出标签,避免影响外层 breakTargets.pop(); + continueTargets.pop(); } - // 更新部分(如 for 的 i++) + // step 起始标签(所有 continue 会跳到这里) + InstructionFactory.label(ctx, lblStep); if (loop.step() != null) build(loop.step()); - // 跳回循环起点 + // 回到 cond 检查 InstructionFactory.jmp(ctx, lblStart); // 循环结束标签 InstructionFactory.label(ctx, lblEnd); diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java index a251532..28e4697 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java @@ -25,7 +25,10 @@ public class TokenFactory { /** * 语言的保留关键字集合。 */ - private static final Set 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 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 等。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ContinueNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ContinueNode.java new file mode 100644 index 0000000..b81dd75 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ContinueNode.java @@ -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 语句节点。 + *

+ * continue 语句用于跳过当前循环剩余部分,直接进入下一次循环的 step→cond 阶段。 + * 该节点仅作为语法树中的一种语句类型出现。 + *

+ */ +public record ContinueNode(NodeContext context) implements StatementNode { + + @Override + public String toString() { + return "continue"; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java index 1272ffa..640db1b 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java @@ -28,6 +28,7 @@ public class StatementParserFactory { registry.put("loop", new LoopStatementParser()); registry.put("return", new ReturnStatementParser()); registry.put("break", new BreakStatementParser()); + registry.put("continue",new ContinueStatementParser()); // 默认处理器: 表达式语句 registry.put("", new ExpressionStatementParser()); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/BreakStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/BreakStatementParser.java index 6e38335..79b7f32 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/BreakStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/BreakStatementParser.java @@ -6,11 +6,23 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 解析 break 语句:仅包含关键字本身,并以换行结束。 + * {@code BreakStatementParser} 用于解析 break 语句。 + *

+ * break 语句的语法仅包含关键字本身,随后以换行结束。 * 语义:立即终止当前(最内层)循环。 + *

*/ public class BreakStatementParser implements StatementParser { + /** + * 解析 break 语句节点。 + *

+ * 期望格式为:'break' NEWLINE + *

+ * + * @param ctx 解析上下文 + * @return BreakNode AST 节点 + */ @Override public BreakNode parse(ParserContext ctx) { // 记录当前位置作为 NodeContext diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ContinueStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ContinueStatementParser.java new file mode 100644 index 0000000..3379087 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ContinueStatementParser.java @@ -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 语句。 + *

+ * continue 语句语法格式简单,仅包含关键字本身,随后以换行结束。 + * 语义:跳过本次剩余循环体,继续执行 step → cond。 + *

+ */ +public class ContinueStatementParser implements StatementParser { + + /** + * 解析 continue 语句节点。 + *

+ * 期望格式为:'continue' NEWLINE + *

+ * + * @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)); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ContinueAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ContinueAnalyzer.java new file mode 100644 index 0000000..f78f7b1 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/statement/ContinueAnalyzer.java @@ -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 语句的语义分析器。 + *

+ * 当前实现不做任何额外检查。continue 是否出现在有效的循环体内, + * 由 IR 构建阶段(如 StatementBuilder)负责判定与错误提示。 + *

+ *

+ * 用于 AST 的 {@link ContinueNode} 语句节点。 + *

+ */ +public class ContinueAnalyzer implements StatementAnalyzer { + + /** + * 分析 continue 语句节点的语义。 + *

+ * 该方法为 no-op,相关语义约束由后续阶段处理。 + *

+ * + * @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 构建阶段检查 + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java index 18d4c0c..0e5e318 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java @@ -41,6 +41,7 @@ public final class AnalyzerRegistrar { registry.registerStatementAnalyzer(ReturnNode.class, new ReturnAnalyzer()); registry.registerExpressionAnalyzer(BoolLiteralNode.class, new BoolLiteralAnalyzer()); registry.registerStatementAnalyzer(BreakNode.class, new BreakAnalyzer()); + registry.registerStatementAnalyzer(ContinueNode.class, new ContinueAnalyzer()); // 特殊处理: 表达式语句(如 "foo();")作为语句包装表达式 registry.registerStatementAnalyzer(ExpressionStatementNode.class,