ANTLR教程(四)语法树遍历机制

方法一: 使用antlr定义的语法树遍历顺序——listener

antlr生成类ParseTreeListener,这个类里面包含了进入语法树种每个节点和退出每个节点时要进行的操作。本质上,就是树的前序和后序遍历。

类的继承关系

这里写图片描述

  1. ANTLR自动生成 XXXListener接口,在类xxxBaseListener中实现所有的方法
  2. 程序员需要做的是集成xxxxBaseListener类

需要与antlr遍历类ParseTreeWalker一起使用

对同一非终结符的不同产生式进行标记

不标记的话实现起来复杂

listeners/Expr.g4
grammar Expr;
s:e;
e:eop=MULTe //MULTis’*’

e op=ADD e // ADD is ‘+’INT

;

  1. listener需要判断哪个e
    listeners/TestEvaluator.java
    public void exitE(ExprParser.EContext ctx) {
    if ( ctx.getChildCount()==3 ) { // operations have 3 children
    int left = values.get(ctx.e(0));
    int right = values.get(ctx.e(1));
    if ( ctx.op.getType()==ExprParser.MULT ) {
    values.put(ctx, left * right);
    }
    else {
    values.put(ctx, left + right);
    } }
    else {
    values.put(ctx, values.get(ctx.getChild(0))); // an INT
    } }
  2. 上下文EContext将三个可选择的产生式放到了同一个上下文
    public static class EContext extends ParserRuleContext {
    public Token op;// derived from label op
    public List e() { … } */ get all e subtrees
    public EContext e(int i) { … } /* get ith e subtree
    public TerminalNode INT() { … } // get INT node if alt 3 of e

    }

解决方法: 标记产生式

e : e MULT e # Mult

e ADD e # Add
INT # Int

;

  1. ANTLR为每个产生式生成函数
    public interface LExprListener extends ParseTreeListener { void enterMult(LExprParser.MultContext ctx);
    void exitMult(LExprParser.MultContext ctx);
    void enterAdd(LExprParser.AddContext ctx);
    void exitAdd(LExprParser.AddContext ctx); void enterInt(LExprParser.IntContext ctx); void exitInt(LExprParser.IntContext ctx); …
    }
  2. ANTLR 生成特定的上下文对象,EContext的子类
  3. IntContext has only an INT() method

特点

  1. 程序员不需要显示定义遍历语法树的顺序,实现简单
  2. 缺点,也是不能显示控制遍历语法树的顺序,visit方式可以
  3. 动作代码与文法产生式解耦,利于文法产生式的重用
  4. 没有返回值,需要使用map、栈等结构在节点间传值

例子

这里写图片描述
语法树遍历时,函数调用顺序
这里写图片描述

方法二: 程序员需要自定义语法树遍历顺序——visit

类的继承关系

这里写图片描述

特点

  1. 程序员可以显示定义遍历语法树的顺序
  2. 不需要与antlr遍历类ParseTreeWalker一起使用,直接对tree操作
  3. 动作代码与文法产生式解耦,利于文法产生式的重用
  4. visitor方法可以直接返回值,返回值的类型必须一致,不需要使用map这种节点间传值方式,效率高

例子

这里写图片描述

PropertyFileVisitor loader = new PropertyFileVisitor();
loader.visit(tree);
System.out.println(loader.props); // print results

方法三: 将动作代码嵌入文法产生式文法

不利于文法产生式在不同的语言中重用

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值