我正在为学校开展一个项目,将一个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是原因。如果你有任何想法,我非常感激。谢谢,对不起我发布的代码格式有多糟糕。
答案 0 :(得分:1)
我的词法分析规则出现在我的语法分析器规则之前是否重要...
不,那没关系。
问题是在你的atom
规则中,ANTLR无法在这三种变体之间做出选择:
ID ( ...
ID [ ...
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
规则中的六个不同“分支”从A
标记为F
:
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不知道解析器应该如何处理它。它可以用两种不同的方式解析:
D
后跟分支A
C
ANTLR抱怨的含糊不清的原因是什么。如果您要对其中一个分支A
,C
或D
进行注释,则错误将会消失。
希望有所帮助。