From f6804d05a9967b8313110d121fe4afa5a4ecfefe Mon Sep 17 00:00:00 2001
From: Luke
Date: Fri, 25 Apr 2025 16:07:30 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=87=BD=E6=95=B0=E5=99=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../parser/function/FunctionParser.java | 95 +++++++++++--------
.../parser/util/FlexibleSectionParser.java | 55 ++++++-----
2 files changed, 87 insertions(+), 63 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java
index 37c24b3..7b47a5a 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java
@@ -26,76 +26,83 @@ import java.util.Map;
* 返回类型
* 函数体
*
- *
- * 解析顺序不固定,且每个部分的解析逻辑由 {@code FlexibleSectionParser} 配合外部条件和解析器来控制。
- *
- * 解析过程中,函数定义的各个部分被依次解析,并最终构建成 {@code FunctionNode},作为抽象语法树的一部分。
+ * 各部分的顺序不固定,由 FlexibleSectionParser 按规则识别和处理。
*
*/
public class FunctionParser implements TopLevelParser {
/**
- * 解析函数定义,构建函数的抽象语法树。
+ * 解析函数定义,构建函数的抽象语法树节点。
*
- * 此方法解析函数的多个部分,包括函数名、参数、返回类型和函数体。各部分的解析顺序由 {@code FlexibleSectionParser} 控制。
+ * 此方法首先解析函数的头部和名称,然后通过 FlexibleSectionParser
+ * 分别解析函数的参数、返回类型和函数体,最后封装为 FunctionNode 返回。
*
*
- * @param ctx 解析上下文,包含 Token 流等信息
- * @return 解析后的函数语法树节点
+ * @param ctx 解析上下文(包含 Token 流、作用域信息等)
+ * @return 构建完成的 FunctionNode
*/
@Override
public FunctionNode parse(ParserContext ctx) {
TokenStream tokens = ctx.getTokens();
- // 匹配函数头部
+ // 匹配并消费 "function:" 标记
parseFunctionHeader(tokens);
- // 解析函数名
+ // 获取函数名称
String functionName = parseFunctionName(tokens);
- // 用于存储参数、返回类型和函数体
+ // 用于接收参数、返回类型和函数体的容器
List parameters = new ArrayList<>();
- String[] returnType = {null}; // 模拟引用传参
+ String[] returnType = {null}; // 使用数组模拟引用,以便 lambda 内修改值
List body = new ArrayList<>();
- // 定义可变区块的解析规则
+ // 构建区块解析定义(参数、返回类型、函数体)
Map sectionDefinitions = getStringSectionDefinitionMap(parameters, returnType, body);
- // 使用 FlexibleSectionParser 解析函数的可变部分,顺序无关
+ // 使用 FlexibleSectionParser 解析区块,顺序无关
FlexibleSectionParser.parse(ctx, tokens, sectionDefinitions);
- // 匹配函数结尾标签
+ // 匹配函数结束部分(end function)
parseFunctionFooter(tokens);
- // 返回构建好的函数节点
+ // 构建语法树节点并返回
return new FunctionNode(functionName, parameters, returnType[0], body);
}
+ /**
+ * 构造区块定义映射,包括参数、返回类型、函数体。
+ *
+ * @param parameters 参数节点容器
+ * @param returnType 返回类型容器(数组模拟引用)
+ * @param body 函数体语句节点容器
+ * @return 各关键字对应的解析逻辑映射
+ */
private Map getStringSectionDefinitionMap(List parameters, String[] returnType, List body) {
Map sectionDefinitions = new HashMap<>();
- // 参数解析
+ // 参数部分解析规则
sectionDefinitions.put("parameter", new SectionDefinition(
ts -> ts.peek().getLexeme().equals("parameter"),
(_, ts1) -> parameters.addAll(parseParameters(ts1))
));
- // 返回类型解析
+ // 返回类型部分解析规则
sectionDefinitions.put("return_type", new SectionDefinition(
ts -> ts.peek().getLexeme().equals("return_type"),
(_, ts1) -> returnType[0] = parseReturnType(ts1)
));
- // 函数体解析
+ // 函数体部分解析规则
sectionDefinitions.put("body", new SectionDefinition(
ts -> ts.peek().getLexeme().equals("body"),
(ctx1, ts1) -> body.addAll(parseFunctionBody(ctx1, ts1))
));
+
return sectionDefinitions;
}
/**
- * 匹配并解析函数头部标记(例如:function:)。
+ * 匹配并解析函数头部(function:)。
*
* @param ts Token 流
*/
@@ -105,10 +112,10 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析函数名并跳过换行符。
+ * 解析函数名称,并跳过换行。
*
* @param ts Token 流
- * @return 函数名
+ * @return 函数名称
*/
private String parseFunctionName(TokenStream ts) {
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
@@ -117,7 +124,7 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 匹配并解析函数结尾标记(例如:end function)。
+ * 匹配并解析函数尾部(end function)。
*
* @param ts Token 流
*/
@@ -128,10 +135,12 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析参数列表。
- *
- * 该方法解析以 "declare" 开头的参数声明行,并返回一个包含参数的 {@code ParameterNode} 列表。
- *
+ * 解析函数参数部分,格式:
+ *
+ * parameter:
+ * declare param1: int
+ * declare param2: string
+ *
*
* @param ts Token 流
* @return 参数节点列表
@@ -143,18 +152,21 @@ public class FunctionParser implements TopLevelParser {
List params = new ArrayList<>();
+ // 持续解析参数声明行,直到下一个区块或 "end"
while (true) {
if (ts.peek().getType() == TokenType.NEWLINE) {
- ts.next();
+ ts.next(); // 跳过空行
continue;
}
- if ("return_type".equals(ts.peek().getLexeme()) || "body".equals(ts.peek().getLexeme()) || "end".equals(ts.peek().getLexeme())) {
+ // 到达下一个区块或函数结尾时停止
+ String keyword = ts.peek().getLexeme();
+ if ("return_type".equals(keyword) || "body".equals(keyword) || "end".equals(keyword)) {
break;
}
+ // 匹配 "declare paramName: Type" 格式
ts.expect("declare");
-
String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expect(":");
String paramType = ts.expectType(TokenType.TYPE).getLexeme();
@@ -167,10 +179,13 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析返回类型。
+ * 解析返回类型部分,格式如下:
+ *
+ * return_type: int
+ *
*
* @param ts Token 流
- * @return 返回类型
+ * @return 返回类型字符串
*/
private String parseReturnType(TokenStream ts) {
ts.expect("return_type");
@@ -181,14 +196,17 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析函数体。
- *
- * 该方法解析函数体中的每个语句,并返回一个 {@code StatementNode} 列表。
- *
+ * 解析函数体部分,格式示例:
+ *
+ * body:
+ * print "hello"
+ * return x
+ * end body
+ *
*
* @param ctx 解析上下文
* @param ts Token 流
- * @return 函数体的语句列表
+ * @return 语句节点列表
*/
private List parseFunctionBody(ParserContext ctx, TokenStream ts) {
ts.expect("body");
@@ -197,6 +215,7 @@ public class FunctionParser implements TopLevelParser {
List body = new ArrayList<>();
+ // 持续解析直到遇到 end
while (true) {
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
@@ -207,11 +226,13 @@ public class FunctionParser implements TopLevelParser {
break;
}
+ // 获取当前语句关键字,并通过工厂选择对应的语句解析器
String keyword = ts.peek().getLexeme();
StatementNode statement = StatementParserFactory.get(keyword).parse(ctx);
body.add(statement);
}
+ // 匹配 end body
ts.expect("end");
ts.expect("body");
ts.expectType(TokenType.NEWLINE);
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java
index a53511b..95390a0 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java
@@ -14,9 +14,8 @@ import java.util.function.Predicate;
* {@code FlexibleSectionParser} 提供了一个灵活的机制来解析可变的语法块。每个语法块的解析逻辑通过外部提供,
* 该类仅负责按顺序解析不同的区块,直到遇到结束标记。它完全解耦了具体的语法关键字和解析逻辑。
*
- *
*
- * 使用此类解析函数定义中的多个部分(如参数、返回类型、函数体等),而不需要在解析器中显式地硬编码每个部分。
+ * 使用此类可以解析如函数定义中的多个部分(如参数、返回类型、函数体等),而无需在解析器中硬编码这些结构。
*
*/
public class FlexibleSectionParser {
@@ -24,41 +23,45 @@ public class FlexibleSectionParser {
/**
* 解析一系列的可变区块,解析顺序和具体内容由外部定义。
*
- * 该方法接受一个包含区块定义的映射,每个区块定义包含一个条件(`Predicate`)和一个解析器(`BiConsumer`)。
- * 条件用于判断是否应该解析该区块,解析器则负责实际的解析过程。
+ * 该方法接受一个包含区块定义的映射,每个区块定义包含一个条件(Predicate)
+ * 和一个解析器(BiConsumer)。
+ * 条件用于判断当前是否应解析该区块,解析器则执行解析逻辑。
*
*
- * @param ctx 解析上下文,包含词法流等信息
- * @param tokens 当前的 Token 流
- * @param sectionDefinitions 各种区块定义,键值为区块的名称,值为对应的解析器和条件
+ * @param ctx 当前的解析上下文,包含语法分析所需的所有信息(如作用域、错误处理等)
+ * @param tokens 当前的词法 token 流,用于逐个查看或消耗 token
+ * @param sectionDefinitions 区块定义映射:每个关键字(如 "params", "returns", "body")对应一个区块定义
*/
public static void parse(ParserContext ctx,
TokenStream tokens,
Map sectionDefinitions) {
- // 跳过空行
+ // 跳过最开始的空行,避免误判开始关键字
while (tokens.peek().getType() == TokenType.NEWLINE) {
tokens.next();
}
- // 遍历所有可变部分的解析
+ // 主循环:逐个处理区块,直到遇到 "end" 为止
while (true) {
+ // 获取当前 token 的字面量(通常是关键字字符串)
String keyword = tokens.peek().getLexeme();
- // 查找是否有与当前关键字匹配的区块
+ // 尝试在映射中找到对应该关键字的区块定义
SectionDefinition definition = sectionDefinitions.get(keyword);
+ // 如果找到了定义且其条件满足当前 token 流
if (definition != null && definition.condition().test(tokens)) {
- // 执行解析动作
+ // 执行该区块的解析逻辑
definition.parser().accept(ctx, tokens);
} else if ("end".equals(keyword)) {
- // 如果遇到 "end",则退出解析
+ // 如果遇到 "end",表示所有区块结束,退出循环
break;
} else {
+ // 如果关键字无法识别,或不满足条件,则抛出异常
throw new RuntimeException("未识别的关键字或条件不满足: " + keyword);
}
- // 跳过空行,继续解析
+ // 每次解析完成后,继续跳过空行,准备进入下一个区块的判断
while (tokens.peek().getType() == TokenType.NEWLINE) {
tokens.next();
}
@@ -66,31 +69,31 @@ public class FlexibleSectionParser {
}
/**
- * 定义区块的结构:每个区块有一个条件和一个解析器。
+ * 区块定义类:表示一个语法区块的匹配条件和解析逻辑。
*
- * {@code SectionDefinition} 是描述如何解析某个语法块的结构。
- * 它包含一个条件(`Predicate`),用于判断当前 Token 是否符合该区块的开始标识,
- * 以及一个解析器(`BiConsumer`),用于执行具体的解析操作。
+ * 每个区块由两个部分组成:
+ * - 条件:用于判断当前 token 流是否应进入该区块的解析。
+ * - 解析器:具体的解析逻辑,通常是消费若干 token 并更新解析上下文。
*
*
- * @param condition 条件,判断是否需要解析该区块
- * @param parser 区块的解析器
+ * @param condition 匹配条件,返回 true 表示此区块应被解析
+ * @param parser 实际解析逻辑
*/
public record SectionDefinition(Predicate condition, BiConsumer parser) {
/**
- * 构造一个新的区块定义。
+ * 构造函数。Java Record 自动生成,但我们保留注释以说明其目的。
*
- * @param condition 判断该区块是否应该解析的条件
- * @param parser 区块的解析器
+ * @param condition 判断当前是否应解析该区块的逻辑
+ * @param parser 负责实际解析过程的处理器
*/
public SectionDefinition {
}
/**
- * 获取该区块的条件,用于判断是否解析此区块。
+ * 获取条件判断函数。
*
- * @return 区块的条件
+ * @return 一个用于判断是否进入该区块的 Predicate
*/
@Override
public Predicate condition() {
@@ -98,9 +101,9 @@ public class FlexibleSectionParser {
}
/**
- * 获取该区块的解析器。
+ * 获取解析器函数。
*
- * @return 区块的解析器
+ * @return 一个解析该区块的 BiConsumer 函数
*/
@Override
public BiConsumer parser() {