我有一个语法,我必须使用JJTree和JavaCC来创建符号表和AST。 虽然我完全理解我创建表和树的任务部分,但我给出的语法含糊不清,包含左递归和间接左回归。它也需要被考虑在内。 我已经在互联网上搜寻,试图寻找适合我的方法。
例如:
A :: =Aα| β
可以更改为:
A :: =βA'
A'= =αA' | ε
但我不知道如何将其应用于我的语法。
以下是我从语法中编写的生产规则的一部分,其中包含上述问题。
void statement() #STM : {}
{
identifier() <ASSIGNMENT> expression()
| identifier() <ASSIGNMENT> <STRING>
| <EXCLAMATION> expression()
| <QUESTION> identifier()
| identifier() <LBR> arg_list() <RBR>
| <BEGIN> (statement() <SEMIC>)+ <END>
| matched()
| unmatched()
| <WHILE> <LBR> condition() <RBR> <DO> statement()
| {}
}
void matched() #void : {}
{
<IF> condition() <THEN> matched() <ELSE> matched()
}
void unmatched() #void : {}
{
<IF> condition() <THEN> statement()
| <IF> condition() <THEN> matched() <ELSE> unmatched()
}
void expression() #EXPR : {}
{
fragment() ((<PLUS>|<MINUS>|<MULT>|<DIV>) fragment())*
}
void fragment() #FRAG : {}
{
(identifier() | <NUM> | (<PLUS>|<MINUS>) fragment() | expression())
}
答案 0 :(得分:3)
这里有很多问题。大多数都在JavaCC FAQ的问题4.6中处理。 http://www.engr.mun.ca/~theo/JavaCC-FAQ/
首先,要做的事情有很多。左分解试图将选择移到后面的解析中。例如。如果你有
void statement() #STM : {}
{
identifier() <ASSIGNMENT> expression()
| identifier() <ASSIGNMENT> <STRING>
| identifier() <LBR> arg_list() <RBR>
}
并且解析器期望一个语句,下一个输入项是一个标识符,然后解析器无法做出选择。将左侧的公共部分分解出来以获得
void statement() #STM : {}
{
identifier()
( <ASSIGNMENT> expression()
| <ASSIGNMENT> <STRING>
| <LBR> arg_list() <RBR>
)
}
然后
void statement() #STM : {}
{
identifier()
( <ASSIGNMENT> ( expression() | <STRING> )
| <LBR> arg_list() <RBR>
)
}
其次,非终结“匹配”是没用的,因为没有非递归的情况。我怀疑你正试图处理悬空的其他问题。这不是解决悬空问题的好方法。请参阅JavaCC FAQ以了解处理它的明智方法。
第三,非终结符“fragment”和“expression”之间存在相互左递归。我不确定你要在这里完成什么。有几种方法可以处理不使用左递归的解析表达式。有关详细信息,请参阅http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm。我对JavaCC的教程介绍也可能有所帮助。 http://www.engr.mun.ca/~theo/JavaCC-Tutorial/
最后一句忠告。从语言的一小部分语法开始,然后一次添加一个或两个构造。这样你就不必立即处理很多问题。