注意:这是一个自我回答的问题,旨在提供一个关于ANTLR用户最常见的错误之一的参考。
当我测试这个非常简单的语法时:
grammar KeyValues;
keyValueList: keyValue*;
keyValue: key=IDENTIFIER '=' value=INTEGER ';';
IDENTIFIER: [A-Za-z0-9]+;
INTEGER: [0-9]+;
WS: [ \t\r\n]+ -> skip;
foo = 42;
在这种情况下,ANTLR为什么不将42
识别为整数
?
它应该很好地匹配模式[0-9]+
。
如果我颠倒定义integer
和identifier
的顺序,这似乎是可行的,但为什么顺序首先重要呢?
在ANTLR中,lexer与解析器是隔离的,这意味着它会根据lexer语法规则将文本拆分为类型化的令牌,解析器对这个过程没有影响(它不能说“现在给我一个integer
”)。它自己产生一个令牌流。而且,解析器并不关心令牌文本,它只关心与它的规则匹配的令牌类型。
当几个lexer规则可以匹配相同的输入文本时,这可能很容易成为一个问题。在这种情况下,将根据以下优先规则选择令牌类型:
'='
),请使用隐式规则作为令牌类型为了有效地使用ANTLR,记住这些规则是非常重要的。
在问题的示例中,解析器希望看到以下令牌流以匹配keyvalue
解析器规则:identifier
'='
integer
';“
其中'='
和;”
是隐式令牌类型。
由于42
可以同时匹配integer
和identifier
并且identifier
是首先定义的,解析器将接收以下输入:identifier
'='
identifier
;它将无法与
。请记住,解析器不能与lexer通信,它只能从lexer接收数据,因此它不能说“Try to matchkeyvalue
规则匹配的'integer
next”。
最好将lexer规则的重叠最小化,以限制这种效果的影响。在上面的例子中,我们有几个选项:
标识符
重新定义为[A-Za-z][A-Za-z0-9]*
(要求它以字母开头)。这完全避免了这个问题,但防止定义以数字开头的标识符名称,因此它改变了语法的意图。整数
和标识符
。这解决了大多数情况下的问题,但防止定义完全数值化的标识符,因此它还以一种微妙的、不那么明显的方式改变了语法的意图。integer
和identifier
以便优先使用integer
。然后,定义分析器规则id:IDENTIFIER
;然后使用该规则而不是其他分析器规则中的IDENTIFIER
,这会将keyvalue
更改为key=id'='value=integer';'
。下面是第二个lexer行为示例总结:
以下组合语法:
grammar LexerPriorityRulesExample;
// Parser rules
randomParserRule: 'foo'; // Implicitly declared token type
// Lexer rules
BAR: 'bar';
IDENTIFIER: [A-Za-z]+;
BAZ: 'baz';
WS: [ \t\r\n]+ -> skip;
考虑到以下输入:
aaa foo bar baz barz
将从lexer生成以下令牌序列:
identifier
'foo'
bar
identifier
identifier
Eof
>
AAA
是标识符
类型
只有identifier
规则可以与此令牌匹配,没有二义性。
foo
的类型为'foo'
bar
的类型为bar
此文本与bar
规则匹配,该规则在identifier
规则之前定义,因此具有优先级。
BAZ
类型为identifier
该文本与BAZ
规则匹配,但也与identifier
规则匹配。选择后者,因为它是在bar
之前定义的。
给定语法,BAZ
将永远无法匹配,因为Identifier
规则已经覆盖了BAZ
可以匹配的所有内容。
barz
类型为标识符
bar
规则可以匹配此字符串(bar
)的前3个字符,但identifier
规则将匹配4个字符。由于identifier
匹配较长的子字符串,因此它被选在bar
之上。
EOF
(文件末尾)是隐式定义的标记类型,它总是出现在输入的末尾。
作为经验法则,特定的规则应该在更通用的规则之前被定义。如果规则只能匹配先前定义的规则已经覆盖的输入,则永远不会使用该规则。
隐式定义的规则(如'foo'
)的作用就好像它们是在所有其他lexer规则之前定义的。由于它们增加了复杂性,因此最好完全避免它们,而声明显式的lexer规则。这种方法的一个显著优点是只在一个地方有一个令牌列表,而不是将它们分散在语法中。
到目前为止,我有这个: 和这个: 当我测试这个时,它不能采取双倍数字,我收到这个消息: 我该如何解决这个问题?
我试图从thymeleaf输入到我的java类中获取一个值。 错误信息 我的应用程序是用Springboot、Java和Thymeleaf创建的。我做错了什么?ModelandView是否可能不能使用PostMapping?我还按照https://spring.io/guides/gs/handling-form-submission/进行了操作,但当我试图遵循逻辑并在项目中实现时,该示例就开始工
我刚刚开始学习ANTLR4 lexer规则。我的目标是为Java属性文件创建一个简单的语法。以下是我目前掌握的信息:
我制作了一个GUI程序,它统计在主文本字段中输入的任何内容的某些元素。如果文本字段为空,则应弹出一条消息,说明用户应在文本字段中输入文本。我做了一个if语句,如果tfMain==null,JOptionPane消息应该会弹出,但由于某些原因它不会弹出。有没有关于为什么它不会弹出的提示? 这是我的代码:
因此,我尝试在单个查询中,仅在行不存在的情况下插入行。 我的疑问如下: 有时(非常罕见,但仍然如此),它会生成以下错误: 违反主键约束“主键用户角色”。无法在对象“dbo”中插入重复键。用户的角色。重复的键值为(29851,1)。 是。下面是表的架构的完整SQL: 背景: 这是由托管在Apache服务器上的PHP脚本执行的,在数百次事件中,“随机”发生一次(很可能与并发相关)。 更多信息: 提供:
我正试图通过Jison为ChucK语言生成JavaScript解析器,并且已经有了一个良好的开端,只是生成的解析器无法处理语言中的歧义。最初的ChucK编译器是由Bison生成的,它必须能够以某种方式解决这些歧义。 出于这个问题的目的,我已经将这个问题简化为一个仅表示一种歧义的解释语法。作为参考,我列出了所有相关文件(包括生成的解析器)的要点。项目结构如下: 语言/词汇。js:lexer 语法本身