前言
ANTLR是一款强大的语言解析工具,包含语法分析器、词法分析器等。可以用来实现语言解析器、编译器、配置文件读取器等等。也可以用来实现自己的编程语言。感谢Terence Parr教授多年研究的成果,为语言开发进行了大量的基础工作。关于ANTLR的介绍网上不少,但以简单范例居多,antlr内部复杂的原理、部件、逻辑关系等信息非常少。
由于在工作中需要进行一款解释器开发,虽然看完了两本教程,但结合到自己的实际场景开发,还是有些瞎子摸象的困惑。经过不断的摸索、爬坑,积累了一点经验,实在是感觉艰辛,故作此文,如能对广大朋友们有所帮助,也便不枉费了我的艰苦投入。
版本及工具准备
现在antlr的最新版是4.7.2。可以从https://github.com/antlr/antlr4 下载到源代码和工具包。
开发我用的是visual studio 2019 community,安装了跨平台,支持linux开发。
开发语言C++。
远程环境ubuntu 16.04.6 LTS。
由于我用了C++语言,需要配置antlr生成C++源代码,这里用github上的命令,做成sh脚本即可。
#!/bin/bash
set -o errexit
java -cp $CLASSPATH org.antlr.v4.Tool -Dlanguage=Cpp -listener -visitor -o generated/ -package antlrCplr XLexer.g4 XParser.g4
脚本参数-Dlanguage=Cpp指定生成cpp源文件,-o generated/指定生成的源文件都放在当前目录的子目录generated底下。如果没有目录,则会创建目录。 -package antlrCplr 指将生成的类打包放在命名空间antlrCplr 中。
生成成功后,大概是这样
信息输入
环境配置什么的,其实应该单独写一篇的,还有很多很多配置,挺麻烦的。扯得有点远了。。。言归正传。
antlr可以解析文法,肯定是需要输入才能解析的。antlr提供了多种输入方式,可以直接输入字符串,也可以读文件。
先来两个样例:
字符串输入
ANTLRInputStream input(u8"? = ? + \"?\";(((x * π))) * µ + ∰; a + (x * (y ? 0 : 1) + z);");
文件流输入
std::istream iss(&in);
ANTLRInputStream input(iss);
可以看出,antlr使用了一个类ANTLRInputStream 来进行文本输入。
ANTLRInputStream
位于runtime/src/ANTLRInputStream.h中,定义为
class ANTLR4CPP_PUBLIC ANTLRInputStream : public CharStream
该类拥有3个构造函数,分别是
ANTLRInputStream(const std::string &input = "");
ANTLRInputStream(const char data_[], size_t numberOfActualCharsInArray);
ANTLRInputStream(std::istream &stream);
可以接受字符串类型、字节数组类型、输入流类型的方式。如果采用输入流方式,这个类内部将其转换为字符串进行处理。
virtual void load(const std::string &input);
virtual void load(std::istream &stream);
load函数也有2个实现,输入流转换为字符串,就是在这里实现的。第二个函数会调用第一个函数,将输入字符/文本存储在类内部的变量UTF32String _data;中。
这个流的实例,会给词法分析器的作为输入,词法分析器在此基础上,解析词法流。