在访问者之间共享Antlr访问者代码

时间:2018-09-28 17:26:02

标签: java antlr antlr4 visitor

我有两个语法文件/访问者,简单和复杂,它们将JSON对象解析为字符串。我要解析的Complex对象本质上可以包含许多Simple对象(以及其他内容)。为了简单起见,假设当我解析基本的Simple对象(而不是Complex对象中包含的Simple对象)时,我想使用类似“ Simple start:”的字符串开头,但是当我到达Complex对象中的Simple对象时我想从别的东西开始,说“ Simple in Complex:”。

因此,当前我有两个不同的访问者类,简单访问者的visitSimpleObject方法将返回以“ Simple Start:”开头的字符串,而复杂访问者的visitSimpleObject方法将返回以“ Simple Start”开头的字符串在Complex中:“。除了这种区别之外,其他所有对象都应该相同,无论是在对象本身还是在Complex对象内部,Simple对象中的其他所有内容都可以解析为相同。

我的问题是,如何在这两个访问者之间共享代码?显然,我可以将所有适用的SimpleVisitor代码复制并粘贴到ComplexVisitor中,但随后必须保持同步以进行任何更改。

注意:两个访问者类已经扩展了BaseVisitor类,所以我不能使用典型的继承

1 个答案:

答案 0 :(得分:0)

您可以使用继承来做到这一点,例如: https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

一个简短的例子是:

abstract class Visitor{

    public void sharedMethod() {
        //Do something
    }

    public abstract void visitSimpleObject();
}

class SimpleVisitor extends Visitor{

    @Override
    public void visitSimpleObject() {
        System.out.println("Simple Start:");
    }
}

class ComplexVisitor extends Visitor{

    @Override
    public void visitSimpleObject() {
        System.out.println("Simple within Complex:");   
    }
}

在这种情况下,两个访问者都将从共享代码所在的同一超类(访问者)扩展。这两个子类都可以定义自己的行为。超类本身也可以扩展其他类型的访问者(或实现接口)。

编辑

评论之后,可能更像这样:

示例g4:     语法Ex;

START_COMPLEX : 'complex';
START_SIMPLE : 'simple';
SEPERATOR : ':';
TEXT : [A-Za-z]+;

simple : START_SIMPLE ' ' SEPERATOR ' ' TEXT;
complex : START_COMPLEX ' ' SEPERATOR ' ' TEXT;

还有一个代码示例:

public class Example{

    abstract class Visitor extends ExBaseVisitor<String>{
        @Override
        public String visitComplex(ExParser.ComplexContext ctx) {
            System.out.println("Visiting complex");
            return "";
        }

    }

    class SimpleVisitor extends Visitor{
        @Override
        public String visitSimple(ExParser.SimpleContext ctx) {
            System.out.println("Visiting Simple! " + ctx.TEXT());   
            return "";
            }
    }

    class ComplexVisitor extends Visitor{

        @Override
        public String visitSimple(ExParser.SimpleContext ctx) {
            System.out.println("Visiting Simple, from within complex! " + ctx.TEXT());  
            return "";
            }
    }



    public static void main(String[] args) {
        String text = "simple : hi";
        CharStream charStream = new ANTLRInputStream(text);
        ExLexer exLexer = new ExLexer(charStream);
        TokenStream tokenStream = new CommonTokenStream(exLexer);
        ExParser exParser = new ExParser(tokenStream);

        ComplexVisitor complexVisitor = new Example().new ComplexVisitor();
        complexVisitor.visit(exParser.simple());

        String text2 = "simple : hmmmmm";
        CharStream charStream2 = new ANTLRInputStream(text2);
        ExLexer exLexer2 = new ExLexer(charStream2);
        TokenStream tokenStream2 = new CommonTokenStream(exLexer2);
        ExParser exParser2 = new ExParser(tokenStream2);

        SimpleVisitor simpleVisitor = new Example().new SimpleVisitor();
        simpleVisitor.visit(exParser2.simple());


    }


}

对我来说,此打印:

  

从复杂内部访问简单!嗨

     

访问简单! hmmmmm

现在共享的代码是visitComplex,这可能有点愚蠢,但对于示例来说可能还可以。