看懂antlr4生成parsercontext代码,找到一种在一个上下文中检测terminalNode的好方法

Understand antlr4 generated parsercontext code, Find a good way to detect terminalNode in one context

G4文件部分为:

typeSpecifier
    :   ('void'
    |   'char'
    |   'short'
    |   'int'
    |   '__m128d'
    |   '__m128i')
    |   '__extension__' '(' ('__m128' | '__m128d' | '__m128i') ')'
    |   atomicTypeSpecifier
    |   structOrUnionSpecifier
    |   enumSpecifier
    |   typedefName
    |   '__typeof__' '(' constantExpression ')' // GCC extension
    ;

生成的代码是:

public static class TypeSpecifierContext extends ParserRuleContext {                                                     
    public AtomicTypeSpecifierContext atomicTypeSpecifier() {                                                            
        return getRuleContext(AtomicTypeSpecifierContext.class,0);                                                       
    }                                                                                                                    
    public StructOrUnionSpecifierContext structOrUnionSpecifier() {                                                      
        return getRuleContext(StructOrUnionSpecifierContext.class,0);                                                    
    }                                                                                                                    
    public EnumSpecifierContext enumSpecifier() {                                                                        
        return getRuleContext(EnumSpecifierContext.class,0);                                                             
    }                                                                                                                    
    public TypedefNameContext typedefName() {                                                                            
        return getRuleContext(TypedefNameContext.class,0);                                                               
    }                                                                                                                    
    public ConstantExpressionContext constantExpression() {                                                              
        return getRuleContext(ConstantExpressionContext.class,0);                                                        
    }                                                                                                                    
    public TypeSpecifierContext(ParserRuleContext parent, int invokingState) {                                           
        super(parent, invokingState);                                                                                    
    }                                                                                                                    
    @Override public int getRuleIndex() { return RULE_typeSpecifier; }                                                   
    @Override                                                                                                            
    public void enterRule(ParseTreeListener listener) {                                                                  
        if ( listener instanceof ProbeListener ) ((ProbeListener)listener).enterTypeSpecifier(this);                     
    }                                                                                                                    
    @Override                                                                                                            
    public void exitRule(ParseTreeListener listener) {                                                                   
        if ( listener instanceof ProbeListener ) ((ProbeListener)listener).exitTypeSpecifier(this);                      
    }                                                                                                                    
    @Override                                                                                                            
    public <T> T accept(ParseTreeVisitor<? extends T> visitor) {                                                         
        if ( visitor instanceof ProbeVisitor ) return ((ProbeVisitor<? extends T>)visitor).visitTypeSpecifier(this);     
        else return visitor.visitChildren(this);                                                                         
    }                                                                                                                    
}                                                                                                                        

我想在我的访问代码中查看此 typeSpecifier 是哪种类型:

TypeSpecifierContext typeSpecifier = ctx.typeSpecifier(); // ctx is parent context    
LOG.trace(String.format("typeSepcifier the start is %s the stop is %s" , typeSpecifier.getStart().getText()
                    , typeSpecifier.getStop().getText()));

我可以获得如下输出:

typeSepcifier the start is int the stop is int

我觉得这个方法很丑,Antlr4 可以提供方法来实现像 instanceof IntTypeSpecifier 这样的方法吗?

您可以使用访问者设计模式来访问 ANTLR 的 AST 并对其进行处理,因此您甚至不需要使用 instanceof。

final class Visitor extends YourGrammarParserBaseVisitor<String> { // The name of the base visitor should be <your grammar name> + 'ParserBaseVisitor'

    @Override
    public String visitTypeSpecifier(TypeSpecifierContext ctx) { // 'visit' + <name of the rule with the first letter to upper case>
        // Your code here

        return "the result";
    }

    // other visit methods for other rules
}

给您的访客打电话:

new Visitor.visit(new YourGrammarParser(/* weird ANTLR stuff */).typeSpecifier());

如果您为 int 类型创建规则,假设:

typeSpecifier
    : intTypeSpecifier
    | // the other rules
    ;

intTypeSpecifier : 'int';

您将能够为 IntTypeSpecifierContext 创建一个访问方法 visitIntTypeSpecifier 以轻松处理 int 类型。

因此代码应如下所示:

final class Visitor extends YourGrammarParserBaseVisitor<String> {

    @Override
    public String visitTypeSpecifier(TypeSpecifierContext ctx) {
        return super();
    }

    @Override
    public String visitIntTypeSpecifier(IntTypeSpecifierContext ctx) {
        return 'int'; // or ctx.getText()
    }

    // Rest of the rules
}

现在纠正我,因为我可能错了,但是你可以直接调用 getText 来查看 typeSpecifier 的类型(TypeSpecifierContext extend RuleContext 提供了这个方法)。