From ff51636fe7354bb7bb6b84afd08a6c8a0d20217e Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 23 Apr 2025 16:50:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Java=20Doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jcnc/snow/compiler/JsonFormatter.java | 42 +++++++++++--- .../snow/compiler/parser/ParserEngine.java | 27 +++++++-- .../snow/compiler/parser/TopLevelParser.java | 10 +++- .../parser/ast/ASTJsonSerializer.java | 19 ++++++- .../snow/compiler/parser/ast/ASTPrinter.java | 22 +++++-- .../compiler/parser/ast/AssignmentNode.java | 10 +++- .../parser/ast/BinaryExpressionNode.java | 12 +++- .../parser/ast/CallExpressionNode.java | 11 +++- .../compiler/parser/ast/DeclarationNode.java | 27 ++++++++- .../compiler/parser/ast/ExpressionNode.java | 4 +- .../parser/ast/ExpressionStatementNode.java | 5 +- .../compiler/parser/ast/FunctionNode.java | 8 ++- .../compiler/parser/ast/IdentifierNode.java | 10 +++- .../jcnc/snow/compiler/parser/ast/IfNode.java | 7 ++- .../snow/compiler/parser/ast/ImportNode.java | 6 +- .../snow/compiler/parser/ast/LoopNode.java | 14 ++++- .../parser/ast/MemberExpressionNode.java | 12 +++- .../snow/compiler/parser/ast/ModuleNode.java | 23 ++++++-- .../jcnc/snow/compiler/parser/ast/Node.java | 4 +- .../parser/ast/NumberLiteralNode.java | 10 +++- .../compiler/parser/ast/ParameterNode.java | 10 +++- .../snow/compiler/parser/ast/ReturnNode.java | 21 ++++++- .../compiler/parser/ast/StatementNode.java | 4 +- .../parser/ast/StringLiteralNode.java | 11 ++-- .../parser/context/ParseException.java | 9 ++- .../parser/context/ParserContext.java | 13 ++++- .../compiler/parser/context/TokenStream.java | 57 ++++++++++++++++--- .../expression/BinaryOperatorParselet.java | 29 ++++++++-- .../parser/expression/CallParselet.java | 27 +++++++-- .../parser/expression/ExpressionParser.java | 10 +++- .../parser/expression/GroupingParselet.java | 11 +++- .../parser/expression/IdentifierParselet.java | 11 +++- .../parser/expression/InfixParselet.java | 19 ++++++- .../parser/expression/MemberParselet.java | 22 +++++-- .../expression/NumberLiteralParselet.java | 11 +++- .../expression/PrattExpressionParser.java | 46 +++++++++++---- .../parser/expression/Precedence.java | 26 +++++++-- .../parser/expression/PrefixParselet.java | 11 +++- .../expression/StringLiteralParselet.java | 18 ++++-- .../factory/StatementParserFactory.java | 14 ++++- .../parser/factory/TopLevelParserFactory.java | 13 ++++- .../parser/function/FunctionParser.java | 49 +++++++++++----- .../compiler/parser/module/ImportParser.java | 23 +++++--- .../compiler/parser/module/ModuleParser.java | 27 +++++++-- .../statement/DeclarationStatementParser.java | 33 +++++++++-- .../statement/ExpressionStatementParser.java | 25 +++++--- .../parser/statement/IfStatementParser.java | 26 +++++++-- .../parser/statement/LoopStatementParser.java | 37 ++++++++---- .../statement/ReturnStatementParser.java | 22 ++++++- .../parser/statement/StatementParser.java | 10 +++- 50 files changed, 766 insertions(+), 162 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/JsonFormatter.java b/src/main/java/org/jcnc/snow/compiler/JsonFormatter.java index 4ae2e3c..5c1a41f 100644 --- a/src/main/java/org/jcnc/snow/compiler/JsonFormatter.java +++ b/src/main/java/org/jcnc/snow/compiler/JsonFormatter.java @@ -1,26 +1,44 @@ package org.jcnc.snow.compiler; +/** + * JSON 格式化工具类。 + * 提供将紧凑 JSON 字符串美化为带缩进和换行的易读格式的方法。 + */ public class JsonFormatter { + /** * 对一个紧凑的 JSON 字符串进行缩进美化。 - * @param json 紧凑的 JSON - * @return 带换行和缩进的 JSON + * 例如: + *
{@code
+     * {"a":1,"b":[2,3]} →
+     * {
+     *   "a": 1,
+     *   "b": [
+     *     2,
+     *     3
+     *   ]
+     * }
+     * }
+ * + * @param json 紧凑的 JSON 字符串。 + * @return 格式化后的 JSON 字符串,带有缩进与换行。 */ public static String prettyPrint(String json) { StringBuilder sb = new StringBuilder(); int indent = 0; boolean inQuotes = false; + for (int i = 0; i < json.length(); i++) { char c = json.charAt(i); - // 切换引号状态(忽略转义的 \") + + // 检查是否进入或退出字符串(忽略转义的引号) if (c == '"' && (i == 0 || json.charAt(i - 1) != '\\')) { inQuotes = !inQuotes; sb.append(c); } else if (!inQuotes) { switch (c) { case '{', '[': - sb.append(c) - .append('\n'); + sb.append(c).append('\n'); indent++; appendIndent(sb, indent); break; @@ -31,8 +49,7 @@ public class JsonFormatter { sb.append(c); break; case ',': - sb.append(c) - .append('\n'); + sb.append(c).append('\n'); appendIndent(sb, indent); break; case ':': @@ -44,14 +61,21 @@ public class JsonFormatter { } } } else { - // 在字符串内原样输出 + // 字符串内部原样输出 sb.append(c); } } + return sb.toString(); } + /** + * 向字符串构建器追加指定层级的缩进。 + * + * @param sb 输出目标。 + * @param indent 缩进层级(每层为两个空格)。 + */ private static void appendIndent(StringBuilder sb, int indent) { - sb.append(" ".repeat(Math.max(0, indent))); // 两个空格 + sb.append(" ".repeat(Math.max(0, indent))); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java b/src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java index 2dca672..fe6ee54 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java @@ -10,31 +10,48 @@ import java.util.ArrayList; import java.util.List; /** - * 解析引擎入口:循环读取顶层块直到 EOF,自动跳过空行(NEWLINE)。 + * 解析器主引擎,负责驱动顶层结构(如 module)解析。 + * 它会循环处理每个顶层语法块,直到遇到 EOF。 + * 同时自动跳过空行(NEWLINE)以增强容错性。 */ public class ParserEngine { private final ParserContext ctx; + /** + * 构造解析器引擎。 + * + * @param ctx 解析上下文,封装了 Token 流等解析状态。 + */ public ParserEngine(ParserContext ctx) { this.ctx = ctx; } + /** + * 启动解析流程,返回顶层节点列表(模块、导入等)。 + * + * @return 所有解析出的 AST 顶层节点。 + */ public List parse() { List nodes = new ArrayList<>(); TokenStream ts = ctx.getTokens(); + while (ts.isAtEnd()) { - // 跳过空行(NEWLINE) + // 跳过空行 if (ts.peek().getType() == TokenType.NEWLINE) { ts.next(); continue; } + + // 根据当前关键字分发顶层解析器 String lex = ts.peek().getLexeme(); - TopLevelParser p = TopLevelParserFactory.get(lex); - if (p == null) { + TopLevelParser parser = TopLevelParserFactory.get(lex); + if (parser == null) { throw new IllegalStateException("Unexpected top-level token: " + lex); } - nodes.add(p.parse(ctx)); + + nodes.add(parser.parse(ctx)); } + return nodes; } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/TopLevelParser.java b/src/main/java/org/jcnc/snow/compiler/parser/TopLevelParser.java index 926394c..1e3de17 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/TopLevelParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/TopLevelParser.java @@ -4,8 +4,16 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.ast.Node; /** - * 顶层解析器接口,如 module、import 等。 + * 顶层结构解析器接口,用于解析模块级别的语法结构,如 {@code module}、{@code import} 等。 + * 所有顶层解析器应实现该接口。 */ public interface TopLevelParser { + + /** + * 从解析上下文中解析一个顶层语法结构。 + * + * @param ctx 当前解析上下文。 + * @return 表示顶层结构的 AST 节点。 + */ Node parse(ParserContext ctx); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTJsonSerializer.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTJsonSerializer.java index 65920f5..31a3595 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTJsonSerializer.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTJsonSerializer.java @@ -2,8 +2,19 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.List; + +/** + * ASTJsonSerializer 是一个用于将抽象语法树(AST)序列化为 JSON 字符串的工具类。 + * 该类通过访问不同类型的语法树节点,将其结构以标准 JSON 格式输出,适用于调试、可视化或进一步处理。 + */ public class ASTJsonSerializer { + /** + * 将语法树节点列表序列化为 JSON 字符串。 + * + * @param ast 抽象语法树的节点列表。 + * @return 表示整个 AST 的 JSON 字符串。 + */ public static String toJsonString(List ast) { StringBuilder sb = new StringBuilder(); sb.append("["); @@ -189,8 +200,12 @@ public class ASTJsonSerializer { + "}"; } - /** 把 Java 字符串内容转成 JSON 字符串常量(加双引号并转义) */ - private static String quote(String s) { + /** + * 将字符串转换为合法的 JSON 字符串常量(添加双引号并进行必要的转义)。 + * + * @param s 原始字符串。 + * @return 转义并加双引号的 JSON 字符串。 + */ private static String quote(String s) { StringBuilder sb = new StringBuilder(); sb.append("\""); for (char c : s.toCharArray()) { diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTPrinter.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTPrinter.java index 8ca04d1..df2018b 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ASTPrinter.java @@ -3,17 +3,30 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.List; /** - * 一个简单的 AST 打印器,将所有节点格式化成可读的多行文本。 + * AST 打印器,用于将抽象语法树(AST)中的节点打印为可读的、格式化的多行文本。 + * 每个节点根据其类型和结构打印相应的缩进层级,便于人类阅读和调试。 */ public class ASTPrinter { + + /** + * 打印整个语法树的节点列表。 + * + * @param nodes 要打印的 AST 节点列表,通常是顶层模块或语句。 + */ public static void print(List nodes) { for (Node n : nodes) { print(n, 0); } } + /** + * 打印单个节点及其子节点,带有缩进格式。 + * + * @param n 要打印的节点。 + * @param indent 当前的缩进层级(每层两个空格)。 + */ private static void print(Node n, int indent) { - String pad = " ".repeat(indent); + String pad = " ".repeat(indent); // 缩进字符串 switch (n) { case ModuleNode m -> { @@ -65,9 +78,10 @@ public class ASTPrinter { } case ReturnNode r -> System.out.println(pad + "return" + r.getExpression().map(e -> " " + e).orElse("")); - case ExpressionStatementNode(ExpressionNode expression) -> System.out.println(pad + expression); + case ExpressionStatementNode(ExpressionNode expression) -> + System.out.println(pad + expression); case null, default -> - // 回退:直接调用 toString() + // 回退:如果节点类型不在上述范围内,则使用 toString() System.out.println(pad + n); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java index 734b375..c65aea0 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java @@ -1,10 +1,18 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 赋值语句节点,例如 x = expr。 + * 表示赋值语句的 AST(抽象语法树)节点,例如 {@code x = expr}。 + * + * @param variable 赋值语句左侧的变量名。 + * @param value 赋值语句右侧的表达式节点,表示要赋给变量的值。 */ public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode { + /** + * 返回赋值语句的字符串表示形式,例如 {@code x = y + 1}。 + * + * @return 表示赋值语句的字符串。 + */ @Override public String toString() { return variable + " = " + value; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java index bba717e..fef5cd2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java @@ -1,11 +1,21 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 二元运算表达式节点,如 a + b。 + * 表示二元运算表达式的 AST 节点,例如 {@code a + b}。 + * 该节点包含一个左操作数、一个操作符字符串和一个右操作数。 + * + * @param left 表达式左侧的子表达式。 + * @param operator 运算符字符串,例如 "+"、"-"、"*"、"/" 等。 + * @param right 表达式右侧的子表达式。 */ public record BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right) implements ExpressionNode { + /** + * 返回该二元表达式的字符串表示形式,例如 {@code a + b}。 + * + * @return 表达式的字符串形式。 + */ @Override public String toString() { return left + " " + operator + " " + right; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java index d567fa6..d9a908f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java @@ -3,10 +3,19 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.List; /** - * 函数调用表达式节点:callee(args…)。 + * 表示函数调用表达式的 AST 节点,例如 {@code foo(arg1, arg2)}。 + * 包含一个被调用的表达式(callee)和一个参数列表(arguments)。 + * + * @param callee 被调用的表达式,通常是一个标识符或成员访问表达式。 + * @param arguments 函数调用的参数列表,每个参数都是一个表达式节点。 */ public record CallExpressionNode(ExpressionNode callee, List arguments) implements ExpressionNode { + /** + * 返回函数调用表达式的字符串表示形式,例如 {@code foo(x, y)}。 + * + * @return 表达式的字符串形式。 + */ @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java index aab840c..82b7be7 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java @@ -3,20 +3,45 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.Optional; /** - * declare 语句节点:声明变量,可选初始化表达式。 + * 表示变量声明语句的 AST 节点,例如 {@code int x = 5;}。 + * 该节点包含变量名称、类型,以及可选的初始化表达式。 */ public class DeclarationNode implements StatementNode { private final String name; private final String type; private final Optional initializer; + /** + * 构造一个变量声明节点。 + * + * @param name 变量的名称。 + * @param type 变量的类型(例如 "int", "string")。 + * @param initializer 可选的初始化表达式,若为 null 表示未初始化。 + */ public DeclarationNode(String name, String type, ExpressionNode initializer) { this.name = name; this.type = type; this.initializer = Optional.ofNullable(initializer); } + /** + * 获取变量名称。 + * + * @return 变量名字符串。 + */ public String getName() { return name; } + + /** + * 获取变量类型。 + * + * @return 变量类型字符串。 + */ public String getType() { return type; } + + /** + * 获取可选的初始化表达式。 + * + * @return 包含初始化表达式的 Optional 对象,可能为空。 + */ public Optional getInitializer() { return initializer; } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionNode.java index 5aceece..62ebab1 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionNode.java @@ -1,6 +1,8 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 标记所有表达式节点。 + * 表示抽象语法树中的表达式节点类型。 + * 所有具体的表达式(如常量、变量、运算、函数调用等)都应实现该接口。 + * 这是一个标记接口(marker interface),用于统一处理所有表达式节点。 */ public interface ExpressionNode extends Node {} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java index c5b7eb7..e446a82 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java @@ -1,7 +1,10 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 单独的表达式语句节点(如函数调用、赋值等)。 + * 表示一条独立的表达式语句,例如 {@code foo();} 或 {@code x = 1;}。 + * 该节点将一个表达式作为语句出现。 + * + * @param expression 表达式内容,通常是函数调用或赋值操作。 */ public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode { } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java index cf36cf0..f213345 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java @@ -3,7 +3,13 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.List; /** - * 函数定义节点:包含函数名、参数列表、返回类型和函数体语句列表。 + * 表示函数定义的 AST 节点,包含函数名、参数、返回类型和函数体。 + * 示例:{@code int add(int a, int b) { return a + b; }} + * + * @param name 函数名称。 + * @param parameters 参数列表,每个参数是一个 {@link ParameterNode}。 + * @param returnType 返回值类型,表示函数的返回类型(例如 "int"、"void")。 + * @param body 函数体,由若干语句组成的列表。 */ public record FunctionNode(String name, List parameters, String returnType, List body) implements Node { diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java index 4f3af86..e50f8e5 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java @@ -1,9 +1,17 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 标识符表达式节点。 + * 表示标识符的表达式节点,例如变量名 {@code x}、函数名 {@code foo} 等。 + * + * @param name 标识符的名称。 */ public record IdentifierNode(String name) implements ExpressionNode { + + /** + * 返回标识符的字符串表示形式,即其名称。 + * + * @return 标识符名称字符串。 + */ @Override public String toString() { return name; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java index 5f993e5..351537d 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java @@ -3,7 +3,12 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.List; /** - * if 语句节点:包含条件表达式和 then 分支语句列表。 + * 表示 if 语句的 AST 节点。 + * 包含一个条件表达式和一个 then 分支的语句列表,不包含 else 分支。 + * 示例:{@code if (x > 0) { print(x); }} + * + * @param condition 条件表达式,控制是否执行 then 分支。 + * @param thenBranch 条件为真时执行的语句列表。 */ public record IfNode(ExpressionNode condition, List thenBranch) implements StatementNode { } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java index fca6340..865ee00 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java @@ -1,7 +1,11 @@ package org.jcnc.snow.compiler.parser.ast; /** - * import 语句节点:仅保存被导入模块名。 + * 表示 import 语句的 AST 节点。 + * 该节点仅包含被导入模块的名称。 + * 示例:{@code import my.module;} + * + * @param moduleName 被导入的模块名称。 */ public record ImportNode(String moduleName) implements Node { } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java index 42e3d2f..4d7548f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java @@ -3,7 +3,19 @@ package org.jcnc.snow.compiler.parser.ast; import java.util.List; /** - * loop 语句节点:包含初始化语句、条件表达式、更新语句和循环体。 + * 表示循环语句(loop)的 AST 节点,结构类似于传统的 for 循环。 + * 包含初始化语句、循环条件、更新语句和循环体。 + * 示例: + * {@code + * for (int i = 0; i < 10; i++) { + * print(i); + * } + * } + * + * @param initializer 循环开始前执行的初始化语句。 + * @param condition 每次迭代前都会评估的条件表达式。 + * @param update 每次迭代结束时执行的更新语句。 + * @param body 循环体内的语句列表。 */ public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update, List body) implements StatementNode { diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java index 3846a30..14c2277 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java @@ -1,9 +1,19 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 成员访问表达式节点,如 obj.prop。 + * 表示成员访问的表达式节点,例如 {@code obj.prop}。 + * 包含一个对象表达式和成员名称。 + * + * @param object 表达式左侧的对象部分,通常是一个标识符或更复杂的表达式。 + * @param member 成员名称,表示要访问的字段或方法。 */ public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode { + + /** + * 返回成员访问表达式的字符串表示形式,例如 {@code obj.prop}。 + * + * @return 成员访问表达式的字符串形式。 + */ @Override public String toString() { return object + "." + member; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java index 8bfa9e2..9e44581 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java @@ -1,16 +1,29 @@ -// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java package org.jcnc.snow.compiler.parser.ast; import java.util.List; import java.util.StringJoiner; /** - * 模块定义节点:包含模块名、import 列表和函数列表。 + * 表示模块定义的 AST 节点。 + * 一个模块通常由模块名、导入语句列表和函数定义列表组成。 + * 示例结构: + * {@code + * module my.module { + * import other.module; + * fun foo() { ... } + * } + * } + * + * @param name 模块名称。 + * @param imports 模块导入列表,每个导入是一个 {@link ImportNode}。 + * @param functions 模块中的函数列表,每个函数是一个 {@link FunctionNode}。 */ public record ModuleNode(String name, List imports, List functions) implements Node { /** - * 返回模块的字符串表示,便于调试和打印。 + * 返回模块节点的字符串表示形式,包含模块名、导入模块列表和函数列表。 + * + * @return 模块的简洁字符串表示,用于调试和日志输出。 */ @Override public String toString() { @@ -23,7 +36,7 @@ public record ModuleNode(String name, List imports, List + *
  • {@code return;}
  • + *
  • {@code return x + 1;}
  • + * */ public class ReturnNode implements StatementNode { private final Optional expression; + /** + * 构造一个 return 语句节点。 + * + * @param expression 可选的返回表达式,若为 null 则表示无返回值。 + */ public ReturnNode(ExpressionNode expression) { this.expression = Optional.ofNullable(expression); } - public Optional getExpression() { return expression; } + /** + * 获取返回表达式。 + * + * @return 表示返回值的可选表达式,如果没有则为 {@code Optional.empty()}。 + */ + public Optional getExpression() { + return expression; + } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/StatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/StatementNode.java index 0ee1141..0cbea88 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/StatementNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/StatementNode.java @@ -1,6 +1,8 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 标记所有语句节点。 + * 表示语法树中的语句节点类型。 + * 所有语句类(如声明、赋值、if、loop、return 等)都应实现该接口。 + * 这是一个标记接口(marker interface),用于统一处理所有语句节点。 */ public interface StatementNode extends Node {} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java index 01d7b5e..2a13739 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java @@ -1,15 +1,18 @@ package org.jcnc.snow.compiler.parser.ast; /** - * 字符串字面量表达式节点,如 "hello"。 + * 表示字符串字面量的表达式节点,例如 {@code "hello"}。 + * 字面量值不包含引号,仅在打印时添加。 * - * @param value 不包含引号的字符串内容 + * @param value 字符串内容,不包括两端引号。 */ public record StringLiteralNode(String value) implements ExpressionNode { /** - * 打印时在两端加上引号, - * 例如 value = Result:,则 toString() 返回 "Result:"。 + * 返回带引号的字符串表示形式,适用于调试和打印。 + * 例如:如果 {@code value = Result:},则 {@code toString()} 返回 {@code "Result:"}。 + * + * @return 添加双引号后的字符串字面量。 */ @Override public String toString() { diff --git a/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java b/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java index ebdb0d3..bc382d3 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java @@ -1,9 +1,16 @@ package org.jcnc.snow.compiler.parser.context; /** - * 解析时抛出的异常,用于语法错误报告。 + * 表示解析过程中发生的异常,通常用于报告语法错误。 + * 在语法分析器发现非法语法或无法处理的结构时抛出。 */ public class ParseException extends RuntimeException { + + /** + * 构造一个解析异常实例,并提供错误消息。 + * + * @param message 错误描述信息,用于指出语法错误的详情。 + */ public ParseException(String message) { super(message); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java b/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java index 1c9bf75..90384a2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java @@ -4,15 +4,26 @@ import org.jcnc.snow.compiler.lexer.token.Token; import java.util.List; /** - * Parser 共享上下文,包含 TokenStream,可扩展错误收集、符号表等功能。 + * 表示解析器的共享上下文,封装了当前的 {@link TokenStream}。 + * 后续还可以扩展为包含错误收集器、符号表、作用域信息等。 */ public class ParserContext { private final TokenStream tokens; + /** + * 构造解析上下文,并包装传入的词法单元列表为 {@link TokenStream}。 + * + * @param tokens 词法分析器生成的 token 列表。 + */ public ParserContext(List tokens) { this.tokens = new TokenStream(tokens); } + /** + * 获取当前的 Token 流,用于驱动语法解析过程。 + * + * @return token 流实例。 + */ public TokenStream getTokens() { return tokens; } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/context/TokenStream.java b/src/main/java/org/jcnc/snow/compiler/parser/context/TokenStream.java index ac76751..a8066b6 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/context/TokenStream.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/context/TokenStream.java @@ -6,18 +6,29 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; import java.util.List; /** - * 封装 Token 列表并维护当前位置,提供 peek/next/match/expect 等操作, - * 现在新增 peek(offset) 以便在解析赋值时向前看一个 Token。 + * 封装 Token 列表并维护当前位置,用于解析器消费 Token 的工具类。 + * 提供常见的操作如 {@code peek}(查看)、{@code next}(消费)、{@code match}(匹配)、 + * {@code expect}(断言)等,支持向前查看多个 Token 以实现前瞻解析。 */ public class TokenStream { private final List tokens; private int pos = 0; + /** + * 构造 Token 流对象。 + * + * @param tokens 从词法分析器生成的 Token 列表。 + */ public TokenStream(List tokens) { this.tokens = tokens; } - /** 向前 offset 个位置的 Token,不消费 */ + /** + * 向前查看指定偏移量的 Token(不消费)。 + * + * @param offset 相对于当前位置的偏移量(例如 0 表示当前位置)。 + * @return 对应位置的 Token,如果越界则返回 EOF Token。 + */ public Token peek(int offset) { int idx = pos + offset; if (idx >= tokens.size()) { @@ -26,19 +37,32 @@ public class TokenStream { return tokens.get(idx); } - /** 默认 peek(0) */ + /** + * 查看当前位置的 Token,等价于 {@code peek(0)}。 + * + * @return 当前 Token。 + */ public Token peek() { return peek(0); } - /** 消费并返回当前 Token */ + /** + * 消费并返回当前位置的 Token,内部位置前移。 + * + * @return 当前的 Token。 + */ public Token next() { Token t = peek(); pos++; return t; } - /** 如果当前词素等于 lexeme,则消费并返回 true */ + /** + * 如果当前 Token 的词素等于指定字符串,则消费该 Token 并返回 true。 + * + * @param lexeme 要匹配的词素。 + * @return 是否成功匹配。 + */ public boolean match(String lexeme) { if (peek().getLexeme().equals(lexeme)) { next(); @@ -47,7 +71,13 @@ public class TokenStream { return false; } - /** 断言 lexeme,否则抛错 */ + /** + * 断言当前 Token 的词素等于指定字符串,否则抛出 {@link ParseException}。 + * + * @param lexeme 期望的词素。 + * @return 匹配的 Token。 + * @throws ParseException 如果词素不匹配。 + */ public Token expect(String lexeme) { Token t = peek(); if (!t.getLexeme().equals(lexeme)) { @@ -59,7 +89,13 @@ public class TokenStream { return next(); } - /** 断言类型,否则抛错 */ + /** + * 断言当前 Token 的类型等于指定类型,否则抛出 {@link ParseException}。 + * + * @param type 期望的 Token 类型。 + * @return 匹配的 Token。 + * @throws ParseException 如果类型不匹配。 + */ public Token expectType(TokenType type) { Token t = peek(); if (t.getType() != type) { @@ -71,6 +107,11 @@ public class TokenStream { return next(); } + /** + * 判断是否还未到达文件结尾(EOF)。 + * + * @return 如果当前位置的 Token 不是 EOF,则返回 true。 + */ public boolean isAtEnd() { return peek().getType() != TokenType.EOF; } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java index 77142df..13a8f06 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java @@ -6,29 +6,48 @@ import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 解析二元运算符表达式,支持左/右结合。 + * 表示中缀二元运算符的解析规则(parselet),用于解析如 {@code a + b} 的表达式结构。 + * 支持设置运算符的优先级和结合性(左结合或右结合)。 */ public class BinaryOperatorParselet implements InfixParselet { private final Precedence precedence; private final boolean leftAssoc; + /** + * 构造二元运算符的解析器。 + * + * @param precedence 运算符的优先级。 + * @param leftAssoc 是否是左结合(true 表示左结合,false 表示右结合)。 + */ public BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) { this.precedence = precedence; this.leftAssoc = leftAssoc; } + /** + * 解析一个中缀表达式。 + * + * @param ctx 解析上下文,包含 Token 流等信息。 + * @param left 当前已解析出的左表达式。 + * @return 一个新的 {@link BinaryExpressionNode} 表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { - Token op = ctx.getTokens().next(); + Token op = ctx.getTokens().next(); // 获取当前运算符 Token int prec = precedence.ordinal(); - // 若左结合,则右侧优先级减一 + // 如果是左结合运算符,右表达式的优先级应减一(右边绑定更紧) ExpressionNode right = new PrattExpressionParser().parseExpression( - ctx, - leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1] + ctx, + leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1] ); return new BinaryExpressionNode(left, op.getLexeme(), right); } + /** + * 返回该运算符的优先级。 + * + * @return 当前运算符的优先级枚举。 + */ @Override public Precedence getPrecedence() { return precedence; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java index 965862c..8a90214 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java @@ -8,23 +8,40 @@ import java.util.ArrayList; import java.util.List; /** - * 解析函数调用:left ( args… ) + * 表示函数调用的解析规则(parselet),用于解析形如 {@code foo(arg1, arg2)} 的调用表达式。 + * 函数调用的结构为:已解析的 callee 表达式后接一对圆括号和参数列表。 */ public class CallParselet implements InfixParselet { + + /** + * 解析函数调用表达式,形如 {@code callee(args...)}。 + * + * @param ctx 解析上下文,包含 Token 流等信息。 + * @param left 已解析的函数名或调用目标(即 callee 表达式)。 + * @return 生成的 {@link CallExpressionNode} 表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { - // 已知 peek 是 "(" - ctx.getTokens().next(); // consume "(" + ctx.getTokens().next(); // 消费 "(" + List args = new ArrayList<>(); + + // 如果不是空参数列表 if (!ctx.getTokens().peek().getLexeme().equals(")")) { do { args.add(new PrattExpressionParser().parse(ctx)); - } while (ctx.getTokens().match(",")); + } while (ctx.getTokens().match(",")); // 支持多个参数,用逗号分隔 } - ctx.getTokens().expect(")"); + + ctx.getTokens().expect(")"); // 消费并校验 ")" return new CallExpressionNode(left, args); } + /** + * 获取函数调用的优先级,通常是最高级别之一。 + * + * @return {@link Precedence#CALL} 表示函数调用的绑定紧密度。 + */ @Override public Precedence getPrecedence() { return Precedence.CALL; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/ExpressionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/ExpressionParser.java index 7bf554c..fa8138f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/ExpressionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/ExpressionParser.java @@ -4,8 +4,16 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 表达式解析接口。 + * 表达式解析器接口,用于从 {@link ParserContext} 中解析出一个完整的 {@link ExpressionNode} 表达式。 + * 不同的解析器实现可以支持不同的解析策略(如 Pratt 解析、递归下降等)。 */ public interface ExpressionParser { + + /** + * 从解析上下文中解析一个表达式。 + * + * @param ctx 当前的解析上下文。 + * @return 解析后的表达式节点。 + */ ExpressionNode parse(ParserContext ctx); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/GroupingParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/GroupingParselet.java index d7dbc7d..2db4d4a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/GroupingParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/GroupingParselet.java @@ -5,9 +5,18 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 解析括号表达式: ( expr ) + * 解析圆括号包裹的表达式,例如 {@code (a + b)}。 + * 用于提升子表达式的优先级,使其在整体表达式中优先计算。 */ public class GroupingParselet implements PrefixParselet { + + /** + * 解析括号表达式。假定当前 token 是左括号 "(",解析中间的表达式并消费右括号 ")"。 + * + * @param ctx 当前解析上下文。 + * @param token 当前起始 token(应为 "(")。 + * @return 被括号包围的表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { ExpressionNode expr = new PrattExpressionParser().parse(ctx); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java index 790d31e..af6fd9f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java @@ -6,9 +6,18 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 解析标识符。 + * 用于解析标识符(identifier)的前缀解析器。 + * 例如:变量名、函数名等单词形式的表达式,如 {@code x}、{@code count}、{@code isValid} 等。 */ public class IdentifierParselet implements PrefixParselet { + + /** + * 将当前的标识符 Token 解析为 {@link IdentifierNode} 表达式节点。 + * + * @param ctx 当前解析上下文(未使用)。 + * @param token 当前的标识符 Token。 + * @return 一个表示标识符的表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { return new IdentifierNode(token.getLexeme()); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/InfixParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/InfixParselet.java index 3b9a430..42c30ce 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/InfixParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/InfixParselet.java @@ -4,9 +4,26 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 中缀解析器接口:处理二元运算、函数调用、成员访问等。 + * 中缀解析器接口(InfixParselet),用于处理中缀表达式的解析逻辑。 + * 例如二元运算符(如 {@code a + b})、函数调用(如 {@code f(x)})或成员访问(如 {@code obj.prop})。 + * 实现类需提供解析方法及该表达式的优先级。 */ public interface InfixParselet { + + /** + * 解析一个中缀表达式。 + * + * @param ctx 解析上下文。 + * @param left 当前已解析的左侧表达式。 + * @return 组合后的完整表达式节点。 + */ ExpressionNode parse(ParserContext ctx, ExpressionNode left); + + /** + * 获取当前中缀表达式的优先级。 + * 优先级用于决定运算符的绑定顺序。 + * + * @return 表达式的优先级。 + */ Precedence getPrecedence(); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java index 9e24470..6fc405e 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java @@ -7,21 +7,35 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.context.TokenStream; /** - * 解析成员访问表达式: left . IDENTIFIER + * 用于解析成员访问表达式的中缀解析器,例如 {@code object.property}。 + * 成员访问是一种紧绑定表达式,常用于访问对象的字段或方法。 */ public class MemberParselet implements InfixParselet { + + /** + * 解析成员访问表达式,形如 {@code left.member}。 + * + * @param ctx 解析上下文。 + * @param left 已解析的左侧表达式(对象)。 + * @return 一个 {@link MemberExpressionNode} 表示成员访问的表达式。 + */ @Override public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { TokenStream ts = ctx.getTokens(); - // 消费掉 "." - ts.expect("."); - // 现在下一个一定是标识符 + ts.expect("."); // 消费点号 + // 接下来应为标识符 String member = ts .expectType(TokenType.IDENTIFIER) .getLexeme(); return new MemberExpressionNode(left, member); } + /** + * 获取成员访问表达式的优先级。 + * 与函数调用一样,通常具有较高的优先级。 + * + * @return {@link Precedence#CALL},表示高优先级。 + */ @Override public Precedence getPrecedence() { return Precedence.CALL; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java index 5077f63..68403b2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java @@ -6,9 +6,18 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 解析数字字面量。 + * 用于解析数字字面量的前缀解析器。 + * 例如 {@code 42}、{@code 3.14} 等常量数值表达式。 */ public class NumberLiteralParselet implements PrefixParselet { + + /** + * 解析一个数字字面量 Token,转换为 {@link NumberLiteralNode} 表达式节点。 + * + * @param ctx 当前解析上下文(未使用)。 + * @param token 当前的数字 Token。 + * @return 表示数字字面量的表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { return new NumberLiteralNode(token.getLexeme()); 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 dd0d740..de7af9f 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 @@ -9,45 +9,61 @@ import java.util.HashMap; import java.util.Map; /** - * Pratt 算法实现的表达式解析器,支持算术、比较、调用、成员访问、字面量等。 + * 基于 Pratt 算法的表达式解析器,实现灵活优雅的运算符优先级与结合性处理。 + * 支持数字、字符串、标识符、分组表达式、二元运算、函数调用、成员访问等。 */ public class PrattExpressionParser implements ExpressionParser { + private static final Map prefixes = new HashMap<>(); private static final Map infixes = new HashMap<>(); static { - // 注册前缀 parselet + // 注册前缀解析器(PrefixParselet) prefixes.put(TokenType.NUMBER_LITERAL.name(), new NumberLiteralParselet()); prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet()); prefixes.put(TokenType.LPAREN.name(), new GroupingParselet()); - prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet()); // 新增 + prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet()); // 字符串字面量支持 - // 注册中缀 parselet(略,保持原样) - infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true)); - infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true)); - infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, true)); - infixes.put("/", new BinaryOperatorParselet(Precedence.PRODUCT, true)); + // 注册中缀解析器(InfixParselet) + infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true)); + infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true)); + infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, true)); + infixes.put("/", new BinaryOperatorParselet(Precedence.PRODUCT, true)); infixes.put(">", new BinaryOperatorParselet(Precedence.SUM, true)); infixes.put("<", new BinaryOperatorParselet(Precedence.SUM, true)); infixes.put("==", new BinaryOperatorParselet(Precedence.SUM, true)); infixes.put("!=", new BinaryOperatorParselet(Precedence.SUM, true)); infixes.put(">=", new BinaryOperatorParselet(Precedence.SUM, true)); infixes.put("<=", new BinaryOperatorParselet(Precedence.SUM, true)); - infixes.put("(", new CallParselet()); - infixes.put(".", new MemberParselet()); + infixes.put("(", new CallParselet()); + infixes.put(".", new MemberParselet()); } + /** + * 解析完整表达式,入口方法,使用最低优先级启动解析。 + * + * @param ctx 解析上下文。 + * @return 表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx) { return parseExpression(ctx, Precedence.LOWEST); } + /** + * 根据当前优先级解析表达式。 + * + * @param ctx 解析上下文。 + * @param prec 当前解析优先级。 + * @return 表达式节点。 + */ ExpressionNode parseExpression(ParserContext ctx, Precedence prec) { Token token = ctx.getTokens().next(); PrefixParselet prefix = prefixes.get(token.getType().name()); if (prefix == null) { - throw new IllegalStateException("No prefix for " + token.getType()); + throw new IllegalStateException("No prefix parselet registered for token type: " + token.getType()); } + ExpressionNode left = prefix.parse(ctx, token); while (ctx.getTokens().isAtEnd() && @@ -55,11 +71,19 @@ public class PrattExpressionParser implements ExpressionParser { String lex = ctx.getTokens().peek().getLexeme(); InfixParselet infix = infixes.get(lex); if (infix == null) break; + left = infix.parse(ctx, left); } + return left; } + /** + * 获取下一个中缀运算符的优先级。 + * + * @param ctx 当前解析上下文。 + * @return 若存在下一个中缀解析器,则返回其优先级 ordinal;否则返回 -1。 + */ private int nextPrecedence(ParserContext ctx) { InfixParselet infix = infixes.get(ctx.getTokens().peek().getLexeme()); return infix != null ? infix.getPrecedence().ordinal() : -1; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java index a706e19..5b53746 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java @@ -1,11 +1,27 @@ package org.jcnc.snow.compiler.parser.expression; /** - * 运算符优先级枚举,用于 Pratt 算法比较。 + * 表示运算符优先级的枚举类型,用于 Pratt 解析算法中比较不同运算符的绑定紧密度。 + * 数值越大,优先级越高。 */ public enum Precedence { - LOWEST, // 最低 - SUM, // + - - PRODUCT, // * / - CALL // 函数调用、成员访问 + /** + * 最低优先级,通常用于解析入口。 + */ + LOWEST, + + /** + * 加法、减法等二元运算(+,-)。 + */ + SUM, + + /** + * 乘法、除法等优先级更高的二元运算(*,/)。 + */ + PRODUCT, + + /** + * 函数调用、成员访问(例如 {@code foo()}、{@code obj.prop}),绑定最紧密。 + */ + CALL } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrefixParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrefixParselet.java index 444f07c..dc2a3e8 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrefixParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrefixParselet.java @@ -5,8 +5,17 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.lexer.token.Token; /** - * 前缀解析器接口:处理数字字面量、标识符、括号等前缀。 + * 前缀解析器接口(PrefixParselet),用于解析以当前 Token 开头的前缀表达式。 + * 典型的前缀表达式包括数字字面量、标识符、括号表达式、前缀运算符等。 */ public interface PrefixParselet { + + /** + * 解析一个前缀表达式。 + * + * @param ctx 当前的解析上下文。 + * @param token 当前的前缀 Token。 + * @return 解析得到的表达式节点。 + */ ExpressionNode parse(ParserContext ctx, Token token); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java index 2f0b2dc..e020981 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java @@ -6,15 +6,23 @@ import org.jcnc.snow.compiler.parser.ast.StringLiteralNode; import org.jcnc.snow.compiler.parser.context.ParserContext; /** - * 解析字符串字面量前缀,并去掉两端的引号。 + * 用于解析字符串字面量的前缀解析器。 + * 会从原始 Token 中提取内容,并去除两端的引号。 + * 例如,Token 为 {@code "\"hello\""},则解析为 {@code StringLiteralNode("hello")}。 */ public class StringLiteralParselet implements PrefixParselet { + + /** + * 解析字符串字面量 Token,去除包裹的引号,生成 {@link StringLiteralNode}。 + * + * @param ctx 当前解析上下文(未使用)。 + * @param token 当前字符串字面量 Token,包含带引号的原始文本。 + * @return 解析后的字符串字面量表达式节点。 + */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { - // token.getRaw() 包含原始 "\"Result:\"" - String raw = token.getRaw(); - // 去掉首尾引号 - String content = raw.substring(1, raw.length() - 1); + String raw = token.getRaw(); // 包含引号的原始字符串,例如 "\"Result:\"" + String content = raw.substring(1, raw.length() - 1); // 去除前后引号 return new StringLiteralNode(content); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java index 9e62c54..bc12474 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java @@ -1,24 +1,34 @@ package org.jcnc.snow.compiler.parser.factory; import org.jcnc.snow.compiler.parser.statement.*; + import java.util.Map; import java.util.HashMap; /** - * 语句解析器工厂:关键字 → 对应 StatementParser。 + * 语句解析器工厂类,用于根据关键字(如 "if"、"loop")返回对应的 {@link StatementParser} 实例。 + * 所有语句解析器在静态代码块中预先注册。 + * 若关键字未注册,则默认返回 {@link ExpressionStatementParser}(空字符串对应)。 */ public class StatementParserFactory { private static final Map registry = new HashMap<>(); static { + // 注册各类语句解析器 registry.put("declare", new DeclarationStatementParser()); registry.put("if", new IfStatementParser()); registry.put("loop", new LoopStatementParser()); registry.put("return", new ReturnStatementParser()); - // 默认使用表达式语句 + // 默认解析器:表达式语句 registry.put("", new ExpressionStatementParser()); } + /** + * 根据语句关键字获取对应的语句解析器。 + * + * @param keyword 语句开头的关键字,例如 "if"、"loop"、"declare"。 + * @return 对应的 {@link StatementParser} 实例,若无匹配则返回默认解析器。 + */ public static StatementParser get(String keyword) { return registry.getOrDefault(keyword, registry.get("")); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java index 71c68b8..99b7d35 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java @@ -7,16 +7,25 @@ import java.util.Map; import java.util.HashMap; /** - * 顶层解析器工厂:根据首个关键字(如 module)分发对应解析器。 + * 顶层解析器工厂类,用于根据文件开头的关键字(如 {@code module})分发对应的顶层结构解析器。 + * 每种顶层结构(模块、导入等)应有一个专门的 {@link TopLevelParser} 实现类。 */ public class TopLevelParserFactory { private static final Map registry = new HashMap<>(); static { + // 注册模块解析器 registry.put("module", new ModuleParser()); - // 如需支持 standalone import,可在此注册 + + // import、package 在此添加注册项 } + /** + * 根据顶层关键字获取对应的解析器。 + * + * @param keyword 顶层结构的关键字(如 "module")。 + * @return 对应的 {@link TopLevelParser} 实例;若未注册,则返回 null。 + */ public static TopLevelParser get(String keyword) { return registry.get(keyword); } 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 03476b8..8d6de5d 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 @@ -11,14 +11,29 @@ import java.util.ArrayList; import java.util.List; /** - * 解析 function 块: - * function: NAME NEWLINE - * parameter: (declare name:type | name:type)* - * return_type: TYPE NEWLINE - * body: ... end body - * end function NEWLINE + * 用于解析函数定义块(function),包括函数名、参数列表、返回类型、函数体等。 + * 支持的语法结构示例: + *
    {@code
    + * function: myFunc
    + * parameter:
    + *   declare a:int
    + *   b:int
    + * return_type: int
    + * body:
    + *   declare x:int = 10
    + *   return x
    + * end body
    + * end function
    + * }
    */ public class FunctionParser implements TopLevelParser { + + /** + * 解析一个函数定义并返回对应的 {@link FunctionNode}。 + * + * @param ctx 解析上下文。 + * @return 解析生成的函数节点。 + */ @Override public FunctionNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); @@ -27,7 +42,7 @@ public class FunctionParser implements TopLevelParser { String name = ts.expectType(TokenType.IDENTIFIER).getLexeme(); ts.expectType(TokenType.NEWLINE); - // 参数列表 + // 解析参数列表 ts.expect("parameter"); ts.expect(":"); ts.expectType(TokenType.NEWLINE); @@ -41,7 +56,7 @@ public class FunctionParser implements TopLevelParser { break; } if ("declare".equals(ts.peek().getLexeme())) { - ts.next(); // consume 'declare' + ts.next(); // 支持 declare 前缀 } String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme(); ts.expect(":"); @@ -50,25 +65,25 @@ public class FunctionParser implements TopLevelParser { params.add(new ParameterNode(paramName, paramType)); } - // 返回类型 + // 解析返回类型 ts.expect("return_type"); ts.expect(":"); String returnType = ts.expectType(TokenType.TYPE).getLexeme(); ts.expectType(TokenType.NEWLINE); - // 函数体解析 + // 解析函数体 ts.expect("body"); ts.expect(":"); ts.expectType(TokenType.NEWLINE); List body = new ArrayList<>(); parseBody(ctx, body); - // end body + // 解析函数体结束标识 ts.expect("end"); ts.expect("body"); ts.expectType(TokenType.NEWLINE); - // end function + // 解析函数定义结束标识 ts.expect("end"); ts.expect("function"); ts.expectType(TokenType.NEWLINE); @@ -77,7 +92,10 @@ public class FunctionParser implements TopLevelParser { } /** - * 辅助方法:根据 ParserContext 解析函数体中所有语句,直到遇到 end + * 辅助方法:从上下文中解析函数体,直到遇到 "end"。 + * + * @param ctx 当前解析上下文。 + * @param body 存放解析出的语句节点的列表。 */ private void parseBody(ParserContext ctx, List body) { TokenStream ts = ctx.getTokens(); @@ -90,7 +108,8 @@ public class FunctionParser implements TopLevelParser { break; } String key = ts.peek().getLexeme(); - body.add(StatementParserFactory.get(key).parse(ctx)); + StatementNode stmt = StatementParserFactory.get(key).parse(ctx); + body.add(stmt); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java index 6f0465b..2b6ead4 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java @@ -8,27 +8,36 @@ import java.util.ArrayList; import java.util.List; /** - * 解析 import 语句:import: MOD1, MOD2, ... NEWLINE - * 可以在一行声明多个模块,用逗号分隔。 + * 负责解析 import 语句的解析器。 + * 支持在一行中导入多个模块,格式如: + * {@code import: mod1, mod2, mod3} */ public class ImportParser { + /** - * 读取一行 import 声明,返回多个 ImportNode + * 解析一条 import 声明语句,返回对应的 {@link ImportNode} 列表。 + * 格式必须为:{@code import: MODULE[, MODULE]* NEWLINE} + * + * @param ctx 当前的解析上下文。 + * @return 所有被导入模块的节点列表。 */ public List parse(ParserContext ctx) { ctx.getTokens().expect("import"); ctx.getTokens().expect(":"); + List imports = new ArrayList<>(); - // 读取第一个模块名 - // 继续读取逗号分隔的模块名 + + // 读取第一个模块名,然后继续读取逗号分隔的模块名 do { String mod = ctx.getTokens() .expectType(TokenType.IDENTIFIER) .getLexeme(); imports.add(new ImportNode(mod)); } while (ctx.getTokens().match(",")); - // 消费行尾 + + // 消费行尾换行符 ctx.getTokens().expectType(TokenType.NEWLINE); + return imports; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java index 8a469e2..5a8a018 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java @@ -13,12 +13,24 @@ import java.util.ArrayList; import java.util.List; /** - * 解析 module 块: - * module: NAME NEWLINE - * (import… | function… )* - * end module NEWLINE + * 模块解析器,用于解析形如 module 块的顶层结构。 + * 语法示例: + *
    {@code
    + * module: my.module
    + * import: mod1, mod2
    + * function: ...
    + * end module
    + * }
    + * 支持导入语句和多个函数定义,允许中间包含空行。 */ public class ModuleParser implements TopLevelParser { + + /** + * 解析模块定义块,返回 {@link ModuleNode} 表示模块结构。 + * + * @param ctx 解析上下文。 + * @return 模块节点,包含模块名、导入列表和函数列表。 + */ @Override public ModuleNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); @@ -32,17 +44,18 @@ public class ModuleParser implements TopLevelParser { ImportParser importParser = new ImportParser(); FunctionParser funcParser = new FunctionParser(); - // 解析导入和函数,支持空行 + // 解析模块体:包含 import 和 function 语句 while (true) { // 跳过空行 if (ts.peek().getType() == TokenType.NEWLINE) { ts.next(); continue; } - // 如果遇到 end,跳出循环 + // 遇到 "end" 表示模块结束 if ("end".equals(ts.peek().getLexeme())) { break; } + String lex = ts.peek().getLexeme(); if ("import".equals(lex)) { imports.addAll(importParser.parse(ctx)); @@ -53,9 +66,11 @@ public class ModuleParser implements TopLevelParser { } } + // 结束模块块结构 ts.expect("end"); ts.expect("module"); ts.expectType(TokenType.NEWLINE); + return new ModuleNode(name, imports, functions); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java index 38e13f6..ce6c816 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java @@ -7,24 +7,47 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; /** - * 解析 declare 语句: declare name:type (= expr)? NEWLINE + * 解析变量声明语句的解析器。 + * 支持语法格式: + *
    {@code
    + * declare name:type
    + * declare name:type = expression
    + * }
    + * 每条语句必须以换行(NEWLINE)结束。 */ public class DeclarationStatementParser implements StatementParser { + + /** + * 解析一条 declare 声明语句。 + * + * @param ctx 当前解析上下文。 + * @return 构造好的 {@link DeclarationNode} AST 节点。 + */ @Override public DeclarationNode parse(ParserContext ctx) { ctx.getTokens().expect("declare"); + + // 获取变量名 String name = ctx.getTokens() - .expectType(TokenType.IDENTIFIER) - .getLexeme(); + .expectType(TokenType.IDENTIFIER) + .getLexeme(); + ctx.getTokens().expect(":"); + + // 获取变量类型 String type = ctx.getTokens() - .expectType(TokenType.TYPE) - .getLexeme(); + .expectType(TokenType.TYPE) + .getLexeme(); + + // 可选初始化表达式 ExpressionNode init = null; if (ctx.getTokens().match("=")) { init = new PrattExpressionParser().parse(ctx); } + + // 声明语句必须以 NEWLINE 结束 ctx.getTokens().expectType(TokenType.NEWLINE); + return new DeclarationNode(name, type, init); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java index c0fdca6..128b7b9 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java @@ -10,27 +10,38 @@ import org.jcnc.snow.compiler.parser.context.TokenStream; import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; /** - * 将任意表达式或赋值当作语句: - * identifier = expr NEWLINE - * expr NEWLINE + * 表达式语句解析器:将赋值表达式或任意表达式作为语句进行解析。 + * 支持的形式包括: + *
    + *   identifier = expression
    + *   expression
    + * 
    + * 两者都必须以换行(NEWLINE)结尾。 */ public class ExpressionStatementParser implements StatementParser { + + /** + * 解析一个表达式语句,可能是赋值语句或普通表达式。 + * + * @param ctx 当前的解析上下文。 + * @return 表达式语句节点或赋值语句节点。 + */ @Override public StatementNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); - // 先检测赋值语句:IDENTIFIER '=' ... + // 检查是否是赋值形式(identifier = expr) if (ts.peek().getType() == TokenType.IDENTIFIER && ts.peek(1).getLexeme().equals("=")) { - String varName = ts.next().getLexeme(); // consume identifier - ts.expect("="); // consume '=' + String varName = ts.next().getLexeme(); // 消费 identifier + ts.expect("="); // 消费 '=' ExpressionNode value = new PrattExpressionParser().parse(ctx); ts.expectType(TokenType.NEWLINE); return new AssignmentNode(varName, value); } - // 否则当作普通表达式语句 + // 否则解析为普通表达式语句 ExpressionNode expr = new PrattExpressionParser().parse(ctx); ts.expectType(TokenType.NEWLINE); return new ExpressionStatementNode(expr); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java index c1e8102..64bf84a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java @@ -11,23 +11,41 @@ import java.util.ArrayList; import java.util.List; /** - * 解析 if 语句: if expr then NEWLINE stmts end if NEWLINE + * if 语句解析器,支持基本格式: + *
    {@code
    + * if condition then
    + *   statements...
    + * end if
    + * }
    + * 不支持 else 分支,仅支持 then 分支。 */ public class IfStatementParser implements StatementParser { + + /** + * 解析 if 表达式,并构造 {@link IfNode}。 + * + * @param ctx 当前解析上下文。 + * @return 表示 if 语句的 AST 节点。 + */ @Override public IfNode parse(ParserContext ctx) { ctx.getTokens().expect("if"); + + // 解析条件表达式 var cond = new PrattExpressionParser().parse(ctx); + ctx.getTokens().expect("then"); ctx.getTokens().expectType(TokenType.NEWLINE); + // 解析 then 分支的语句块 List thenBranch = new ArrayList<>(); while (!ctx.getTokens().peek().getLexeme().equals("end")) { - thenBranch.add( - StatementParserFactory.get(ctx.getTokens().peek().getLexeme()).parse(ctx) - ); + String keyword = ctx.getTokens().peek().getLexeme(); + StatementNode stmt = StatementParserFactory.get(keyword).parse(ctx); + thenBranch.add(stmt); } + // 匹配 end if 结束语句 ctx.getTokens().expect("end"); ctx.getTokens().expect("if"); ctx.getTokens().expectType(TokenType.NEWLINE); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java index 6dff091..fc855b2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java @@ -14,16 +14,29 @@ import java.util.ArrayList; import java.util.List; /** - * 解析 loop 语句: - * loop: NEWLINE - * initializer: … NEWLINE - * condition: … NEWLINE - * update: … NEWLINE - * body: … NEWLINE - * end body NEWLINE - * end loop NEWLINE + * 用于解析 loop 语句块,支持以下结构: + *
    {@code
    + * loop:
    + *   initializer:
    + *     declare i:int = 0
    + *   condition:
    + *     i < 10
    + *   update:
    + *     i = i + 1
    + *   body:
    + *     ...语句...
    + * end body
    + * end loop
    + * }
    */ public class LoopStatementParser implements StatementParser { + + /** + * 解析一个完整的 loop 语句块,返回 {@link LoopNode}。 + * + * @param ctx 当前的解析上下文。 + * @return 表示 loop 结构的 AST 节点。 + */ @Override public LoopNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); @@ -53,7 +66,7 @@ public class LoopStatementParser implements StatementParser { ts.expectType(TokenType.NEWLINE); skipNewlines(ts); - // update (专用赋值解析): + // update: ts.expect("update"); ts.expect(":"); ts.expectType(TokenType.NEWLINE); @@ -90,7 +103,11 @@ public class LoopStatementParser implements StatementParser { return new LoopNode(initializer, condition, update, body); } - /** 连续跳过所有空行(NEWLINE) */ + /** + * 跳过连续的 NEWLINE token,用于容错和格式整洁。 + * + * @param ts 当前的 Token 流。 + */ private void skipNewlines(TokenStream ts) { while (ts.peek().getType() == TokenType.NEWLINE) { ts.next(); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java index 5f34b02..286ca36 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java @@ -7,19 +7,35 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; /** - * 解析 return 语句: return expr? NEWLINE + * 用于解析 return 语句。 + * 支持有无返回值两种形式: + *
    {@code
    + * return
    + * return expression
    + * }
    + * 语句必须以换行符(NEWLINE)结束。 */ public class ReturnStatementParser implements StatementParser { + + /** + * 解析 return 语句并构建 {@link ReturnNode}。 + * + * @param ctx 当前解析上下文。 + * @return 表示 return 语句的 AST 节点。 + */ @Override public ReturnNode parse(ParserContext ctx) { ctx.getTokens().expect("return"); + ExpressionNode expr = null; - // 如果下一个不是换行,就解析表达式 + + // 如果不是换行,说明有返回值 if (ctx.getTokens().peek().getType() != TokenType.NEWLINE) { expr = new PrattExpressionParser().parse(ctx); } - // 用 expectType 来消费真正的 NEWLINE token + ctx.getTokens().expectType(TokenType.NEWLINE); + return new ReturnNode(expr); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/StatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/StatementParser.java index 20e6388..cb78a3e 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/StatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/StatementParser.java @@ -4,8 +4,16 @@ import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.ast.StatementNode; /** - * 语句解析器接口。 + * 语句解析器接口,用于将解析上下文中的 Token 转换为 {@link StatementNode}。 + * 各类语句(如声明、赋值、条件、循环、返回等)均应实现该接口。 */ public interface StatementParser { + + /** + * 从给定的解析上下文中解析出一个语句节点。 + * + * @param ctx 当前的解析上下文。 + * @return 表示语句的 AST 节点。 + */ StatementNode parse(ParserContext ctx); }