Antlr4 g4通配符配置
在Antlr4中,定义文法规则时,通配符通常会贯穿文法定义始终,包括 关键字、字符串、注释注解、变量 等,都离不开通配符的使用。在通配符使用中,有贪婪匹配和非贪婪匹配两种方式,本文将简单通过示例介绍这两种匹配方式。
1. 贪婪匹配和非贪婪匹配
在Antlr4中,使用 g4 文件定义文法规则时,使用的是EBNF范式。EBNF范式,在处理 (...)?,(...)* 和 (...)+ 时,是贪婪匹配的,就是尽可能地匹配更多的字符。当然,也可以设置只匹配首次匹配到的数据后即返回,这种称为非贪婪匹配。可以通过在原来的 贪婪匹配的后面,加上一个 ? 来表示非贪婪匹配。下面将通过两个例子,来描述贪婪匹配和非贪婪匹配的区别。
(1) 字符串规则
Antlr4 g4 规则(贪婪匹配)如下:
s : STRING+ ;
STRING : ('hua'|'wei')*'wei';
如上面两行内容,STRING 是一个 Lexer,s 是一个 Parser,其中,STRING 需要以字符串 wei 结束,('hua' | 'wei') 表示是 字符串 'hua' 或者 'wei',因为使用的是 ()*,所以是贪婪匹配(*表示匹配0次或多次)。考虑下面的三个字符串:
huaweiweiwei
huahuaweiweihuawei
huaweiabc
通过贪婪匹配,可以匹配到的结果是:
huaweiweiwei
huahuaweiweihuawei
huawei
如下图所示:
当我们将Antlr4 g4规则修改为非贪婪匹配:
s : STRING+ ;
STRING : ('hua'|'wei')*?'wei';
如上,所示,对于上面的文法,我们可以匹配到多个,还是上面的文法,匹配到的结果如下:
huawei wei wei
huahuawei wei huawei
huawei
如上所示,第一个字符串 huaweiweiwei 经过上面的Antlr4规则匹配,匹配成了三个字符串,分别是 huawei、wei、wei,因为 基于非贪婪匹配。在 STRING 中,首先匹配到 huawei,然后在剩下的 weiwei 里面,再匹配到 wei(前面*没有匹配到数据),然后在剩下的 wei 里面,又匹配到 wei,结束。
(2) Comment语法
对于 Comment 语法,我们首先介绍 非贪婪匹配使用,g4定义如下:
c : COMMENT+ ;
COMMENT : '/*' .*? '*/';
test如上,COMMENT 以 /* 开头,以 */ 结尾,中间 .* 表示匹配 0个或者多个字符,问号表示最小匹配(非贪婪),如下面的例子:
/* abc */ ... /* dfas */
表示两个注释,中间 ... 表示其他内容,匹配到的结果如下:
如上,的确匹配到两个注释,中间的 ... 因为没有其他规则可以匹配,因此会报错,但是不影响我们识别。
但是,如果我们修改为贪婪匹配呢?如下所示的语法定义:
c : COMMENT+ ;
COMMENT : '/*' .* '*/';
可以看到匹配的结果如下:
将两个注释及中间的内容,全部合并成了一个注释,其实这种匹配,是不合理的。如果这样设置,那么在代码中,多个注释合并,多个注释中间的代码,不会认为是有效代码。
2. 注意及说明
2.1 正确使用贪婪匹配和非贪婪匹配
在写 g4 文件时,我们需要基于代码解析场景,正确使用贪婪匹配和非贪婪匹配,在 Antlr4 中,绝大部分场景,都是贪婪匹配的,例如 字符串生成、变量名、标识符、数字等,但是也有一些场景,是非贪婪匹配的,例如上面介绍到的 注释匹配。
Antlr4在基于g4生成解析的SDK的时候,在可能有问题的场景中,会给出提示,如下面的提示:
$ java -jar antlr-4.9.2-complete.jar -Dlanguage=Java -visitor Scala.g4
warning(131): Scala.g4:1351:25: greedy block ()* contains wildcard; the non-greedy syntax ()*? may be preferred
原因是,在 Scala.g4 文件(github Scala.g4)里面,对应的地方,Antlr4认为应该是非贪婪匹配,但是此处的语法是贪婪匹配:
2.2 一个错误场景的处理
这里,介绍一个,我在使用Antlr4中,因为上面的warning导致无法正确生成词法和语法的解析代码的问题。
上面,在 2.1节中,提示了一个 warning,但是,词法和语法的解析代码还是会正常生成,但是我在使用Antlr4 Maven插件时,无法生成 ScalaLexer.java 文件,当时,我 Antlr4 Maven插件的设置如下:
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.9.2</version>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
<configuration>
<sourceDirectory>${basedir}/src/main/resources</sourceDirectory>
<outputDirectory>${project.build.directory}/generated-sources/antlr4/zmj/test/antlr4/parser</outputDirectory>
<listener>true</listener>
<visitor>true</visitor>
<treatWarningsAsErrors>true</treatWarningsAsErrors>
</configuration>
</plugin>
</plugins>
</build>
原因就在于:在配置中,我设置了 <treatWarningsAsErrors>true</treatWarningsAsErrors>,将 warning 认为是 error,此时,Antlr4 Maven 插件,在 生成代码时,因为有个 warning,所以将 warning 识别为 error,导致执行失败。
如果认为 g4 中的 warning 无需修改,可以忽略,可以将该参数设置为 false。
- 点赞
- 收藏
- 关注作者
评论(0)