之前写过安装antlr4,我希望能用它生成以C++为源码语言的语法分析器。这里并不是说生成的Parser是用在C++身上的,而是Parser本身的源码是C++。
这个操作还是很简单的,直接生成就行。
antlr4 -Dlanguage=Cpp test.g4
要注意是-Dlanguage=Cpp的大小写,不是CPP,也不是cpp。更不是c++、C++。
然后就会生成一些以test*为文件名格式的文件,把其中的.cpp文件放在一起,用g++编译就行了。
g++ ./*.cpp
但真的就行了吗?如果没安装antlr的runtime library,肯定是不行的。
antlr生成的cpp文件编译时需要如"antlr-runtime.h"这样的头文件,也需要链接一些它自己库的函数。如果只是安装一个jar,没有弄这些,肯定是不行的。应该会报错“没有antlr-runtime.h文件或目录”或者"antlr-runtime.h: No such file or directory"这样。
安装运行时库的方法是,去官网找C++的runtime library源码,然后自己编译。
把官网上用于C++的源码的压缩包(.zip)下载并解压
@ubuntu:~$ wget https://www.antlr.org/download/antlr4-cpp-runtime-4.9.3-source.zip
@ubuntu:~$ unzip antlr4-cpp-runtime-4.9.3-source.zip -d antlr4-cpp-runtime-4.9.3
编译
首先确保有以下几个软件支持。
@ubuntu:~$ sudo apt install cmake
@ubuntu:~$ sudo apt install uuid-dev
@ubuntu:~$ sudo apt install pkg-config
cmake是一定要有(不会有人真没有吧),剩下两个没有我也不知道行不行。
然后就准备编译了,还是按照cmake的老套路,新建一个build目录来构造。可以把输出的编译成果都放到一个文件夹里(就叫./run吧),方便找。
@ubuntu:~$ cd antlr4-cpp-runtime-4.9.3/
@ubuntu:~/antlr4-cpp-runtime-4.9.3$ mkdir build && mkdir run && cd build
@ubuntu:~/antlr4-cpp-runtime-4.9.3/build$ cmake ..
@ubuntu:~/antlr4-cpp-runtime-4.9.3/build$ make install DESTDIR=../run
会用cmake的都很懂这个流程了,但我在实操的时候cmake一开始总是不成功,似乎是它试图去什么地方wget一个什么东西,但网络连接总是不稳定。我多试了几次就好了,可能也有通过cmake参数调整来规避这个问题的办法吧,不知道。
编译过程有点慢,就别动,等它跑就行了。
把生成的文件放到系统文件夹里
都跑完了以后,run文件夹里就有东西了,但得把它们拷贝到编译器寻找头文件、库的时候能查到的地方。
@ubuntu:~/antlr4-cpp-runtime-4.9.3/build$ cd ../run/usr/local/include
@ubuntu:~/antlr4-cpp-runtime-4.9.3/run/usr/local/include$ sudo cp -r antlr4-runtime/* /usr/local/include
@ubuntu:~/antlr4-cpp-runtime-4.9.3/run/usr/local/include$ cd ../lib
@ubuntu:~/antlr4-cpp-runtime-4.9.3/run/usr/local/lib$ sudo cp * /usr/local/lib
@ubuntu:~/antlr4-cpp-runtime-4.9.3/run/usr/local/lib$ sudo ldconfig
放过去一劳永逸,但你要是想编译的时候通过编译选项指定头文件和库的路径,也可以不动。最后的ldconfig是为了让新安装的动态链接库为系统所共享(虽然安装了,但也得告诉系统一声,用的时候才知道有)。当然你也可以通过重启来达成这个目的,反正就是为了共享。
有些地方说应该把头文件的antlr4-runtime文件夹直接拷贝到/usr/local/include下,但我发现antlr4生成的c++语法分析器源码中,对runtime头文件的引用就是#include "antlr4-runtime.h",并不是#include "antlr4-runtime/antlr4-runtime.h"。如果你生成的源码是后一种,那确实应该整个拷贝过去,也不是太难理解为什么要这样做。
行了,大功告成。
哦,记得在编译的时候加上“-lantlr4-runtime”,因为g++不会自动链接这个库。
g++ ./*.cpp -lantlr4-runtime