首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Lexer令牌意外

Lexer令牌意外
EN

Stack Overflow用户
提问于 2012-12-03 08:38:15
回答 2查看 184关注 0票数 4

下面这个非常简单的语法示例并不像我所期望的那样(一点也不)。

代码语言:javascript
复制
Declaration :   'VAR';
Letter: ('A'..'Z');

message :   Declaration Letter+;

因此,我所期望的是,任何字母序列都会将lex作为单个字母,而序列“VAR”将被作为单个标记进行词汇处理。

当我查看ANTLRWorks interperter时,我看到以下结果:

  • VARA将解析为message -> "VAR", "A" (预期)
  • VARVA不解析(MismatchedTokenException(-1 != 5)。雷克萨斯击中了第二个VA,并试图对Declaration进行令牌化。预期:message -> "VAR", "V", "A"
  • VARVPP将解析为message -> "VAR", "V", "P", "P" (预期)
  • VARVALL将其解析为message -> "VAR", "VALL"

我想要一些帮助理解这种行为,并建议我如何解决这个问题。

具体地说:

  • 如果以VA开头的字符串后面跟着一个字母,那么它为什么要尝试把所有字符串都托起呢?
  • 为什么lexer不尝试使用以V开头的所有字符串来完成此操作?
  • 如果有一个额外的字符,为什么lexer不尝试这样做呢?
  • 我应该如何改变这个语法来解析我所期望的方式?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-12-03 12:42:15

让我们来看看你的四个例子:

1 "VARA“

一切都好。

2 "VARVA“

"VAR" (很明显)被标记为VAR,但是lexer“看到”"VA"并期望得到一个不存在的"R"。它发出以下错误:

代码语言:javascript
复制
line 1:5 mismatched character '<EOF>' expecting 'R'
line 1:5 required (...)+ loop did not match anything at input '<EOF>'

并丢弃导致创建单个令牌的"VA",正如您在运行ANTLRWorks调试器时所看到的(忽略解析中的异常,它们实际上并不存在:):

你必须意识到的是,雷克萨斯永远不会放弃它已经匹配的东西。因此,如果lexer看到了"VA"并且不能在它之后匹配一个"R",那么它将查看其他可以与"VA"匹配的词汇规则。但是Letter与此不匹配(它只匹配单个字母!)如果您将Letter更改为与多个字符匹配,则ANTLR将能够返回该规则。但是当它匹配一个字母时就不行了: lexer不会为了让"A"规则匹配而放弃来自"VA"Letter。无可奈何:这就是ANTLR的lexer的工作方式。

这通常不是一个问题,因为当关键字不能匹配时,通常会有某种类型的IDENTIFIER规则使词法器返回。

3 "VARVPP“

好的:"VAR"变成了一个VAR,然后莱克星试图在"V"之后匹配一个"A",但是这没有发生,所以莱克星回到了单一"V"Letter规则上。在此之后,"PP"都被标记为Letter

4 "VARVALL“

"VAR"又变成了VAR。然后,"L"中的"VAL"将导致lexer产生以下错误消息:

代码语言:javascript
复制
line 1:5 mismatched character 'L' expecting 'R'

最后一个"L"变成了一个Letter

我想(或希望)前三个问题现在已经回答了,这就留给了你最后的答案:

我应该如何改变这个语法来解析我所期望的方式?

如果前面确实有"VAR",则强制lexer首先查看字符流,如果没有,只需匹配一个"V"并将匹配的令牌类型更改为Letter,如下所示:

代码语言:javascript
复制
Declaration
 : ('VAR')=> 'VAR'
 |           'V'   {$type=Letter;}
 ;

正如我在回答之前提到的,请参阅以下相关的问答:ANTLR lexer can't lookahead at all

票数 5
EN

Stack Overflow用户

发布于 2012-12-03 12:14:14

lexer并不真正执行展望,只有解析器执行;您可以在ANTLR lexer can't lookahead at all中了解更多有关它的信息。所以这里的问题是,一旦VAR不匹配,它就会试图匹配到目前为止得到的结果-- VA --并且没有匹配的标记,因为字母不能匹配两个字符,只有一个字符。

至于解决方案,一个简单的解决方案就是将其更改为单个令牌:

代码语言:javascript
复制
Message :   'VAR' ('A'..'Z')+;
message :   Message;

但是,它不会为每封信给你一个不同的标记。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13679674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档