【问题标题】:EBNF grammar (ANTLR)EBNF 语法 (ANTLR)
【发布时间】:2013-05-13 11:19:22
【问题描述】:

我在 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

谁能帮我解决这个问题? 提前致谢。

问候, 哈拉迪奥

编辑:

所以我应该使用片段关键字,如果它不引用令牌?这样使用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

【问题讨论】:

    标签: antlr grammar ebnf


    【解决方案1】:

    您的词法分析器规则CLASSNAME 当前引用解析器规则upper_lower_case(词法分析器规则以大写字母开头;解析器规则以小写字母开头)。词法分析器规则只能引用词法分析器规则。

    此外,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 标记并且永远 是@ 987654337@ 令牌。如果在语法中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) 后,您可以查找 classname 的所有实例并确保匹配的IDENTIFIER 以所需的大写字母开头。

    解析器自动错误报告产生的错误信息示例:

    第 1:15 行不匹配的输入“变量”需要 CLASSNAME

    单独验证产生的错误信息示例:

    第 1:15 行类名 variable 必须以大写字母开头

    【讨论】:

    • 那么有没有可能区分CLASSNAME和OBJECTNAME?我正在编写简单的 Java 类生成器,我可以在其中键入:create ClassName +name:String, -age:int; 其中变量、年龄、字符串和 int 是 OBJECTNAME。
    • 我有点失望,它不能在解析器阶段完成。无论如何,非常感谢你的帮助:)
    • @Hladeo 相反,我实际上建议将它移到解析器阶段(使用解析器规则classname 和objectname)。为此,您只需确保词法分析器不会尝试将两者分开。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多