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