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

如何在Java、Python、JS中打印Antlr的ctx详情并获取Token信息?

ANTLR中Context对象(ctx)的Token相关属性/方法及可读导出方案(Java、Python、JS)

背景与已知使用示例

我了解ctx是ANTLR中的核心对象,以下是Java和Python中的基础使用示例:

Java示例

@Override
public Value visitNumberAtom(MuParser.NumberAtomContext ctx) {
    return new Value(Double.valueOf(ctx.getText()));
}

Python示例

def visitNumberAtom(self, ctx):
    value = ctx.getText()
    return float(value)

问题

我想知道ctx还有哪些与Token相关的属性或方法;理想情况下能以可读格式打印(导出)ctx。同时想了解这在Java、Python和JS中是否可行,或者能实现的最佳效果是什么?

补充示例说明

为了更清晰说明问题,我补充了具体示例:

Expr.g4 语法文件

grammar Expr;
prog: expr EOF;
expr:
    expr ('+' | '-') expr
    | INT;
NEWLINE: [\r\n]+ -> skip;
INT: [0-9]+;

生成Java文件的命令

antlr4 Expr.g4 -visitor -no-listener

EvalVisitor.java 重写类

public class EvalVisitor extends ExprBaseVisitor<Object> {
    @Override
    public Object visitExpr(ExprParser.ExprContext ctx) {
        System.out.println("visitExpr ctx.getText(): " + ctx.getText());
        System.out.println("visitExpr ctx.toString(): " + ctx.toString());
        return visitChildren(ctx);
    }
}

Main.java 调用代码

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

public class Main {
    public static void main(String[] args) throws Exception {
        ExprLexer lexer = new ExprLexer(CharStreams.fromString("5+2-1"));
        ExprParser parser = new ExprParser(new CommonTokenStream(lexer));
        ParseTree tree = parser.prog();
        System.out.println("tree: " + tree.toStringTree(parser));
        EvalVisitor visitor = new EvalVisitor();
        visitor.visit(tree);
    }
}

编译运行输出

$ java Main
tree: (prog (expr (expr (expr 5) + (expr 2)) - (expr 1)) <EOF>)
visitExpr ctx.getText(): 5+2-1
visitExpr ctx.toString(): [4]
visitExpr ctx.getText(): 5+2
visitExpr ctx.toString(): [2 4]
visitExpr ctx.getText(): 5
visitExpr ctx.toString(): [2 2 4]
visitExpr ctx.getText(): 2
visitExpr ctx.toString(): [20 2 4]
visitExpr ctx.getText(): 1
visitExpr ctx.toString(): [20 4]

可以看到toString()和toStringTree()的输出对普通用户友好,但对开发者不够直观——我想明确知道ctx的哪些属性对应具体Token,比如如何获取INT Token的内容?


解答

一、ctx与Token相关的核心属性/方法

所有ANTLR生成的Context类都继承自ParserRuleContext,核心Token相关方法/属性如下:

  • getText(): 返回当前ctx覆盖的所有文本(如示例中的5+2-1)
  • getStart(): 返回当前ctx对应的第一个Token对象
  • getStop(): 返回当前ctx对应的最后一个Token对象
  • getToken(int tokenType, int index): 根据Token类型和索引获取指定Token(比如获取INT类型的第0个Token)
  • getChildCount(): 返回当前ctx的子节点数量(包括子Context和Token)
  • getChild(int index): 获取指定索引的子节点,可通过类型判断是否为Token

针对你的示例,要获取INT Token的内容,可在visitExpr中做如下处理:

Java实现

@Override
public Object visitExpr(ExprParser.ExprContext ctx) {
    // 直接匹配INT类型的子Token
    if (ctx.INT() != null) {
        System.out.println("INT Token内容: " + ctx.INT().getText());
    }
    // 遍历所有子节点查找Token
    for (int i = 0; i < ctx.getChildCount(); i++) {
        Object child = ctx.getChild(i);
        if (child instanceof Token) {
            Token token = (Token) child;
            System.out.printf("Token类型: %s, 内容: %s, 位置: %d%n",
                    ExprLexer.VOCABULARY.getSymbolicName(token.getType()),
                    token.getText(),
                    token.getStartIndex());
        }
    }
    return visitChildren(ctx);
}

Python实现

def visitExpr(self, ctx):
    # 直接访问生成的INT属性
    if ctx.INT():
        print(f"INT Token内容: {ctx.INT().getText()}")
    # 遍历子节点
    for child in ctx.getChildren():
        if hasattr(child, 'getSymbol'):
            token = child.getSymbol()
            print(f"Token类型: {self.parser.symbolicNames[token.type]}, 内容: {token.text}, 位置: {token.start}")
    return self.visitChildren(ctx)

JS实现

visitExpr(ctx) {
    // 直接访问INT节点
    if (ctx.INT()) {
        console.log(`INT Token内容: ${ctx.INT().getText()}`);
    }
    // 遍历子节点
    for (let i = 0; i < ctx.getChildCount(); i++) {
        const child = ctx.getChild(i);
        if (child.getSymbol) {
            const token = child.getSymbol();
            console.log(`Token类型: ${this.parser.vocabulary.getSymbolicName(token.type)}, 内容: ${token.text}, 位置: ${token.startIndex}`);
        }
    }
    return this.visitChildren(ctx);
}

二、可读格式打印/导出ctx的最佳方案

1. 自定义打印方法

针对开发者需求,可编写工具方法遍历ctx的所有属性和Token信息,输出结构化内容(比如JSON格式):

Java示例(导出为JSON)
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;

public class CtxPrinter {
    public static String printCtx(ParserRuleContext ctx) {
        List<TokenInfo> tokens = new ArrayList<>();
        collectTokens(ctx, tokens);
        return new Gson().toJson(tokens);
    }

    private static void collectTokens(ParserRuleContext ctx, List<TokenInfo> tokens) {
        for (int i = 0; i < ctx.getChildCount(); i++) {
            Object child = ctx.getChild(i);
            if (child instanceof Token) {
                Token token = (Token) child;
                tokens.add(new TokenInfo(
                        ctx.getClass().getSimpleName(),
                        ExprLexer.VOCABULARY.getSymbolicName(token.getType()),
                        token.getText(),
                        token.getStartIndex(),
                        token.getStopIndex()
                ));
            } else if (child instanceof ParserRuleContext) {
                collectTokens((ParserRuleContext) child, tokens);
            }
        }
    }

    private static class TokenInfo {
        public String contextType;
        public String tokenType;
        public String text;
        public int startIndex;
        public int stopIndex;

        public TokenInfo(String contextType, String tokenType, String text, int startIndex, int stopIndex) {
            this.contextType = contextType;
            this.tokenType = tokenType;
            this.text = text;
            this.startIndex = startIndex;
            this.stopIndex = stopIndex;
        }
    }
}

调用方式:System.out.println(CtxPrinter.printCtx(ctx));

2. 利用ANTLR内置工具

  • toStringTree(parser): 输出结构化的语法树(适合快速查看树结构)
  • getRuleContext(): 获取当前ctx对应的规则上下文信息
  • Java环境下可通过反射遍历ctx的自动生成属性(如INT()、PLUS()等方法)

三、各语言的实现差异

语言Token获取方式导出便利性
Java自动生成对应Token的getter方法(如ctx.INT()),支持强类型判断可通过反射、JSON库快速结构化导出
Python自动生成属性(如ctx.INT),需通过getSymbol()获取Token对象原生支持字典转换,可快速转为JSON
JS自动生成方法(如ctx.INT()),Token对象通过getSymbol()获取原生支持JSON序列化,实现成本低

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:50:20