ANTLR4:隐式或显式标记定义

TFu*_*uto 3 antlr token antlrworks antlr4

在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]+;
Run Code Online (Sandbox Code Playgroud)

生成的令牌是:

T__0=1
T__1=2
MODULE=3
IDENTIFIER=4
'library'=1
';'=2
'module'=3
Run Code Online (Sandbox Code Playgroud)

如果我对'library'"令牌" 不感兴趣,因为规则已经确定了我所匹配的内容,而且无论如何我都会跳过它,用LIBRARY令牌声明替换它是否有意义?(然后令牌的数量会增加.)为什么这是ANTLRWorks中的警告?

TFu*_*uto 6

实际上,隐式令牌和显式令牌之间存在差异:

来自“权威 ANTLR4 参考”,第 76 页:

ANTLR 从解析器规则中收集和分离所有字符串文字和词法规则。诸如“enum”之类的字面量成为词法规则并紧跟在解析器规则之后但在显式词法规则之前

ANTLR 词法分析器通过偏爱首先指定的规则来解决词法规则之间的歧义。

从我突出。


Mep*_*phy 5

Antlr(和大多数编译器/编译器生成器)实现使用单独的词法分析器和解析器的概念,主要是出于性能原因.在这个模型中,词法分析器负责读取输入字符串中的实际字符,并以更简洁的表示形式返回找到的标记列表,如每个标记的枚举或int代码.解析器将使用这些令牌而不是原始输入,以便于实现和性能.

有两种方法可以在Antlr中"声明"令牌的使用,一种是显式的并且具有常规的模式表达,另一种是隐式的,始终是固定的字符串.

ExplicitRegExp: [A-Z][a-z]+; // lexer rule starts with uppercase letter
ExplicitFixed: 'fixed';
parserRule: 'implicit' ExplicitRegExp; // parser rules starts with lowercase letter
Run Code Online (Sandbox Code Playgroud)

当显式声明一个标记时,它被分配一个在解析状态机中使用的int-code.假设ExplicitRegExp变为1并ExplicitFixed变为2.但是解析器还需要implicit令牌能够正确地解析语法,因此implicit令牌被隐含地分配了代码3 .

怎么那么糟糕?你可能在语法的不同部分有拼写错误:

a : 'implicit' c;
b : 'implcit' d; // typo here
Run Code Online (Sandbox Code Playgroud)

并且你的语法将不会按预期工作,因为implcit它将是一个有效的标记,分配了int-code 4.由于Antlr自动为隐式规则生成名称,它也使你的语法/词法分析器更难调试T___0.另一件事是你失去了词法分析器规则的顺序,这可能会产生差异(通常不是因为隐式令牌都是固定内容).

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]+;
Run Code Online (Sandbox Code Playgroud)

如果您通过显式名称(如MODULE)或其内容(如'module')引用固定令牌,则没有任何区别.