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

ANTLR4解析顺序正确但Context为空,如何获取文本内容?

问题描述

我尝试解析形如「Answer(x,y,z):-R(x,y),U(y,z).」的合取查询,使用Java(Maven)中的ANTLR4构建了如下语法规则:

grammar CQgrammar;

// Parser rules
query : head ':-' body;
head : atom;
body : atom (',' atom)* '.';
atom : ATOMNAME '(' term* (',' term)* ')';
term : CONST | VAR;

// Lexer rules
VAR: [a-z];
CONST: '"' [a-zA-Z0-9]+ '"';
TERMS: '(' | ')' | ',' | '.' | ':-';

ATOMNAME: [a-zA-Z0-9]+;

随后我扩展生成的Listener类,重写了enterQuery、enterHead、enterBody、enterAtom、enterTerm方法,当前仅在这些方法中加入简单打印语句,目标是构建合取查询类。主函数如下:

public static void main(String[] args) {
        String query = ""Answer(x,y,z):-R(x,y),U(y,z)."";
        org.parsing.CQgrammarLexer lexer = new org.parsing.CQgrammarLexer(CharStreams.fromString(query));
        org.parsing.CQgrammarParser parser = new org.parsing.CQgrammarParser(new CommonTokenStream(lexer));

        CQparser listener = new CQparser();
        parser.addParseListener(listener);
        parser.query();
    }

从打印结果可见,解析顺序正确且无错误,但在这些重写方法中调用ctx.getText()时返回空值,ctx的其他Getter方法(如enterAtom中的ctx.Atom())也为空。怀疑Lexer部分存在问题,但文档说明不够清晰,请问该如何解决?

解决方法

1. 修复Lexer规则的优先级与定义错误

ANTLR4的Lexer规则按顺序匹配最长字符串,原TERMS规则存在核心问题:将多个符号打包为同一token类型,导致Parser无法正确识别语法中的对应符号,进而上下文对象无法关联有效内容。

替换原TERMS规则,为每个符号单独定义明确的token类型:

// 替换原TERMS规则
COLONMINUS : ':-';
LPAREN     : '(';
RPAREN     : ')';
COMMA      : ',';
DOT        : '.';

2. 修正Parser中atom规则的冗余定义

原atom规则里的term* (',' term)*存在语法歧义,会导致解析逻辑混乱,修改为更严谨的参数列表定义:

atom : ATOMNAME LPAREN (term (COMMA term)*)? RPAREN;

该规则既支持空参数列表,也支持多个逗号分隔的参数,避免重复定义引发的解析异常。

3. 修正主函数中的字符串转义问题

主函数中使用的"是HTML实体,应替换为Java原生的字符串转义符\",若查询本身不需要引号包裹,直接写原始字符串即可:

String query = "Answer(x,y,z):-R(x,y),U(y,z).";

否则Lexer会把开头的"误判为CONST的一部分,导致解析错位。

4. 正确获取Listener上下文内容

修改后的语法生成的Parser上下文会包含有效子节点,示例代码如下:

@Override
public void enterAtom(CQgrammarParser.AtomContext ctx) {
    // 获取原子名称
    System.out.println("原子名称: " + ctx.ATOMNAME().getText());
    // 获取所有参数
    List<CQgrammarParser.TermContext> terms = ctx.term();
    for (CQgrammarParser.TermContext termCtx : terms) {
        System.out.println("参数: " + termCtx.getText());
    }
}

最终修正后的完整语法

grammar CQgrammar;

// Parser rules
query : head COLONMINUS body;
head : atom;
body : atom (COMMA atom)* DOT;
atom : ATOMNAME LPAREN (term (COMMA term)*)? RPAREN;
term : CONST | VAR;

// Lexer rules
VAR        : [a-z]+; // 可选:支持多字符变量名,如xyz,仅需单字符可保留[a-z]
CONST      : '"' [a-zA-Z0-9]+ '"';
COLONMINUS : ':-';
LPAREN     : '(';
RPAREN     : ')';
COMMA      : ',';
DOT        : '.';

ATOMNAME   : [a-zA-Z0-9]+;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:34:58