提取出混合排列方法
This commit is contained in:
parent
92e36f3dd0
commit
030f8c5b44
@ -8,51 +8,46 @@ import org.jcnc.snow.compiler.parser.ast.StatementNode;
|
||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||
import org.jcnc.snow.compiler.parser.context.TokenStream;
|
||||
import org.jcnc.snow.compiler.parser.factory.StatementParserFactory;
|
||||
import org.jcnc.snow.compiler.parser.util.FlexibleSectionParser;
|
||||
import org.jcnc.snow.compiler.parser.util.FlexibleSectionParser.SectionDefinition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@code FunctionParser} 是一个顶层语法分析器,用于解析函数定义语法结构。
|
||||
* {@code FunctionParser} 是一个顶层语法分析器,用于解析函数定义的语法结构。
|
||||
* <p>
|
||||
* 它支持以下组成部分,且顺序可灵活排列:
|
||||
* 该解析器通过 {@code FlexibleSectionParser} 解析函数定义的多个部分,包括:
|
||||
* <ul>
|
||||
* <li>{@code function}:函数名声明</li>
|
||||
* <li>{@code parameter}:参数列表(支持可选的 {@code declare} 关键字)</li>
|
||||
* <li>{@code return_type}:返回类型声明</li>
|
||||
* <li>{@code body}:函数体代码块,包含函数内的语句</li>
|
||||
* <li>函数名</li>
|
||||
* <li>参数列表</li>
|
||||
* <li>返回类型</li>
|
||||
* <li>函数体</li>
|
||||
* </ul>
|
||||
* 每个部分的顺序是非固定的,只要结构合法即可。
|
||||
* </p>
|
||||
* 解析顺序不固定,且每个部分的解析逻辑由 {@code FlexibleSectionParser} 配合外部条件和解析器来控制。
|
||||
* <p>
|
||||
* 示例函数定义语法如下:
|
||||
* <pre>{@code
|
||||
* module: MathUtils
|
||||
* function: square_number
|
||||
* parameter:
|
||||
* declare number: int
|
||||
* return_type: int
|
||||
* body:
|
||||
* return number * number
|
||||
* end body
|
||||
* end function
|
||||
* end module
|
||||
* }</pre>
|
||||
* 本解析器将该结构转换为抽象语法树(AST)中的 {@code FunctionNode} 节点。
|
||||
* 解析过程中,函数定义的各个部分被依次解析,并最终构建成 {@code FunctionNode},作为抽象语法树的一部分。
|
||||
* </p>
|
||||
*/
|
||||
|
||||
public class FunctionParser implements TopLevelParser {
|
||||
|
||||
/**
|
||||
* 解析完整的函数结构,构建 FunctionNode 语法树节点。
|
||||
* 解析函数定义,构建函数的抽象语法树。
|
||||
* <p>
|
||||
* 此方法解析函数的多个部分,包括函数名、参数、返回类型和函数体。各部分的解析顺序由 {@code FlexibleSectionParser} 控制。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 解析上下文,包含 token 流和其他辅助信息。
|
||||
* @return 构造的函数语法树节点。
|
||||
* @param ctx 解析上下文,包含 Token 流等信息
|
||||
* @return 解析后的函数语法树节点
|
||||
*/
|
||||
@Override
|
||||
public FunctionNode parse(ParserContext ctx) {
|
||||
TokenStream tokens = ctx.getTokens();
|
||||
|
||||
// 匹配 function: 起始标签
|
||||
// 匹配函数头部
|
||||
parseFunctionHeader(tokens);
|
||||
|
||||
// 解析函数名
|
||||
@ -63,17 +58,41 @@ public class FunctionParser implements TopLevelParser {
|
||||
String[] returnType = {null}; // 模拟引用传参
|
||||
List<StatementNode> body = new ArrayList<>();
|
||||
|
||||
// 解析 parameter / return_type / body,顺序任意
|
||||
parseFlexibleSections(ctx, tokens, parameters, body, type -> returnType[0] = type);
|
||||
// 定义可变区块的解析规则
|
||||
Map<String, SectionDefinition> sectionDefinitions = new HashMap<>();
|
||||
|
||||
// 参数解析
|
||||
sectionDefinitions.put("parameter", new SectionDefinition(
|
||||
ts -> ts.peek().getLexeme().equals("parameter"),
|
||||
(ctx1, ts1) -> parameters.addAll(parseParameters(ts1))
|
||||
));
|
||||
|
||||
// 返回类型解析
|
||||
sectionDefinitions.put("return_type", new SectionDefinition(
|
||||
ts -> ts.peek().getLexeme().equals("return_type"),
|
||||
(ctx1, ts1) -> returnType[0] = parseReturnType(ts1)
|
||||
));
|
||||
|
||||
// 函数体解析
|
||||
sectionDefinitions.put("body", new SectionDefinition(
|
||||
ts -> ts.peek().getLexeme().equals("body"),
|
||||
(ctx1, ts1) -> body.addAll(parseFunctionBody(ctx1, ts1))
|
||||
));
|
||||
|
||||
// 使用 FlexibleSectionParser 解析函数的可变部分,顺序无关
|
||||
FlexibleSectionParser.parse(ctx, tokens, sectionDefinitions);
|
||||
|
||||
// 匹配函数结尾标签
|
||||
parseFunctionFooter(tokens);
|
||||
|
||||
// 返回构建好的函数节点
|
||||
return new FunctionNode(functionName, parameters, returnType[0], body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配 function 起始标志(function:)
|
||||
* 匹配并解析函数头部标记(例如:function:)。
|
||||
*
|
||||
* @param ts Token 流
|
||||
*/
|
||||
private void parseFunctionHeader(TokenStream ts) {
|
||||
ts.expect("function");
|
||||
@ -81,7 +100,10 @@ public class FunctionParser implements TopLevelParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配函数名称标识符,并跳过换行
|
||||
* 解析函数名并跳过换行符。
|
||||
*
|
||||
* @param ts Token 流
|
||||
* @return 函数名
|
||||
*/
|
||||
private String parseFunctionName(TokenStream ts) {
|
||||
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
||||
@ -90,77 +112,26 @@ public class FunctionParser implements TopLevelParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析函数的可变结构部分(parameter, return_type, body),顺序不限。
|
||||
* 匹配并解析函数结尾标记(例如:end function)。
|
||||
*
|
||||
* @param ctx 上下文
|
||||
* @param tokens Token 流
|
||||
* @param parameters 存储解析后的参数节点
|
||||
* @param body 存储解析后的语句节点
|
||||
* @param returnTypeSetter 设置返回类型(使用 lambda)
|
||||
* @param ts Token 流
|
||||
*/
|
||||
private void parseFlexibleSections(ParserContext ctx,
|
||||
TokenStream tokens,
|
||||
List<ParameterNode> parameters,
|
||||
List<StatementNode> body,
|
||||
java.util.function.Consumer<String> returnTypeSetter) {
|
||||
boolean parsedParam = false;
|
||||
boolean parsedReturn = false;
|
||||
boolean parsedBody = false;
|
||||
|
||||
while (true) {
|
||||
// 跳过空行
|
||||
while (tokens.peek().getType() == TokenType.NEWLINE) {
|
||||
tokens.next();
|
||||
}
|
||||
|
||||
// 获取当前关键字
|
||||
String keyword = tokens.peek().getLexeme();
|
||||
|
||||
switch (keyword) {
|
||||
case "parameter":
|
||||
if (parsedParam) throw new RuntimeException("重复定义 parameter 区块。");
|
||||
parameters.addAll(parseParameters(tokens));
|
||||
parsedParam = true;
|
||||
break;
|
||||
|
||||
case "return_type":
|
||||
if (parsedReturn) throw new RuntimeException("重复定义 return_type 区块。");
|
||||
returnTypeSetter.accept(parseReturnType(tokens));
|
||||
parsedReturn = true;
|
||||
break;
|
||||
|
||||
case "body":
|
||||
if (parsedBody) throw new RuntimeException("重复定义 body 区块。");
|
||||
body.addAll(parseFunctionBody(ctx, tokens));
|
||||
parsedBody = true;
|
||||
break;
|
||||
|
||||
case "end":
|
||||
return; // 完成可变区块的解析,继续处理函数结尾
|
||||
|
||||
default:
|
||||
throw new RuntimeException("函数定义中出现未识别的关键字: " + keyword);
|
||||
}
|
||||
}
|
||||
private void parseFunctionFooter(TokenStream ts) {
|
||||
ts.expect("end");
|
||||
ts.expect("function");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析参数定义区块。
|
||||
* 解析参数列表。
|
||||
* <p>
|
||||
* 语法格式示例:
|
||||
* <pre>
|
||||
* parameter:
|
||||
* declare param1: int
|
||||
* declare param2: string
|
||||
* </pre>
|
||||
* 每一行参数定义都必须以 <code>declare</code> 开头。
|
||||
* 方法将跳过空行,并在遇到下一个语句区块(如 return_type、body、end)时终止。
|
||||
* 该方法解析以 "declare" 开头的参数声明行,并返回一个包含参数的 {@code ParameterNode} 列表。
|
||||
* </p>
|
||||
*
|
||||
* @param ts Token 流,用于逐个读取语法标记
|
||||
* @return 参数节点列表,每个 {@link ParameterNode} 包含参数名和类型
|
||||
* @param ts Token 流
|
||||
* @return 参数节点列表
|
||||
*/
|
||||
private List<ParameterNode> parseParameters(TokenStream ts) {
|
||||
// 开始:匹配 "parameter:" 行
|
||||
ts.expect("parameter");
|
||||
ts.expect(":");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
@ -168,47 +139,33 @@ public class FunctionParser implements TopLevelParser {
|
||||
List<ParameterNode> params = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
// 跳过空行
|
||||
if (ts.peek().getType() == TokenType.NEWLINE) {
|
||||
ts.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
String lexeme = ts.peek().getLexeme();
|
||||
|
||||
// 遇到新语句区块的开始(结束当前参数解析块)
|
||||
if ("return_type".equals(lexeme) || "body".equals(lexeme) || "end".equals(lexeme)) {
|
||||
if ("return_type".equals(ts.peek().getLexeme()) || "body".equals(ts.peek().getLexeme()) || "end".equals(ts.peek().getLexeme())) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 参数定义必须以 "declare" 开头
|
||||
ts.expect("declare");
|
||||
|
||||
// 获取参数名称
|
||||
String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
||||
|
||||
// 冒号分隔符
|
||||
ts.expect(":");
|
||||
|
||||
// 参数类型
|
||||
String paramType = ts.expectType(TokenType.TYPE).getLexeme();
|
||||
|
||||
// 每行结束必须是 NEWLINE
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
|
||||
// 加入参数列表
|
||||
params.add(new ParameterNode(paramName, paramType));
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析返回类型区块。
|
||||
* 解析返回类型。
|
||||
*
|
||||
* @param ts Token 流
|
||||
* @return 返回类型字符串
|
||||
* @return 返回类型
|
||||
*/
|
||||
private String parseReturnType(TokenStream ts) {
|
||||
ts.expect("return_type");
|
||||
@ -219,25 +176,16 @@ public class FunctionParser implements TopLevelParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析函数体(body)部分,提取语句并构建 {@link StatementNode} 列表。
|
||||
* 解析函数体。
|
||||
* <p>
|
||||
* 语法结构形如:
|
||||
* <pre>{@code
|
||||
* body:
|
||||
* declare x:int = 5
|
||||
* if x > 0
|
||||
* ...
|
||||
* end body
|
||||
* }</pre>
|
||||
* <p>
|
||||
* 该方法将每一条语句委托给 {@link StatementParserFactory} 根据关键字调度解析器。
|
||||
* 该方法解析函数体中的每个语句,并返回一个 {@code StatementNode} 列表。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 上下文对象,包含词法流与全局状态
|
||||
* @param ts 当前的 Token 流(词法单元序列)
|
||||
* @return 包含函数体所有语句的列表
|
||||
* @param ctx 解析上下文
|
||||
* @param ts Token 流
|
||||
* @return 函数体的语句列表
|
||||
*/
|
||||
private List<StatementNode> parseFunctionBody(ParserContext ctx, TokenStream ts) {
|
||||
// 匹配 body: 起始标记
|
||||
ts.expect("body");
|
||||
ts.expect(":");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
@ -245,42 +193,24 @@ public class FunctionParser implements TopLevelParser {
|
||||
List<StatementNode> body = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
// 跳过空行,确保处理有效语句
|
||||
if (ts.peek().getType() == TokenType.NEWLINE) {
|
||||
ts.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 若遇到 end,则说明函数体结束,跳出循环
|
||||
if ("end".equals(ts.peek().getLexeme())) {
|
||||
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);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 匹配函数定义结束标志(end function)
|
||||
*
|
||||
* @param ts Token 流
|
||||
*/
|
||||
private void parseFunctionFooter(TokenStream ts) {
|
||||
ts.expect("end");
|
||||
ts.expect("function");
|
||||
ts.expectType(TokenType.NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,110 @@
|
||||
package org.jcnc.snow.compiler.parser.util;
|
||||
|
||||
import org.jcnc.snow.compiler.lexer.token.TokenType;
|
||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||
import org.jcnc.snow.compiler.parser.context.TokenStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 通用的解析器,用于解析结构化的内容部分,完全解耦合关键字和语法。
|
||||
* <p>
|
||||
* {@code FlexibleSectionParser} 提供了一个灵活的机制来解析可变的语法块。每个语法块的解析逻辑通过外部提供,
|
||||
* 该类仅负责按顺序解析不同的区块,直到遇到结束标记。它完全解耦了具体的语法关键字和解析逻辑。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 例如,您可以使用此类解析函数定义中的多个部分(如参数、返回类型、函数体等),而不需要在解析器中显式地硬编码每个部分。
|
||||
* </p>
|
||||
*/
|
||||
public class FlexibleSectionParser {
|
||||
|
||||
/**
|
||||
* 解析一系列的可变区块,解析顺序和具体内容由外部定义。
|
||||
* <p>
|
||||
* 该方法接受一个包含区块定义的映射,每个区块定义包含一个条件(`Predicate<TokenStream>`)和一个解析器(`BiConsumer<ParserContext, TokenStream>`)。
|
||||
* 条件用于判断是否应该解析该区块,解析器则负责实际的解析过程。
|
||||
* </p>
|
||||
*
|
||||
* @param ctx 解析上下文,包含词法流等信息
|
||||
* @param tokens 当前的 Token 流
|
||||
* @param sectionDefinitions 各种区块定义,键值为区块的名称,值为对应的解析器和条件
|
||||
*/
|
||||
public static void parse(ParserContext ctx,
|
||||
TokenStream tokens,
|
||||
Map<String, SectionDefinition> sectionDefinitions) {
|
||||
|
||||
// 跳过空行
|
||||
while (tokens.peek().getType() == TokenType.NEWLINE) {
|
||||
tokens.next();
|
||||
}
|
||||
|
||||
// 遍历所有可变部分的解析
|
||||
while (true) {
|
||||
String keyword = tokens.peek().getLexeme();
|
||||
|
||||
// 查找是否有与当前关键字匹配的区块
|
||||
SectionDefinition definition = sectionDefinitions.get(keyword);
|
||||
|
||||
if (definition != null && definition.getCondition().test(tokens)) {
|
||||
// 执行解析动作
|
||||
definition.getParser().accept(ctx, tokens);
|
||||
} else if ("end".equals(keyword)) {
|
||||
// 如果遇到 "end",则退出解析
|
||||
break;
|
||||
} else {
|
||||
throw new RuntimeException("未识别的关键字或条件不满足: " + keyword);
|
||||
}
|
||||
|
||||
// 跳过空行,继续解析
|
||||
while (tokens.peek().getType() == TokenType.NEWLINE) {
|
||||
tokens.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义区块的结构:每个区块有一个条件和一个解析器。
|
||||
* <p>
|
||||
* {@code SectionDefinition} 是描述如何解析某个语法块的结构。
|
||||
* 它包含一个条件(`Predicate<TokenStream>`),用于判断当前 Token 是否符合该区块的开始标识,
|
||||
* 以及一个解析器(`BiConsumer<ParserContext, TokenStream>`),用于执行具体的解析操作。
|
||||
* </p>
|
||||
*/
|
||||
public static class SectionDefinition {
|
||||
|
||||
private final Predicate<TokenStream> condition; // 条件,判断是否需要解析该区块
|
||||
private final BiConsumer<ParserContext, TokenStream> parser; // 区块的解析器
|
||||
|
||||
/**
|
||||
* 构造一个新的区块定义。
|
||||
*
|
||||
* @param condition 判断该区块是否应该解析的条件
|
||||
* @param parser 区块的解析器
|
||||
*/
|
||||
public SectionDefinition(Predicate<TokenStream> condition, BiConsumer<ParserContext, TokenStream> parser) {
|
||||
this.condition = condition;
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该区块的条件,用于判断是否解析此区块。
|
||||
*
|
||||
* @return 区块的条件
|
||||
*/
|
||||
public Predicate<TokenStream> getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该区块的解析器。
|
||||
*
|
||||
* @return 区块的解析器
|
||||
*/
|
||||
public BiConsumer<ParserContext, TokenStream> getParser() {
|
||||
return parser;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user