我在ANTLRWorks中遇到EBNF语法问题:
line 37:
upper_lower_case
: LOWER_CASE
| UPPER_CASE
;
line 42:
CLASSNAME
: UPPER_CASE (DIGITS | upper_lower_case )*
;
line 51:
UPPER_CASE
: 'A'..'Z'
;
line 55:
LOWER_CASE
: 'a'..'z'
;
line 60:
DIGITS : '0'..'9'
;
我希望CLASSNAME始终以大写字母开头,而且它可以包含数字,大写或小写字母。
错误日志:
[13:11:59] warning(200): classgenerator.g:43:42:
Decision can match input such as "'0'..'9'" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
[13:11:59] warning(200): classgenerator.g:43:42:
Decision can match input such as "<EOT>" using multiple alternatives: 2, 3
As a result, alternative(s) 3 were disabled for that input
[13:11:59] error(201): classgenerator.g:43:42: The following alternatives can never be
matched: 3
[13:11:59] error(208): classgenerator.g:60:1: The following token definitions can never
be matched because prior tokens match the same input: UPPER_CASE,DIGITS
有人能帮我解决这个问题吗? 提前谢谢。
此致 Hladeo
编辑:
所以我应该使用fragment关键字,如果它没有引用令牌?这样使用fragment关键字会出错吗?
tokens {
PUBLIC = '+';
PRIVATE = '-';
PROTECTED = '=';
}
fragment ACCESSOR
: PUBLIC
| PRIVATE
| PROTECTED
;
和另一个问题。
OBJECTNAME
: UPPER_LOWER_CASE (UPPER_LOWER_CASE | DIGIT)*
;
OBJECTNAME应该包含至少一个字母(大写或小写无关紧要)以及可选的其他字母或数字 - 这部分代码有什么问题?当我尝试键入例如variable
时 - 它没关系,但是当我以大写字母Variable
开头时,我收到了错误:
line 1:15 mismatched input 'Variable' expecting OBJECTNAME
答案 0 :(得分:2)
您的词法分析器规则CLASSNAME
当前引用解析器规则upper_lower_case
(词法分析器规则以大写字母开头;解析器规则以小写开头)。 Lexer规则只能引用词法规则。
此外,UPPER_CASE
,LOWER_CASE
和DIGITS
似乎不应自行创建令牌,因此应将其标记为fragment
规则。在以下示例中,我将DIGITS
更改为DIGIT
,因为它只匹配一位数。
CLASSNAME : UPPER_CASE (DIGIT | UPPER_LOWER_CASE)*;
fragment UPPER_LOWER_CASE : LOWER_CASE | UPPER_CASE;
fragment UPPER_CASE : 'A'..'Z';
fragment LOWER_CASE : 'a'..'z';
fragment DIGIT : '0'..'9';
编辑1(针对问题中的修改):
输入中的一段文字只能有一种令牌类型。例如,考虑输入文本X3
。由于此文本可以匹配CLASSNAME
或OBJECTNAME
,因此词法分析器将最终为其分配出现在语法中的第一个规则的类型。换句话说,如果语法CLASSNAME
之前出现OBJECTNAME
,则输入X3
将始终成为CLASSNAME
令牌并且永远不会成为OBJECTNAME
令牌。如果语法OBJECTNAME
之前出现CLASSNAME
,则输入X3
将始终为OBJECTNAME
而永远不会 CLASSNAME
(事实上,在这种情况下,任何令牌都不会是CLASSNAME
)。
您的ACCESSOR
规则看起来应该是解析器规则,如下所示:
accessor : PUBLIC | PROTECTED | PRIVATE;
编辑2(关于区分CLASSNAME
和OBJECTNAME
的评论):
要区分CLASSNAME
和OBJECTNAME
,您可以创建与之匹配的词法分析器IDENTIFIER
。
IDENTIFIER : UPPER_LOWER_CASE (DIGIT | UPPER_LOWER_CASE)*;
然后,您可以创建解析器规则来处理区别:
classname : IDENTIFIER;
objectname : IDENTIFIER;
显然,这允许x3
成为classname
,这在您的语言中无效。在可能的情况下,我总是更喜欢放松解析器规则并稍后执行进一步验证,我可以提供更好的错误消息。例如,如果允许x3
匹配classname
,那么在解析输入并具有AST(ANTLR 3)或解析树(ANTLR 4)之后,您可以查找{{1}的所有实例。 1}}并确保匹配的classname
以所需的大写字母开头。
解析器的自动错误报告产生的示例错误消息:
第1:15行不匹配的输入'变量'期待CLASSNAME
单独验证产生的示例错误消息:
第1:15行类名
开头IDENTIFIER
必须以大写字母