You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于指定BNF语法的Java递归下降解析器实现求助

递归下降解析器实现方案(针对给定BNF)

核心思路

递归下降解析器的核心是每个BNF非终结符对应一个独立函数,函数负责匹配对应语法规则、处理token流,并完成语义动作(如表达式求值、变量存储)。实现时需要维护:

  • 一个token流指针,跟踪当前待处理的token
  • 符号表(用HashMap实现),存储变量名与对应的值

基础结构与工具方法

首先定义解析器类,包含token流、指针、符号表,以及基础的token操作方法:

import java.util.List;
import java.util.Map;
import java.util.HashMap;

public class RecursiveDescentParser {
    private List<Token> tokens;
    private int currentTokenIndex;
    private Map<String, Integer> symbolTable;

    public RecursiveDescentParser(List<Token> tokens) {
        this.tokens = tokens;
        this.currentTokenIndex = 0;
        this.symbolTable = new HashMap<>();
    }

    // 获取当前未消费的token
    private Token peek() {
        return currentTokenIndex < tokens.size() ? tokens.get(currentTokenIndex) : null;
    }

    // 消费当前token,指针后移
    private Token consume() {
        return tokens.get(currentTokenIndex++);
    }

    // 检查当前token是否为指定类型,是则消费,否则抛出解析异常
    private void match(int expectedType) throws ParseException {
        Token token = peek();
        if (token == null || token.type != expectedType) {
            throw new ParseException(String.format("Expected token type %d, got %s", 
                expectedType, token != null ? token.type : "null"));
        }
        consume();
    }
}

同时定义解析异常类:

public class ParseException extends Exception {
    public ParseException(String message) {
        super(message);
    }
}

对应BNF规则的解析函数

1. <program> → <statements>

作为入口,调用语句处理函数并检查解析完整性:

public void parse() throws ParseException {
    program();
    if (peek() != null) {
        throw new ParseException("Unexpected token after program end");
    }
}

private void program() throws ParseException {
    statements();
}

2. <statements> → <statement> | <statement> <semi_colon> <statements>

处理单个语句,循环匹配分号分隔的后续语句:

private void statements() throws ParseException {
    statement();
    while (peek() != null && peek().type == TokenType.SEMI_COLON) {
        match(TokenType.SEMI_COLON);
        statement();
    }
}

3. <statement> → <ident> <assignment_op> <expression>

匹配变量名、赋值运算符,计算表达式值并存入符号表:

private void statement() throws ParseException {
    Token identToken = peek();
    if (identToken == null || identToken.type != TokenType.IDENT) {
        throw new ParseException("Expected identifier in statement");
    }
    String varName = identToken.token_string;
    consume();

    match(TokenType.ASSIGN);
    int exprValue = expression();
    symbolTable.put(varName, exprValue);
}

4. <expression> → <term> <term_tail>

调用项处理函数,再处理后续加减运算:

private int expression() throws ParseException {
    int value = term();
    return termTail(value);
}

// `<term_tail>` → `<add_op>` `<term>` `<term_tail>` | ε
private int termTail(int currentValue) throws ParseException {
    Token token = peek();
    while (token != null && (token.type == TokenType.PLUS || token.type == TokenType.MINUS)) {
        consume();
        int termValue = term();
        currentValue = token.type == TokenType.PLUS ? currentValue + termValue : currentValue - termValue;
        token = peek();
    }
    return currentValue;
}

5. <term> → <factor> <factor_tail>

调用因子处理函数,再处理后续乘除运算:

private int term() throws ParseException {
    int value = factor();
    return factorTail(value);
}

// `<factor_tail>` → `<mult_op>` `<factor>` `<factor_tail>` | ε
private int factorTail(int currentValue) throws ParseException {
    Token token = peek();
    while (token != null && (token.type == TokenType.STAR || token.type == TokenType.SLASH)) {
        consume();
        int factorValue = factor();
        if (token.type == TokenType.STAR) {
            currentValue *= factorValue;
        } else {
            if (factorValue == 0) {
                throw new ParseException("Division by zero");
            }
            currentValue /= factorValue;
        }
        token = peek();
    }
    return currentValue;
}

6. <factor> → <left_paren> <expression> <right_paren> | <ident> | <const>

处理括号表达式、变量引用或常量:

private int factor() throws ParseException {
    Token token = peek();
    if (token == null) {
        throw new ParseException("Unexpected end of input in factor");
    }

    int value;
    if (token.type == TokenType.LEFT_PAR) {
        consume();
        value = expression();
        match(TokenType.RIGHT_PAR);
    } else if (token.type == TokenType.IDENT) {
        String varName = token.token_string;
        consume();
        if (!symbolTable.containsKey(varName)) {
            throw new ParseException("Undefined variable: " + varName);
        }
        value = symbolTable.get(varName);
    } else if (token.type == TokenType.NUMBER) {
        value = (Integer) token.value;
        consume();
    } else {
        throw new ParseException("Unexpected token in factor: " + token.token_string);
    }
    return value;
}

测试示例

针对给定的测试输入,构造token流并验证解析结果:

public static void main(String[] args) {
    List<Token> tokens = List.of(
        new Token(TokenType.IDENT, "operator1", null),
        new Token(TokenType.ASSIGN, ":=", null),
        new Token(TokenType.NUMBER, "200", 200),
        new Token(TokenType.PLUS, "+", null),
        new Token(TokenType.NUMBER, "100", 100),
        new Token(TokenType.STAR, "*", null),
        new Token(TokenType.LEFT_PAR, "(", null),
        new Token(TokenType.NUMBER, "100", 100),
        new Token(TokenType.MINUS, "-", null),
        new Token(TokenType.NUMBER, "200", 200),
        new Token(TokenType.RIGHT_PAR, ")", null),
        new Token(TokenType.SEMI_COLON, ";", null),
        new Token(TokenType.IDENT, "operator2", null),
        new Token(TokenType.ASSIGN, ":=", null),
        new Token(TokenType.IDENT, "operator1", null),
        new Token(TokenType.PLUS, "+", null),
        new Token(TokenType.NUMBER, "300", 300)
    );

    RecursiveDescentParser parser = new RecursiveDescentParser(tokens);
    try {
        parser.parse();
        System.out.println("operator1 = " + parser.symbolTable.get("operator1")); // 输出:-9800
        System.out.println("operator2 = " + parser.symbolTable.get("operator2")); // 输出:-9500
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

内容的提问来源于stack exchange,提问作者Dagun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:50:28