ANTLR4语法:听众/访客评估或更好的递归评估?

时间:2016-02-24 16:59:00

标签: java parsing antlr4

我想用ANTLR4来评估这个语法:

    grammar GrammarStack;

    prog: sentence+;

    sentence:
            ID 'owns' carDef  
    ;   

    carDef:
            'a' car ( 'and' 'a' car)* '.'
    ;

    car:
        type = ('Toyota'  | 'Ford' | 'Hyundai' | 'Chevrolet' | 'Opel' | 'BMW')
    ;

    COLON: ':' ;
    HASH: '#';
    SEMI: ';';
    ID: [a-zA-Z][a-zA-z0-9]+;
    WS  :   [ \t\n\r]+ -> channel(HIDDEN);
    ANY_CHAR : . ; 

并且监听器的实现:

    import org.antlr.v4.runtime.ParserRuleContext;
    import org.antlr.v4.runtime.tree.ErrorNode;
    import org.antlr.v4.runtime.tree.TerminalNode;
    import java.util.Stack;


    public class MyGrammarStackListener extends GrammarStackBaseListener {
        Stack lifo = new Stack();

        @Override public void enterCarDef(GrammarStackParser.CarDefContext ctx) { 

        }
        @Override public void exitCarDef(GrammarStackParser.CarDefContext ctx) {
            GrammarStackParser.SentenceContext  sctx = (GrammarStackParser.SentenceContext )ctx.parent;
            System.out.println("this is the carDef for : " + sctx.ID().getText());
            for (int i=0;i<ctx.car().size();i++) {
                if (ctx.car(i)!=null) System.out.println("car no. " + (ctx.car().size()-i)       +  ": " + lifo.pop());
            }
            // here I should definitely also find out, if there are AND options

        }

        @Override public void enterCar(GrammarStackParser.CarContext ctx) {
             lifo.push(ctx.type.getText());
        }
    }

在这个例子中,监听器的实现很简单, 虽然我需要一个堆栈来收集变量。

但如果汽车会更复杂(比如一些汽车会有 依赖信息的定义),我更愿意 使用递归而不是监听器。

喜欢

Object exec(int ruletype, Context ctx) {
    switch (ruleType) ..
      case CARDEF_ :  {
        CarStruct cs = exec(ctx.car);
      }

说这个可能更清楚: 我想使用递归函数进行evualating 规则而不是为...编写单独的函数 每条规则。而不是存储相关的信息 在每个特定的功能我想打电话 一些eval-function,它在树下(只要 必要的)并将信息提供给 这一点,需要它。

这可以在ANTLR4中实现吗?

我在这里找到了这种类型的递归执行逻辑的代码 书&#34;语言实现模式&#34;,但有AST(摘要 使用语法树)对我来说它不是 显而易见如何将此应用于上述示例 (例如,从哪里(或者如果)exec函数可以继承或在哪里 可以访问AST。

1 个答案:

答案 0 :(得分:1)

为了简化这些操作,Antlr实现了一个名为YourGrammarNameBaseVisitor的基类,使用visitor pattern下降到语法树的节点。 BaseVisitor有一个名为Visit的方法,它实现了switch或多或少的VisitRuleName,用于选择应该访问哪个规则&#34;下一个。语法中的每个规则都有一个Integer方法。这些方法的基本实现将简单地下降到内部规则中,但是应该覆盖这些规则以在下降期间采取某些操作或更改规则被访问的顺序。

请注意,Visitor类包含一个泛型参数,该参数是每个Visit方法的返回值。有时,如果要创建非常具体的访问者(例如计算器语法),则放置类似Object的类型是有用的,但您始终可以将通用参数设置为Voidclass MyVisitor extends GrammarStackBaseVisitor<Object> { @Override public Object visitCarDef(GrammarStackParser.CarDefContext ctx) { List<Car> cars = new ArrayList<Car>(); // now for each car inside carDef for (GrammarStackParser.CarContext carCtx : ctx.car()) { Car car = (Car)visitCar(carCtx); // here is the recursion! cars.add(car); } return cars; } @Override public Object visitCar(GrammarStackParser.CarContext ctx) { String type = car.type().getText(); return new Car(type); } }

在您的示例语法中,我们可以使用与此类似的代码:

{{1}}