如何把antlr4融合到编译器项目中使用

antlr4是什么?

antlr4是一个开源的词法、语法分析程序生成器,仅需要配置词法和语法规则,即可自动生成语言编译器所需的词法、语法分析程序。

问题:antlr4官方给出了jar包,可以命令行运行使用,但是要是想把源码直接融合到自己的编译器项目中去,如何做呢?

1 下载源码

git clone https://github.com/antlr/antlr4.git

2 寻找程序主入口

官方给出的jar包运行方式是:

java -jar antlr-xxx.jar Hello.g4

java org.antlr.v4.Tool Hello.g4

可以看到antlr4的程序主入口是 org.antlr.v4.Tool 。除此之外,还有一种找程序入口的方法,可以打开项目pom.xml,<CTRL+F>查找一下mainClass
在这里插入图片描述

3 打开Tool.java

在这里插入图片描述
可以看到main函数中,使用了args参数,也就是传递 g4 文件地址。按道理说,只要我们引入源码,然后带参数运行此main函数就可以像命令行那样使用了,但是事实上,编译都没通过。

4 解决编译报错

源码的编译报错,一般不太可能是代码语法问题,基本上都是类找不到,依赖的包没有,antlr4也是如此。

解决依赖包的问题
antlr4依赖项可以从pom.xml<dependencies>标签中找到,如下:

	<dependencies>
		<dependency>
			<groupId>org.antlr</groupId>
			<artifactId>antlr4-runtime</artifactId>
			<version>${project.version}</version>
		</dependency>
		<dependency>
			<groupId>org.antlr</groupId>
			<artifactId>antlr-runtime</artifactId>
			<version>3.5.2</version>
		</dependency>
		<dependency>
			<groupId>org.antlr</groupId>
			<artifactId>ST4</artifactId>
			<version>4.3</version>
		</dependency>
		<dependency>
			<groupId>org.abego.treelayout</groupId>
			<artifactId>org.abego.treelayout.core</artifactId>
			<version>1.0.3</version>
		</dependency>
		<dependency>
			<groupId>org.glassfish</groupId>
			<artifactId>javax.json</artifactId>
			<version>1.0.4</version>
		</dependency>
		<dependency>
			<groupId>com.ibm.icu</groupId>
			<artifactId>icu4j</artifactId>
			<version>61.1</version>
		</dependency>
	</dependencies>

把这段配置加入到自己项目的pom.xml中去,Maven重新构建一下项目,把包装上即可。

解决源码中g文件的编译问题

这个问题相当有趣。在antlr4中有部分源码是用 antlr3 编译 g 文件自动生成的,但是源码中并没有给出这些生成的源码,所以需要自己手动生成。从ANTLR官方下载网址可以看到这样一句话:

ANTLR v4 is written in ANTLR v3.5.2 and StringTemplate 4.3. In antlr-4.9.1-complete.jar, you’ll find everything you need to run the ANTLR tool and make its generated parsers work.

摘自 https://www.antlr.org/download.html

所以,我们需要去下载 antlr3 来对 antlr4 源码中的 g 文件进行编译生成依赖的类文件。点击打开antlr3的官网下载渠道

编译的命令和antlr4是一样的。大部分的 g 文件在 org.antlr.v4.parse包内,生成前的包内是这样的:
在这里插入图片描述
生成后的包内是这样的:
在这里插入图片描述

解决找不到UnicodeData.java类

这个问题很棘手,在org.antlr.v4.unicode.UnicodeDataTemplateController类中,可以看到这样一段注释:

/**
* StringTemplate controller used to generate parameters to feed
* to {@code unicodedata.st} to code-generate {@code UnicodeData.java},
* used by the tool for Unicode property escapes like {@code \p{Lu}}.
*
* Uses ICU to iterate over Unicode character categories, properties,
* and script codes, as well as aliases for those codes.
*
* This class exists in its own Maven module to avoid adding a
* dependency from the tool onto the (large) ICU runtime.
*/

透过这段话,可以知道,UnicodeData.java是由unicodedata.st模板生成的,这应该是要调用源码中某个类的方法来生成。遗憾的是,我找了很久依然不知道如何生成这个类。好在我发现了,其实源码中已经给出了这些需要自动生成的类,只是没有放在正确的位置罢了。

target/generated-sources/tool/src/org/antlr/v4/unicode/UnicodeData.java 

target/generated-sources/antlr3/org/antlr/v4/parse/...      —— 这是parse包内编译 g 文件 自动生成的代码集合

target/generated-sources/antlr3/org/antlr/v4/codegen/...    —— 这是codegen包内编译 g 文件 自动生成的代码集合

Antlr的作者还是很良心的,其实已经把需要的类,帮我们生成了,放在 generated-sources 文件夹下了。

解决找不到 org.antlr.v4.runtime包的问题

r u n t i m e runtime runtime包是antlr4生成的词法和语法文件运行时所需的包,但是不知道为啥编译时竟然也需要这个包。不管他,还是在下载的源码包里去找,根目录有一个runtime文件夹,下面给出了各个目标语言所需的运行时包:
在这里插入图片描述
我这里把Java里面的runtime包,拷贝到 org.antlr.v4.runtime 即可

基本上到这里,所有需要的依赖包或者类都已经加入或生成,源码中编译问题是没有了。

5 解决运行时报错问题

解决了编译问题后,给 Tool.java 一个参数,运行了一下,发现报这个错误:
在这里插入图片描述
找不到 org/antlr/v4/tool/templates/messages/formats/antlr.stg 这个模板文件,去源码中看,tool包下确实没有 templates 这个文件夹。经过查找,在 target/classes/org/antlr/v4/tool 里发现了这个 templates 文件夹。于是将其放至源码 src 下的tool包里,发现依然是这个错误,但是路径应该是没有问题的。

打开 ErrorManager.java 对应错误的位置读一下源码:
在这里插入图片描述
错误位置为 231 行 ,因为urlnull,往上看,有两行关键代码:

        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        URL url = cl.getResource(fileName);

fileName就是上一个图中打印出来的 org/antlr/v4/tool/templates/messages/formats/antlr.stg。这样搞清楚这两行是什么意思,就知道程序为什么会报错。所幸,在这片博文https://www.cnblogs.com/lingxi2b2/p/12063623.html中找到了答案。这里cl.getResource(fileName)相对的是ClassPath的目录,所以这个templates文件夹应该放到classes里面,而不是src下面。

6 成功run起来了

在这里插入图片描述


更新 1

忘记可以直接访问jar包里的资源了,直接Maven导入依赖包,然后import即可使用,瞎搞了一圈。如果想把jar包中的资源也打包进自己的项目,可以先将jar包下载,并放至lib下,然后配置pom.xml,进行打包。


更新 2

没有白费功夫!在源码入口文件Tool.java中,main函数执行结束,强制进行了程序退出,也就是说如果仅是引入依赖包使用,那么调用Tool.main函数后,程序就自动退出了,还是没有起到融合的效果。所以还是得引入源码,然后修改源码来解决这个问题。
在这里插入图片描述
解决程序强制退出问题

这是由于源码中的System.exit(0)引起的,只需要把调用exit函数的地方全部注释掉即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

angelavor

觉得有收获,给我个三连吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值