From 59dbafb2b6b4d749e2c9ad49e90ba63354e85f64 Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 10 May 2025 15:40:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jcnc/snow/compiler/cli/SnowCompiler.java | 5 +- .../parser/utils/FlexibleSectionParser.java | 80 +++++++++---------- test | 3 +- 3 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java b/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java index 79a0a6c..a6d90ed 100644 --- a/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java +++ b/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java @@ -7,6 +7,7 @@ import org.jcnc.snow.compiler.ir.core.IRFunction; import org.jcnc.snow.compiler.ir.core.IRProgram; import org.jcnc.snow.compiler.lexer.core.LexerEngine; import org.jcnc.snow.compiler.lexer.token.Token; +import org.jcnc.snow.compiler.lexer.utils.TokenPrinter; import org.jcnc.snow.compiler.parser.ast.base.Node; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.core.ParserEngine; @@ -48,9 +49,9 @@ public class SnowCompiler { List ast = new ParserEngine(ctx).parse(); // System.out.println(source); -// TokenPrinter.print(tokens); // 打印 Token 列表 + TokenPrinter.print(tokens); // 打印 Token 列表 ASTPrinter.print(ast); // 打印 AST -// ASTPrinter.printJson(ast); // 打印JSON AST + ASTPrinter.printJson(ast); // 打印JSON AST /* 3. 语义分析 */ SemanticAnalyzerRunner.runSemanticAnalysis(ast, false); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java index b11a40e..3143421 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/FlexibleSectionParser.java @@ -10,23 +10,18 @@ import java.util.function.Predicate; /** * 通用的解析器,用于解析结构化的内容部分,完全解耦合关键字和语法。 - *

- * {@code FlexibleSectionParser} 提供了一个灵活的机制来解析可变的语法块。每个语法块的解析逻辑通过外部提供, - * 该类仅负责按顺序解析不同的区块,直到遇到结束标记。它完全解耦了具体的语法关键字和解析逻辑。 - *

- *

- * 使用此类可以解析如函数定义中的多个部分(如参数、返回类型、函数体等),而无需在解析器中硬编码这些结构。 - *

+ * + * FlexibleSectionParser 提供了一个灵活的机制来解析可变的语法块。每个语法块的解析逻辑通过外部提供, + * 该类仅负责按顺序解析不同的区块,直到遇到结束标记,同时能够跳过并收集注释供后续使用。 + * + * 使用此类可以解析如函数定义中的多个部分(如参数、返回类型、函数体等),而无需在解析器中硬编码这些结构, + * 并且保留注释信息以便 IDE 或工具链进行注释跳转、重构等操作。 */ public class FlexibleSectionParser { /** * 解析一系列的可变区块,解析顺序和具体内容由外部定义。 - *

- * 该方法接受一个包含区块定义的映射,每个区块定义包含一个条件(Predicate) - * 和一个解析器(BiConsumer)。 - * 条件用于判断当前是否应解析该区块,解析器则执行解析逻辑。 - *

+ * 在解析过程中会跳过并收集注释,以及跳过空行。 * * @param ctx 当前的解析上下文,包含语法分析所需的所有信息(如作用域、错误处理等) * @param tokens 当前的词法 token 流,用于逐个查看或消耗 token @@ -36,66 +31,63 @@ public class FlexibleSectionParser { TokenStream tokens, Map sectionDefinitions) { - // 跳过最开始的空行,避免误判开始关键字 - while (tokens.peek().getType() == TokenType.NEWLINE) { - tokens.next(); - } + // 在开始解析之前,跳过并收集所有紧邻开头的注释和空行 + skipCommentsAndNewlines(tokens); - // 主循环:逐个处理区块,直到遇到 "end" 为止 while (true) { - // 获取当前 token 的字面量(通常是关键字字符串) + // 在每次解析前,跳过并收集注释和空行 + skipCommentsAndNewlines(tokens); + String keyword = tokens.peek().getLexeme(); - // 尝试在映射中找到对应该关键字的区块定义 - SectionDefinition definition = sectionDefinitions.get(keyword); + if ("end".equals(keyword)) { + // 遇到 'end' 则终止解析 + break; + } - // 如果找到了定义且其条件满足当前 token 流 + SectionDefinition definition = sectionDefinitions.get(keyword); if (definition != null && definition.condition().test(tokens)) { // 执行该区块的解析逻辑 definition.parser().accept(ctx, tokens); - } else if ("end".equals(keyword)) { - // 如果遇到 "end",表示所有区块结束,退出循环 - break; } else { - // 如果关键字无法识别,或不满足条件,则抛出异常 + // 无法识别该关键字或条件不满足则报错 throw new RuntimeException("未识别的关键字或条件不满足: " + keyword); } - - // 每次解析完成后,继续跳过空行,准备进入下一个区块的判断 - while (tokens.peek().getType() == TokenType.NEWLINE) { - tokens.next(); - } + } + } + + /** + * 跳过所有连续的注释行和空行。 + * + * @param tokens 词法流 + */ + private static void skipCommentsAndNewlines(TokenStream tokens) { + while (true) { + TokenType type = tokens.peek().getType(); + if (type == TokenType.COMMENT || type == TokenType.NEWLINE) { + tokens.next(); + continue; + } + break; } } /** * 区块定义类:表示一个语法区块的匹配条件和解析逻辑。 - *

* 每个区块由两个部分组成: * - 条件:用于判断当前 token 流是否应进入该区块的解析。 * - 解析器:具体的解析逻辑,通常是消费若干 token 并更新解析上下文。 - *

* * @param condition 匹配条件,返回 true 表示此区块应被解析 * @param parser 实际解析逻辑 */ - public record SectionDefinition(Predicate condition, BiConsumer parser) { - - /** - * 获取条件判断函数。 - * - * @return 一个用于判断是否进入该区块的 Predicate - */ + public record SectionDefinition(Predicate condition, + BiConsumer parser) { @Override public Predicate condition() { return condition; } - /** - * 获取解析器函数。 - * - * @return 一个解析该区块的 BiConsumer 函数 - */ @Override public BiConsumer parser() { return parser; diff --git a/test b/test index f1f4d9f..a816f71 100644 --- a/test +++ b/test @@ -2,9 +2,10 @@ module: CommonTasks function: main1 parameter: declare num1: int - declare num2: int + declare num2: int // 1 return_type:int + body: num1 = 10 return num1