diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java index f18813f..3fa483c 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java @@ -13,62 +13,62 @@ import java.util.HashMap; import java.util.Map; /** - * {@code PrattExpressionParser} 基于 Pratt 算法的表达式解析器实现。 + * {@code PrattExpressionParser} *
- * 该类通过前缀(PrefixParselet)和中缀(InfixParselet)解析器注册表, - * 支持灵活扩展的表达式语法,包括字面量、变量、函数调用、成员访问和各种运算符表达式。 - *
- *- * 运算符优先级通过枚举控制,结合递归解析实现高效的优先级处理和语法结构解析。 - * 未注册的语法类型或运算符会统一抛出 {@link UnsupportedFeature} 异常。 + * 基于 Pratt 算法的表达式解析器(经典“运算符优先级”递归解析框架)。 + *
- * 用于存储所有支持的前缀表达式解析器,例如字面量、变量、分组、数组、一元运算等。 - * 支持通过 TokenType 的名称和特定词素(如 "(", "[")两种方式索引。 - *
+ * 前缀解析器注册表(通过 Token 类型名或词素作为索引)。 + *- * 用于存储所有支持的中缀表达式解析器,如二元运算、函数调用、下标、成员访问等。 - * 仅通过词素索引(如 "+", "-", "(", "[" 等)。 - *
+ * 中缀解析器注册表(通过运算符词素索引)。 + *- * 该方法将以最低优先级启动表达式递归解析,能够自动适配和处理多层嵌套或复杂组合表达式。 + * 能解析嵌套、复合等所有合法表达式结构。 *
* - * @param ctx 当前解析上下文对象(持有 token 流等信息) + * @param ctx 当前解析上下文对象(含 token 流等信息) * @return 解析得到的表达式 AST 节点对象 */ @Override @@ -106,50 +106,42 @@ public class PrattExpressionParser implements ExpressionParser { } /** - * 按指定优先级解析表达式(Pratt 算法核心)。 + * Pratt 算法主递归循环:按给定优先级递归解析表达式。 *- * 1. 先取当前 token,查找对应的前缀解析器进行初始解析,构建表达式左侧(如字面量、变量等)。 - * 2. 然后循环检测是否有更高优先级的中缀操作符, - * 若有则递归处理右侧表达式并组合为新的表达式节点。 - *
- *- * 未找到对应前缀或中缀解析器时会抛出 {@link UnsupportedFeature} 异常。 + * 实现按优先级吸收中缀操作符(如连续算术、链式调用、组合表达式等)。 *
* * @param ctx 解析上下文 - * @param prec 当前运算符优先级(用于控制递归层级) - * @return 解析构建好的表达式节点 - * @throws UnsupportedFeature 遇到未注册的解析器时抛出 + * @param prec 当前已绑定优先级 + * @return 已解析的表达式节点 */ ExpressionNode parseExpression(ParserContext ctx, Precedence prec) { - // 取下一个 token 作为本轮前缀表达式起始 + // 1) 消耗一个 token 作为前缀起点 Token token = ctx.getTokens().next(); - // 查找前缀解析器(先按类型名,再按词素) - PrefixParselet prefix = prefixes.get(token.getType().name()); + // 2) 查找前缀解析器(优先按词素,再按 TokenType) + PrefixParselet prefix = prefixes.get(token.getLexeme()); if (prefix == null) { - prefix = prefixes.get(token.getLexeme()); + prefix = prefixes.get(token.getType().name()); } if (prefix == null) { - // 未找到前缀解析器则报错 + // 未注册前缀解析器,直接报错 throw new UnsupportedFeature( - "没有为该 Token 类型注册前缀解析器: " + token.getType(), + "没有为该 Token 注册前缀解析器: " + token.getLexeme() + " / " + token.getType(), token.getLine(), token.getCol() ); } - // 执行前缀解析,获得左侧表达式 + // 3) 前缀解析得到左侧表达式 ExpressionNode left = prefix.parse(ctx, token); - // 不断尝试查找优先级更高的中缀运算符,递归处理表达式链 - while (!ctx.getTokens().isAtEnd() - && prec.ordinal() < nextPrecedence(ctx)) { - // 查看下一个 token 词素,查找中缀解析器 + // 4) 主循环:不断吸收更高优先级的中缀操作,直到优先级不再提升 + while (!ctx.getTokens().isAtEnd() && prec.ordinal() < nextPrecedence(ctx)) { String lex = ctx.getTokens().peek().getLexeme(); InfixParselet infix = infixes.get(lex); if (infix == null) { - // 若未注册中缀解析器,则直接抛异常(常见于语法错误) + // nextPrecedence > prec 时一般已注册中缀解析器 Token t = ctx.getTokens().peek(); throw new UnsupportedFeature( "没有为该运算符注册中缀解析器: '" + lex + "'", @@ -157,21 +149,21 @@ public class PrattExpressionParser implements ExpressionParser { t.getCol() ); } - // 使用中缀解析器处理表达式组合 + // 递归组合更高优先级的中缀表达式 left = infix.parse(ctx, left); } - // 返回本层递归已解析的表达式节点 + // 5) 返回本层解析完成的表达式节点 return left; } /** - * 获取下一个 token 词素对应的中缀运算符优先级(Pratt 算法关键)。 + * 获取下一个 token 对应的中缀运算符优先级(Pratt 算法关键)。 *- * 用于决定当前是否需要递归处理更高优先级的中缀操作。 + * 若无注册的中缀解析器,则返回 -1。 *
* - * @param ctx 当前解析上下文 - * @return 下一个中缀运算符的优先级序号;若无注册解析器则返回 -1 + * @param ctx 解析上下文 + * @return 下一个运算符优先级序号(无则-1) */ private int nextPrecedence(ParserContext ctx) { InfixParselet infix = infixes.get(ctx.getTokens().peek().getLexeme());