为什么会发生此错误? -“以下选项永远无法匹配”

| 我对制作编译器,解析器和解析器生成器很感兴趣,但是我对它们并不了解。 阅读了这个问题的答案后,我尝试制作一个“非常”简单的LaTeX解析器。 这是代码:
grammar Latex;

latex   :   ITEM*;
ITEM    :   CMD|LAWTEXT;
CMD :   CHEAD ARGS;
CHEAD   :   \'\\\\\' LETTER(LETTER|DIGIT)*;
LETTER  :   \'A\'..\'Z\'|\'a\'..\'z\';
DIGIT   :   \'0\'|\'1\'|\'2\'|\'3\'|\'4\'|\'5\'|\'6\'|\'7\'|\'8\'|\'9\';
ARGS    :   \'{\' ITEM* \'}\';
LAWTEXT :   (LETTER|DIGIT|WHITESPACE|PUNC)*;
WHITESPACE
    :   \' \'|\'\\t\'|\'\\n\'|\'\\r\';
PUNC    :   \'!\'|\'^\';
(出于测试目的,PUNC中只有两个字符) 这是错误消息:
[18:39:09] warning(200): C:\\Users\\***\\Documents\\Latex.g:9:12: Decision can match input such as \"{\'\\t\'..\'\\n\', \'\\r\', \' \'..\'!\', \'0\'..\'9\', \'A\'..\'Z\', \'\\\\\', \'^\', \'a\'..\'z\', \'}\'}\" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
[18:39:09] error(201): C:\\Users\\***\\Documents\\Latex.g:9:12: The following alternatives can never be matched: 2

[18:39:09] error(211): C:\\Users\\***\\Documents\\Latex.g:1:8: [fatal] rule Tokens has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
我发现发生此错误是因为存在歧义,可以用两种以上的方式解释代码,但是我不知道这种歧义是如何产生的。 这是图表,可以用两种方式解释(也许)。 ...但是how2ѭ和
}
如何混淆?     
已邀请:
  JiminP写道:      我对制作编译器,解析器和解析器生成器很感兴趣,但是我对它们并不了解。 ANTLR根据您编写的语法为您创建一个词法分析器。 ANTLR本身就是解析器生成器,因此您不必编写解析器生成器本身(幸运的是!)。编译器是一种应用程序,它使用解析器生成的树并将输入转换为其他形式:这是您需要自己做的事情。因此,需要强调的是:ANTLR仅可以帮助您为您的语言创建解析器,其余的取决于您。 现在,问题。 您的语法几乎只包含词法分析器规则。 Lexer规则以大写字母开头,用于标记输入源。因此,规则如下:
LETTER  :   \'A\'..\'Z\'|\'a\'..\'z\';
...
LAWTEXT :   (LETTER|DIGIT|WHITESPACE|PUNC)*;
可能会使词法分析器自己创建一个
LETTER
令牌。如果您始终希望将小写或大写的ascii字母变成
LAWTEXT
令牌,那么您需要将
LETTER
设为如下片段规则:
fragment LETTER  :   \'A\'..\'Z\'|\'a\'..\'z\';
...
LAWTEXT :   (LETTER|DIGIT|WHITESPACE|PUNC)+;
如您所见,我以ѭ10而不是ѭ11结束了
LAWTEXT
规则:您不想创建不包含任何内容的令牌(空字符串)。 同样,
args
item
cmd
也不适合词法分析器规则:它们应该是解析器规则。 这是一个生成词法分析器和语法分析器的语法,没有任何错误:
grammar Latex;

latex
  :  item* EOF
  ;

item 
  :  cmd
  |  LAWTEXT
  ;

cmd
  :  CHEAD args
  ;

args
  :  \'{\' item* \'}\'
  ;

CHEAD 
  :  \'\\\\\' LETTER (LETTER | DIGIT)*
  ;  

LAWTEXT
  :  (LETTER | DIGIT | WHITESPACE | PUNC)+
  ;

fragment  
WHITESPACE 
  :  \' \' | \'\\t\' | \'\\n\' | \'\\r\'
  ;

fragment  
PUNC       
  : \'!\' | \'^\'
  ;

fragment
LETTER
  :  \'A\'..\'Z\' | \'a\'..\'z\'
  ;

fragment
DIGIT
  :  \'0\'..\'9\'
  ;
编辑 正如我已经提到的:lexer规则以大写字母开头,而解析器规则以小写字母开头。词法分析器(有时称为令牌生成器或扫描器)负责切分输入源。输入源的开始只是字符流。然后,这些字符由词法分析器分组在一起。因此,考虑到以下词法分析器规则:
Identifier
  :  (Letter | \'_\') (Letter | \'_\' | Digit)*
  ;

Assign
  :  \'=\'
  ;

Number
  :  Digit+ (\'.\' Digit+)?
  ;

fragment Digit
  :  \'0\'..\'9\'
  ;

fragment Letter
  :  \'a\'..\'z\' | \'A\'..\'Z\'
  ;

Spaces
  :  (\' \' | \'\\t\' | \'\\r\' | \'\\n\') {skip();}
  ;
可以采用以下输入源:
foo = 12.34
该词法学家将其视为:
\'f\', \'o\', \'o\', \' \', \'=\', \' \', \'1\', \'2\', \'.\', \'3\', \'4\', EOF
并将创建以下令牌:
Identifier \"foo\"
Assign \"=\"
Number \"12.34\"
(请注意,没有从空白中创建标记:我跳过了这些!) 在词法分析器从您的输入源创建了令牌之后,解析器将传递这些令牌。分配解析器规则如下所示:
assignment
  :  Identifier Assign Number
  ;
重要的是要记住,输入源首先由词法分析器标记,并且只有在该过程之后,解析器规则才起作用。     

要回复问题请先登录注册