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

  • 2017年9月18日
    本节主要介绍了解释器中的一些基本概念,然后对ANTLR的执行过程重新进行了梳理,最后对ANTLR语法进行了简要梳理,如有任何错误欢迎斧正。

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

一、 解释器中的基本概念

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
$ ls
ArrayInit.g4                ArrayInitLexer.tokens
ArrayInit.tokens            ArrayInitListener.java
ArrayInitBaseListener.java  ArrayInitParser.java
ArrayInitLexer.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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值