如何解决ANTLR4 是否仍然支持无扫描器解析器语法?
我有一个使用 CharsAsTokens 人造词法分析器的无扫描器语法分析器,它为 ANTLR4 版本到 4.6 生成一个可用的 Java 分析器类。但是当更新到 ANTLR 4.7.2 到 4.9.3-SNAPSHOT 时,该工具会从同一个语法文件中生成产生数十个编译错误的代码,详情如下。
我的问题很简单:是否不再支持无扫描器解析器语法,或者必须在 4.7 及更高版本中以不同方式指定基于字符的终端?
更新:
很遗憾,我无法在此处发布我的完整语法,因为它源自 FOUO 安全标记指南,美国政府限制访问该指南(我是 DoD/IC 承包商)。
但是,不兼容的升级问题完全可以通过 Ter 在 CSQL.g4 的第 5.6 节中提到的 The Definitive ANTLR 4 Reference 无扫描仪解析器语法示例重现。
与我的语法一样,Csql 示例使用 CharsAsTokens.java 作为其标记器,并使用 CharVocab.tokens 作为其标记词汇。
请注意,每个令牌名称都由其 ASCII 字符-文字等效项指定,如下所示:
'\*'=42
'+'=43
star: '*' ws? ;
plus: '+' ws? ;
这里的问题是,使用 ANTLR4 版本 4.2 到 4.6 会根据这些语法生成可编译的解析器类,而 ANTLR v4.7.2 及更高版本会生成带有大量错误的 Java 代码。
这是来自 ANTLR v4.6 生成的可用 Csql Java 类定义的片段:
public static class ArgsContext extends ParserRuleContext {
public List<ArgContext> arg() {
return getRuleContexts(ArgContext.class);
}
public ArgContext arg(int i) {
return getRuleContext(ArgContext.class,i);
}
public ArgsContext(ParserRuleContext parent,int invokingState) {
super(parent,invokingState);
}
@Override public int getRuleIndex() { return RULE_args; }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof CsqlListener ) ((CsqlListener)listener).enterargs(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof CsqlListener ) ((CsqlListener)listener).exitArgs(this);
}
}
public static class ArgsContext extends ParserRuleContext {
public List<ArgContext> arg() {
return getRuleContexts(ArgContext.class);
}
public ArgContext arg(int i) {
return getRuleContext(ArgContext.class,i);
}
public List<TerminalNode> ','() { return getTokens(Csql.','); } // line 446
public TerminalNode ','(int i) { // line 447
return getToken(Csql.',',i); // line 448
} // line 449
public ArgsContext(ParserRuleContext parent,invokingState);
}
@Override public int getRuleIndex() { return RULE_args; }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof CsqlListener ) ((CsqlListener)listener).enterargs(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof CsqlListener ) ((CsqlListener)listener).exitArgs(this);
}
}
上面的编号行仅由较新的 ANTLR 工具生成(没有添加注释),编译后结果为:
Syntax error on token "','",Identifier expected Csql.java /Csql/generated-sources line 446 Java Problem
Syntax error on token "',delete this token Csql.java /Csql/generated-sources line 447 Java Problem
Csql cannot be resolved to a variable Csql.java /Csql/generated-sources line 448 Java Problem
Syntax error on token ".",expected Csql.java /Csql/generated-sources line 448 Java Problem
那么为什么 ANTLR v4.7+ 中有向后不兼容的变化,我应该如何最好地解决它?
解决方法
尝试定义 GrammarLexer.g4 文件而不是 GrammarLexer.tokens 文件。 (如果您创建 GrammarLexer.tokens 文件,您仍然会像使用 options: { tokenVocab = GrammarLexer; }
一样使用它}它可以很简单:
T1 : ' ';
T2 : '\n';
T3 : '\r';
T4 : 'a';
T5 : 'b';
这将为您创建令牌名称。 Antlr 将允许您在解析器语法规则中使用 'a'
、'\n'
等,但会将它们与词法分析器语法中的词法规则名称匹配并使用该名称(例如:{{ 1}} 当您的规则中有 T4
时,而 'a'
当您有 T2
) 以便编译干净。只要您的 '\n'
产生相同的标记值,您就不必使用词法分析器。 (不过,仔细想想,这个杠杆可能相当于您正在使用的 CharsAsTokens
标记器,并且可以保证标记号匹配。)
这似乎仍然可以实现您的目标,即令牌只是一个字符流,并处理解析器规则中的所有内容。 (并且不会比生成 *.tokens 文件更麻烦。两者都需要是所有有效字符的详尽列表。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。