1

我正在为学校开发一个项目,将 BNF 形式的 Decaf 规范转换为上下文无关语法并在 ANTLR 中构建它。我已经为此工作了几个星期,当我陷入困境时,我一直在去找教授,但我终于遇到了他说不应该导致错误的东西。这是我语法的孤立部分, expr 是起点。在我这样做之前,我有一个问题。

如果我的词法分析器规则出现在我的语法中的解析器规则之前,或者它们是否通过我的语法文件间歇性地混合在一起,这是否重要?

calloutarg:         expr | STRING;
expr:  multexpr ((PLUS|MINUS) multexpr)* ;
multexpr : atom ((MULT|DIVISION) atom)*
;

atom : OPENPAR expr CLOSEPAR | ID ((OPENBRACKET expr CLOSEBRACKET)? | OPENPAR ((expr (COMMA)* )+)? CLOSEPAR)|
CALLOUT OPENPAR STRING (COMMA (calloutarg)+ COMMA)? CLOSEPAR | constant;
constant: INT | CHAR | boolconstant;
boolconstant: TRUE|FALSE;

丑陋的格式是因为他对调试的部分建议是采用单独的规则并将它们分解到模棱两可的地方,以查看错误的开始位置。在这种情况下,问题出在长 ID 部分,原因是 OPENBRACKET 和 OPENPAR。如果您有任何想法,我非常感激。谢谢,对于我发布的代码的格式有多糟糕,我深表歉意。

4

1 回答 1

1

如果我的词法分析器规则出现在我的语法中的解析器规则之前,这是否重要......

不,那没关系。

问题是在您的atom规则内,ANTLR 无法在这三个变体之间做出选择:

  1. ID ( ...
  2. ID [ ...
  3. ID

不诉诸(可能)回溯。您可以通过使用一些语法谓词(看起来像:)来解决它(...)=> ...。句法谓词只不过是“向前看”,如果“向前看”成功,它会选择那条特定的路径。

您当前的atom规则可以重写如下:

atom 
  :  OPENPAR expr CLOSEPAR
  |  ID OPENPAR ((expr (COMMA)* )+)? CLOSEPAR 
  |  ID OPENBRACKET expr CLOSEBRACKET
  |  ID
  |  CALLOUT OPENPAR STRING (COMMA (calloutarg)+ COMMA)? CLOSEPAR
  |  constant
  ;

使用谓词,它看起来像:

atom 
  :  OPENPAR expr CLOSEPAR
  |  (ID OPENPAR)=>     ID OPENPAR ((expr (COMMA)* )+)? CLOSEPAR 
  |  (ID OPENBRACKET)=> ID OPENBRACKET expr CLOSEBRACKET
  |  ID
  |  CALLOUT OPENPAR STRING (COMMA (calloutarg)+ COMMA)? CLOSEPAR
  |  constant
  ;

这应该可以解决问题。

注意:不要使用ANTLRWorks 生成或测试解析器!它不能处理谓词(很好)。最好在命令行上执行。

另见:https ://wincent.com/wiki/ANTLR_predicates


编辑

atom让我们将规则中的六个不同“分支”标记AF

atom                                                            // branch
  :  OPENPAR expr CLOSEPAR                                      //   A
  |  ID OPENBRACKET expr CLOSEBRACKET                           //   B
  |  ID OPENPAR ((expr COMMA*)+)? CLOSEPAR                      //   C
  |  ID                                                         //   D
  |  CALLOUT OPENPAR STRING (COMMA calloutarg+ COMMA)? CLOSEPAR //   E
  |  constant                                                   //   F
  ;

现在,当(未来的)解析器应该像这样处理输入时:

ID OPENPAR expr CLOSEPAR

ANTLR 不知道解析器应该如何处理它。它可以用两种不同的方式解析:

  1. 分支D后跟分支A
  2. 分支C

这是 ANTLR 抱怨的模棱两可的根源。如果您要注释掉其中一个分支AC或者D,错误就会消失。

希望有帮助。

于 2010-10-20T06:55:52.460 回答