当前位置: 首页 > 文档资料 > Antlr 4 参考 >

3.4 Building a Language Application

优质
小牛编辑
131浏览
2023-12-01

识别 到数组初始化语句后,下一步是 转换 初始化语句,将 short 值转换为对应的十六进制表示,例如将 {99, 3, 451} 转换为 \u0063\u0003\u01c3

要转换 token,首先要从 parse tree 中提取 token,可以用默认的 parse-tree walker,当该 walker 执行深度优先遍历时,会触发一系列回调函数,我们只要继承 XXXBaseListener 并 override 特定方法即可。

先看几个手动转换的例子:

img

  • { 转换为 "
  • } 转换为 "
  • short 转换为 4 位十六进制表示的字符串,并前缀 \u

当 walker 进入、离开每个 phrase 时,都会在 Listener 中触发指定方法,可以在 enterXXX 方法中执行转换:

/**
 * 将 {1, 2, 3} 之类的 short 数组转换为 "\u0001\u0002\u0003`
 */
public class ShortToString extends ArrayInitBaseListener {

    // { -> "
    @Override
    public void enterInit(ArrayInitParser.InitContext ctx) {
        System.out.print('"');
    }

    // } -> "
    @Override
    public void exitInit(ArrayInitParser.InitContext ctx) {
        System.out.print('"');
    }

    @Override
    public void enterValue(ArrayInitParser.ValueContext ctx) {
        // Assumes no nested array initializers
        int value = Integer.valueOf(ctx.INT().getText());
        System.out.printf("\\u%04x", value);
    }
}
  • 不需要 override BaseListener 中的所有方法,按需覆盖;
  • ctx.INT() 从上下文对象中获取 INT token 的值;

实现转换:

// 导入 ANTLR runtime
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;

public class Translate {
    public static void main(String[] args) throws Exception {
        // 从标准输入创建 CharStream
        ANTLRInputStream input = new ANTLRInputStream(System.in);

        // 创建 lexer,处理输入的 CharStream
        ArrayInitLexer lexer = new ArrayInitLexer(input);

        // 创建 buffer of tokens,存储 lexer 生成的 token
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        // 创建 parser,处理 token 缓冲区中的 token
        ArrayInitParser parser = new ArrayInitParser(tokens);

        // 从 init rule,开始语法分析
        ParseTree tree = parser.init();

        /********************* Added ****************/
        // 创建 walker
        ParseTreeWalker walker = new ParseTreeWalker();

        // 遍历 parse tree,触发回调
        walker.walk(new ShortToString(), tree);

        System.out.println();
    }
}
  • 相比 Test.java,只添加了最后 3 行!

编译、运行 Translate

javac *.java
java Translate.java

>{1, 2, 3}
>EOF
>"\u0001\u0002\u0003"

通过 listener 机制,grammar 和 language application 完全解耦。