diff --git a/src/main/java/org/jcnc/snow/compiler/Main.java b/src/main/java/org/jcnc/snow/compiler/Main.java index 272fbad..ab9fd7b 100644 --- a/src/main/java/org/jcnc/snow/compiler/Main.java +++ b/src/main/java/org/jcnc/snow/compiler/Main.java @@ -3,7 +3,7 @@ package org.jcnc.snow.compiler; import org.jcnc.snow.compiler.lexer.LexerEngine; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.ASTModule; -import org.jcnc.snow.compiler.parser.ASTPrinter; +import org.jcnc.snow.compiler.parser.utils.ASTPrinter; import org.jcnc.snow.compiler.parser.ParserEngine; import java.io.IOException; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ASTExpression.java b/src/main/java/org/jcnc/snow/compiler/parser/ASTExpression.java index 6633459..0a76af5 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ASTExpression.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ASTExpression.java @@ -1,8 +1,21 @@ package org.jcnc.snow.compiler.parser; /** - * 抽象的表达式节点基类,所有具体表达式都应继承此类。 + * 抽象表达式节点基类。所有具体的表达式类型(如标识符、字面量、 + * 二元运算等)都应继承此类,以便在语法树中统一表示表达式。 + * + *

子类示例: + *

+ * + *

在解析过程中,parseExpression 方法会创建具体的 ASTExpression 实例。 + * 后续阶段(如语义分析、代码生成)可通过 instanceof 或 Visitor 模式对 + * 不同子类进行处理。 + * */ public abstract class ASTExpression { - + // 该类仅作为标记类型,不包含公共字段或方法 } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ASTStatement.java b/src/main/java/org/jcnc/snow/compiler/parser/ASTStatement.java index 8d3b638..57c6f28 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ASTStatement.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ASTStatement.java @@ -1,3 +1,15 @@ package org.jcnc.snow.compiler.parser; -public abstract class ASTStatement extends ASTNode {} +/** + * 抽象语句节点基类。所有语法树中的语句类型(如声明、返回、循环、条件等) + * 都应继承自此类,以便在解析器和后续处理(如语义分析、生成代码) + * 中统一识别和处理。 + * + *

ASTStatement 继承自 ASTNode,包含共通的节点属性和方法。 + * 具体子类需要实现各自的构造器及特定字段,并根据需要重写 + * Visitor 模式或其他遍历/处理逻辑。 + * + * @see ASTNode + */ +public abstract class ASTStatement extends ASTNode { +} \ No newline at end of file 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 a2777a4..2111d35 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java @@ -8,16 +8,41 @@ import java.util.ArrayList; import java.util.List; /** - * 递归下降解析器,实现对模块、函数、语句和表达式的完整解析 + * 递归下降解析器,用于解析模块、函数、语句和表达式,并生成相应的AST节点。 + * + *

使用给定的词法分析器生成的令牌序列,对语法结构进行逐步匹配和构建。 + * 提供对模块(module)、函数(function)、参数(parameter)、声明(declare)、循环(loop)、 + * 条件(if)、返回(return)以及二元表达式的支持。 + * + *

抛出ASTBinaryOp.ParseException以报告解析错误。 */ public class ParserEngine { + /** 令牌序列 */ private final List tokens; + /** 当前处理的令牌位置 */ private int pos = 0; + /** + * 构造函数,初始化解析器。 + * + * @param tokens 由词法分析器生成的令牌列表 + */ public ParserEngine(List tokens) { this.tokens = tokens; } + /** + * 解析整个模块结构,包含模块名和函数定义列表。 + * + *

+     * module: 模块开始标记
+     * IDENTIFIER: 模块名称
+     * end module: 模块结束标记
+     * 
+ * + * @return 构建好的ASTModule节点 + * @throws ASTBinaryOp.ParseException 当解析过程中出现不匹配或意外令牌时抛出 + */ public ASTModule parseModule() { match(TokenType.KEYWORD, "module"); match(TokenType.COLON); @@ -36,6 +61,20 @@ public class ParserEngine { return module; } + /** + * 解析函数定义,包括参数列表、返回类型和函数体。 + * + *
+     * function: 函数开始标记
+     * parameter (可选): 参数声明块
+     * return_type: 返回类型
+     * body: 函数体语句
+     * end function: 函数结束标记
+     * 
+ * + * @return 构建好的ASTFunction节点 + * @throws ASTBinaryOp.ParseException 当解析过程中出现不匹配或意外令牌时抛出 + */ private ASTFunction parseFunction() { match(TokenType.KEYWORD, "function"); match(TokenType.COLON); @@ -76,6 +115,16 @@ public class ParserEngine { return fn; } + /** + * 解析单个参数声明。 + * + *
+     * declare IDENTIFIER:type
+     * 
+ * + * @return 构建好的ASTParameter节点 + * @throws ASTBinaryOp.ParseException 当解析过程中出现不匹配或意外令牌时抛出 + */ private ASTParameter parseParameter() { match(TokenType.KEYWORD, "declare"); String name = current().getLexeme(); @@ -87,6 +136,13 @@ public class ParserEngine { return new ASTParameter(name, type); } + /** + * 解析一条语句,根据关键字分发到不同的解析器。 + * 支持return、declare、loop和if语句。 + * + * @return 对应的ASTStatement子类实例 + * @throws ASTBinaryOp.ParseException 当无法识别语句类型时抛出 + */ private ASTStatement parseStatement() { if (peek(TokenType.KEYWORD, "return")) { return parseReturn(); @@ -100,6 +156,11 @@ public class ParserEngine { throw new ASTBinaryOp.ParseException("无法识别的语句:" + current()); } + /** + * 解析return语句。 + * + * @return 构建好的ASTReturn节点,包含返回的表达式 + */ private ASTReturn parseReturn() { match(TokenType.KEYWORD, "return"); ASTExpression expr = parseExpression(); @@ -107,6 +168,11 @@ public class ParserEngine { return new ASTReturn(expr); } + /** + * 解析声明语句,可选带初始化表达式。 + * + * @return 构建好的ASTDeclare节点,若无初始化则init为null + */ private ASTDeclare parseDeclare() { match(TokenType.KEYWORD, "declare"); String name = current().getLexeme(); match(TokenType.IDENTIFIER); @@ -123,6 +189,11 @@ public class ParserEngine { } } + /** + * 解析循环语句,包含初始化、条件、更新和循环体。 + * + * @return 构建好的ASTLoop节点 + */ private ASTLoop parseLoop() { match(TokenType.KEYWORD, "loop"); match(TokenType.COLON); match(TokenType.NEWLINE); @@ -142,6 +213,11 @@ public class ParserEngine { return new ASTLoop(init, cond, update, stmts); } + /** + * 解析条件语句,仅支持单分支if。 + * + * @return 构建好的ASTIf节点 + */ private ASTIf parseIf() { match(TokenType.KEYWORD, "if"); ASTExpression cond = parseExpression(); @@ -154,6 +230,13 @@ public class ParserEngine { return new ASTIf(cond, thenStmts); } + /** + * 解析表达式,支持标识符、整数字面量和加减乘除二元运算。 + * 实现左递归消除,通过递归调用构建二元运算树。 + * + * @return 构建好的ASTExpression子类实例 + * @throws ASTBinaryOp.ParseException 当遇到意外令牌时抛出 + */ private ASTExpression parseExpression() { ASTExpression left; Token t = current(); @@ -164,13 +247,13 @@ public class ParserEngine { } else { throw new ASTBinaryOp.ParseException("表达式解析错误,意外的令牌:" + t); } - // 处理二元运算 + // 处理二元运算符 Token opTok = current(); String lex = opTok.getLexeme(); if (opTok.getType() == TokenType.PLUS - || opTok.getType() == TokenType.MINUS - || opTok.getType() == TokenType.MULTIPLY - || lex.equals("/")) { + || opTok.getType() == TokenType.MINUS + || opTok.getType() == TokenType.MULTIPLY + || lex.equals("/")) { String op = lex; pos++; ASTExpression right = parseExpression(); @@ -180,22 +263,56 @@ public class ParserEngine { } // 工具方法 + /** + * 获取当前令牌,如果超出范围则抛出异常。 + * + * @return 当前Token + * @throws ASTBinaryOp.ParseException 当访问越界时抛出 + */ private Token current() { if (pos >= tokens.size()) throw new ASTBinaryOp.ParseException("超出令牌范围"); return tokens.get(pos); } + + /** + * 判断当前令牌类型是否匹配。 + * + * @param type 期望的TokenType + * @return 匹配返回true,否则false + */ private boolean peek(TokenType type) { return current().getType() == type; } + + /** + * 判断当前令牌类型和词法是否与期望匹配。 + * + * @param type 期望的TokenType + * @param lexeme 期望的词法串 + * @return 匹配返回true,否则false + */ private boolean peek(TokenType type, String lexeme) { return peek(type) && current().getLexeme().equals(lexeme); } + + /** + * 强制匹配当前令牌类型,如果不匹配则抛出异常。 + * + * @param type 期望的TokenType + * @throws ASTBinaryOp.ParseException 当不匹配时抛出,包含错误信息 + */ private void match(TokenType type) { if (peek(type)) pos++; else throw new ASTBinaryOp.ParseException("期望 " + type + " 但找到 " + current()); } + + /** + * 强制匹配当前令牌类型和词法,如果不匹配则抛出异常。 + * + * @param type 期望的TokenType + * @param lexeme 期望的词法串 + * @throws ASTBinaryOp.ParseException 当不匹配时抛出,包含错误信息 + */ private void match(TokenType type, String lexeme) { if (peek(type, lexeme)) pos++; else throw new ASTBinaryOp.ParseException("期望 '" + lexeme + "' 但找到 " + current()); } } - - diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ASTPrinter.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTPrinter.java similarity index 95% rename from src/main/java/org/jcnc/snow/compiler/parser/ASTPrinter.java rename to src/main/java/org/jcnc/snow/compiler/parser/utils/ASTPrinter.java index 7ae4070..a35d564 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ASTPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTPrinter.java @@ -1,5 +1,7 @@ -package org.jcnc.snow.compiler.parser; +package org.jcnc.snow.compiler.parser.utils; +import org.jcnc.snow.compiler.parser.ASTExpression; +import org.jcnc.snow.compiler.parser.ASTStatement; import org.jcnc.snow.compiler.parser.ast.*; // ----------------- AST 打印工具 -----------------