解释器构造实践-ANTLR(二)

来源:互联网 发布:匹配滤波器 矩阵算法 编辑:程序博客网 时间:2024/06/06 00:00
  • 2017年9月18日
    本节主要介绍了解释器中的一些基本概念,然后对ANTLR的执行过程重新进行了梳理,最后对ANTLR语法进行了简要梳理,如有任何错误欢迎斧正。

  • 2017年9月22日
    对本文页面进行了一些调整

    • 一 解释器中的基本概念
      • 1 解释器interpreter
      • 2 翻译器translator
      • 3 编译器compiler
      • 4 词法分析lexical analyzer
      • 5 语法分析parser or syntax analyzer
    • 二 ANTLR的执行过程
      • 1 制定语法规则
      • 2 生成分析器
      • 3 编译源代码
      • 4 测试语法
      • 5 添加主函数
      • 6 重新编译
      • 7 执行
    • 三 简略语法说明
    • 四 问题
    • 五 参考链接

一、 解释器中的基本概念

1.1 解释器(interpreter)

通常来说,如果一个程序能够计算,或者说是“执行”语句,我们就将其称为解释器。
如计算器、python解释器等。

1.2 翻译器(translator)

如果一个程序能够将一种语言翻译成其他语言,我们就将其称之为翻译器。
如Java到C#的转换与编译器。

1.3 编译器(compiler)

编译器就是将“一种语言(通常为高级语言)”翻译为“另一种语言(通常为低级语言)”的程序

1.4 词法分析(lexical analyzer)

将字符划分为单词或token的过程称为词法分析

1.5 语法分析(parser or syntax analyzer)

在词法分析的基础上将单词序列组合成各类语法短语

二、 ANTLR的执行过程

2.1 制定语法规则

就像我们在《解释器构造实践-ANTLR(一)》(以下简称为(一))中所写过的HelloWorld一样,首先我们需要一个grammar文件,这个grammar文件用于描述各种自定义的规则。

这次我们使用一个数组初始化的语法(ArrayInit):

//头信息,grammar后接语法名,与文件名相同 grammar ArrayInit;   //init将匹配在大括号中,由英文逗号分割的值init : '{' value (',' value)* '}' ; //值可以是整数,也可以是嵌套的数组。‘|’表示或者。value : init | INT ;//匹配整数 INT : [0-9]+ ; //忽略空格、制表、换行 WS : [ \t\r\n]+ -> skip ; 

2.2 生成分析器

在(一)中我们已经配置过了antlr4的别名或者shell脚本,接下来用antlr4指令生成分析文件:

$ antlr4 ArrayInit.g4$ lsArrayInit.g4                ArrayInitLexer.tokensArrayInit.tokens            ArrayInitListener.javaArrayInitBaseListener.java  ArrayInitParser.javaArrayInitLexer.java
ArrayInit├── ArrayInit.g4                -- 语法文件├── ArrayInit.tokens            -- ├── ArrayInitBaseListener.java  -- 缺省情况下生成的Listener├── ArrayInitLexer.java         -- 词法分析器├── ArrayInitLexer.tokens       -- ├── ArrayInitListener.java      -- 缺省情况下生成的Listener└── ArrayInitParser.java        -- 语法分析器

补充说明
ANTLR对生成语法树有两种遍历方法,分别为listener与visitor,如上默认选择的是listener。

  • listener:在遍历语法树时,自动回调Listener中回调方法。实现简单,全自动,采用深度优先遍历,只需要实现listener中的各个接口方法即可完成语义表达。

  • vistior:提供了可以控制遍历过程的一种方式,通过调用visit方法,可以访问子树节点。我们可以采用antlr4 -no-listener -visitor *.g4来生成visit遍历方法而非listener。

2.3 编译源代码

$ javac *.java

2.4 测试语法

在(一)中我们已经配置过了grun的别名,接下来用grun指令进行测试:

$ grun ArrayInit init -tokens{99, 3, 451}EOF[@0,0:0='{',<1>,1:0][@1,1:2='99',<4>,1:1][@2,3:3=',',<2>,1:3][@3,5:5='3',<4>,1:5][@4,6:6=',',<2>,1:6][@5,8:10='451',<4>,1:8][@6,11:11='}',<3>,1:11][@7,13:12='<EOF>',<-1>,2:0]

2.5 添加主函数

//导入antlr的运行时库import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.*;public class Test {    public static void main(String[] args) throws Exception {         //创建一个读取标准输入的CharStream        ANTLRInputStream input = new ANTLRInputStream(System.in);        //创建一个从指定的CharStream中读取数据的词法分析器        ArrayInitLexer lexer = new ArrayInitLexer(input);        //创建一个词法分析器产生的token缓冲        CommonTokenStream tokens = new CommonTokenStream(lexer);        //创建一个从token缓冲中读取token的语法分析器        ArrayInitParser parser = new ArrayInitParser(tokens);        //开始分析规则init        ParseTree tree = parser.init();         //打印Lisp风格的语法分析树        System.out.println(tree.toStringTree(parser));     }}

2.6 重新编译

$ javac Array*.java Test.java

2.7 执行

$ java Test{1,{2,3},4}EOF(init { (value 1) , (value (init { (value 2) , (value 3) })) , (value 4) })

三、 简略语法说明

  • 语法(grammar)由一系列的规则(rule)组成
  • 由小写字母开始的规则组成分析规则
  • 由大写字母开始的规则组成词法规则
  • 用|符号来表示可选择的规则,用圆括号的形式来表示子规则
  • 待补充

四、 问题

  1. 翻译器(translator)与编译器(compiler)的区别

五、 参考链接

  1. 百度百科 编译器
    https://baike.baidu.com/item/编译器/8853067?fr=aladdin
  2. 《The Definitive ANTLR 4 Reference》
    https://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference
  3. 《Antlr v4入门教程》
    http://blog.csdn.net/dc_726/article/details/45399371
阅读全文
0 0
原创粉丝点击