This commit is contained in:
Luke 2025-04-22 18:06:30 +08:00
parent 85ec6c3700
commit 06ccb4f280
5 changed files with 156 additions and 12 deletions

View File

@ -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;

View File

@ -1,8 +1,21 @@
package org.jcnc.snow.compiler.parser;
/**
* 抽象的表达式节点基类所有具体表达式都应继承此类
* 抽象表达式节点基类所有具体的表达式类型如标识符字面量
* 二元运算等都应继承此类以便在语法树中统一表示表达式
*
* <p>子类示例
* <ul>
* <li>{@link org.jcnc.snow.compiler.parser.ast.ASTIdentifier}表示变量或标识符</li>
* <li>{@link org.jcnc.snow.compiler.parser.ast.ASTLiteral}表示整数字面量</li>
* <li>{@link org.jcnc.snow.compiler.parser.ast.ASTBinaryOp}表示加减乘除等二元运算</li>
* </ul>
*
* <p>在解析过程中parseExpression 方法会创建具体的 ASTExpression 实例
* 后续阶段如语义分析代码生成可通过 instanceof Visitor 模式对
* 不同子类进行处理
*
*/
public abstract class ASTExpression {
// 该类仅作为标记类型不包含公共字段或方法
}

View File

@ -1,3 +1,15 @@
package org.jcnc.snow.compiler.parser;
public abstract class ASTStatement extends ASTNode {}
/**
* 抽象语句节点基类所有语法树中的语句类型如声明返回循环条件等
* 都应继承自此类以便在解析器和后续处理如语义分析生成代码
* 中统一识别和处理
*
* <p>ASTStatement 继承自 ASTNode包含共通的节点属性和方法
* 具体子类需要实现各自的构造器及特定字段并根据需要重写
* Visitor 模式或其他遍历/处理逻辑
*
* @see ASTNode
*/
public abstract class ASTStatement extends ASTNode {
}

View File

@ -8,16 +8,41 @@ import java.util.ArrayList;
import java.util.List;
/**
* 递归下降解析器实现对模块函数语句和表达式的完整解析
* 递归下降解析器用于解析模块函数语句和表达式并生成相应的AST节点
*
* <p>使用给定的词法分析器生成的令牌序列对语法结构进行逐步匹配和构建
* 提供对模块(module)函数(function)参数(parameter)声明(declare)循环(loop)
* 条件(if)返回(return)以及二元表达式的支持
*
* <p>抛出ASTBinaryOp.ParseException以报告解析错误
*/
public class ParserEngine {
/** 令牌序列 */
private final List<Token> tokens;
/** 当前处理的令牌位置 */
private int pos = 0;
/**
* 构造函数初始化解析器
*
* @param tokens 由词法分析器生成的令牌列表
*/
public ParserEngine(List<Token> tokens) {
this.tokens = tokens;
}
/**
* 解析整个模块结构包含模块名和函数定义列表
*
* <pre>
* module: 模块开始标记
* IDENTIFIER: 模块名称
* end module: 模块结束标记
* </pre>
*
* @return 构建好的ASTModule节点
* @throws ASTBinaryOp.ParseException 当解析过程中出现不匹配或意外令牌时抛出
*/
public ASTModule parseModule() {
match(TokenType.KEYWORD, "module");
match(TokenType.COLON);
@ -36,6 +61,20 @@ public class ParserEngine {
return module;
}
/**
* 解析函数定义包括参数列表返回类型和函数体
*
* <pre>
* function: 函数开始标记
* parameter (可选): 参数声明块
* return_type: 返回类型
* body: 函数体语句
* end function: 函数结束标记
* </pre>
*
* @return 构建好的ASTFunction节点
* @throws ASTBinaryOp.ParseException 当解析过程中出现不匹配或意外令牌时抛出
*/
private ASTFunction parseFunction() {
match(TokenType.KEYWORD, "function");
match(TokenType.COLON);
@ -76,6 +115,16 @@ public class ParserEngine {
return fn;
}
/**
* 解析单个参数声明
*
* <pre>
* declare IDENTIFIER:type
* </pre>
*
* @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);
}
/**
* 解析一条语句根据关键字分发到不同的解析器
* 支持returndeclareloop和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,7 +247,7 @@ public class ParserEngine {
} else {
throw new ASTBinaryOp.ParseException("表达式解析错误,意外的令牌:" + t);
}
// 处理二元运算
// 处理二元运算
Token opTok = current();
String lex = opTok.getLexeme();
if (opTok.getType() == TokenType.PLUS
@ -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());
}
}

View File

@ -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 打印工具 -----------------