左保理&删除左递归JavaCC

时间:2013-11-29 13:36:50

标签: parsing compiler-construction javacc left-recursion

我有一个语法,我必须使用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())
}

1 个答案:

答案 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/

最后一句忠告。从语言的一小部分语法开始,然后一次添加一个或两个构造。这样你就不必立即处理很多问题。