简体   繁体   中英

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

The part of G4 file is :

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

The generated code is :

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);                                                                         
    }                                                                                                                    
}                                                                                                                        

I am tring to see which type is this typeSpecifier in my visit code:

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()));

I can get ouput like :

typeSepcifier the start is int the stop is int

I think this method is ugly, Can Antlr4 offer ways to implement methods like instanceof IntTypeSpecifier ?

You can use the visitor design pattern to visit ANTLR's AST and process it so you don't even need to use 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
}

Call your visitor:

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

If you create a rule for the int type let's say:

typeSpecifier
    : intTypeSpecifier
    | // the other rules
    ;

intTypeSpecifier : 'int';

You will be able to make a visit method for an IntTypeSpecifierContext visitIntTypeSpecifier to easily handle an int type.

So the code should look like:

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
}

Now correct me because I am probably wrong, but you can directly call getText to see the typeSpecifier's type (TypeSpecifierContext extend RuleContext which provides this method).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM