在ANTLR4中使用显式令牌定义有哪些优点和缺点?我发现单括号中的文本比创建一个单独的标记并用它代替文本更具描述性,更容易使用。
例如:
grammar SimpleTest;
top: library | module ;
library: 'library' library_name ';' ;
library_name: IDENTIFIER;
module: MODULE module_name ';' ;
module_name: IDENTIFIER;
MODULE: 'module' ;
IDENTIFIER: [a-zA-Z0-9]+;
生成的令牌为:
T__0=1
T__1=2
MODULE=3
IDENTIFIER=4
'library'=1
';'=2
'module'=3
如果我对'library'
"令牌"不感兴趣,因为规则已经确定了我要匹配的内容,而且我无论如何都会跳过它,那么用LIBRARY
和令牌声明替换它有意义吗?(代币的数量会增长。)为什么这是ANTLRWorks中的警告?
实际上,隐式和显式令牌之间有区别:
摘自"最终ANTLR4参考",第76页:
ANTLR收集并分离所有字符串文字和lexer语法分析器规则中的规则。"enum"等文字变成词法rules,并紧跟在解析器规则之后,但在显式词汇规则。
ANTLR lexer解决了词汇规则,支持首先指定的规则。
我的突出显示。
Antlr(以及大多数编译器/编译器生成器)实现使用单独的lexer和解析器的概念,主要是出于性能原因。在这个模型中,lexer负责读取输入字符串中的实际字符,并以更简洁的表示形式返回找到的令牌列表,比如每个令牌的枚举或int代码。解析器将处理这些令牌,而不是原始输入,以便于实现和性能。
有两种方法可以"声明"Antlr中令牌的用法,一种是显式的并具有正则模式表达式,另一种是隐式的,始终是固定字符串。
ExplicitRegExp: [A-Z][a-z]+; // lexer rule starts with uppercase letter
ExplicitFixed: 'fixed';
parserRule: 'implicit' ExplicitRegExp; // parser rules starts with lowercase letter
当显式声明一个令牌时,会为其分配一个int代码,以便在解析状态机中使用。假设ExplicitRegExp
变为1,ExplicitFixed
变为2。但是解析器还需要implicit
令牌才能正确解析语法,因此implicit
令牌被隐式地分配了代码3。
怎么这么糟糕?你可能在语法的不同部分有拼写错误:
a : 'implicit' c;
b : 'implcit' d; // typo here
您的语法将无法按预期工作,因为implcit
将是一个有效的令牌,分配了int代码4。由于Antlr自动生成隐式规则的名称(如T___0
),这也使语法/lexer更难调试。另一件事是,您失去了lexer规则的排序,可能会产生差异(通常不是因为隐式令牌都是固定内容)。
Antlr编译器可以选择给你一条错误消息,并要求你显式地编写令牌,但它选择放手,只是警告你不应该这样做,可能是出于原型设计/测试的原因。
为了让Antlr高兴,请以详细的方式进行操作,并声明所有令牌:
grammar SimpleTest;
top: library | module ;
library: 'library' library_name=IDENTIFIER ';' ; // I'm using aliasing instead of different parser rule here, just a preference
module: 'module' module_name=IDENTIFIER ';' ;
MODULE: 'module' ;
LIBRARY: 'library' ;
IDENTIFIER: [a-zA-Z0-9]+;
然后,如果您通过固定令牌的显式名称(如MODULE
)或其内容(如'module'
)引用固定令牌,则没有什么区别。