如何消除这种左递归

时间:2017-11-05 14:54:09

标签: compiler-construction javacc left-recursion

我在编译器构造中做了一个赋值,我在左递归方面遇到了麻烦。 JavaCC给出了一个错误“检测到左递归”的表达式()和condition(),如下所示。每个的第二行是相同的,所以我认为这是问题。

  

A→Aα|β

     

A→βA'

     

A'→ε|αA'

这是用于显示如何消除左递归的公式。我已经在讲座和在线视频和解释中理解了这个概念,但我无法弄清楚如何在这里应用它。有人能告诉我如何消除左递归吗?

void expression() :
{ }
{
  fragment() binary_arith_op() fragment()
| <OPAREN> expression() <CPAREN>
| <ID> <OPAREN> arg_list() <CPAREN>
| fragment()
}

void fragment() :
{ }
{ (<MINUS_SIGN>)? <ID> | <NUM> | <TRUE> | <FALSE> | expression() }

void condition() :
{ }
{ <TILDE> condition()
| <OPAREN> condition() <CPAREN>
| expression() comp_op() expression()
| condition() (<OR> | <AND>) condition()
}

1 个答案:

答案 0 :(得分:2)

类似的例子可以在任何关于编译的书中找到。您还可以查看我的教程Parsing Expressions by Recursive Descent。或者任何其他免费教程。

这是一个解决方案。首先,我要重写表达式有点像这样

void expression() :
{ }
{
  expression() binary_arith_op() expression()
| 
  simpleExpression() :
}

void simpleExpression() :
{ }
{ (<MINUS_SIGN>)? <ID> | <NUM> | <TRUE> | <FALSE> 
| <OPAREN> expression() <CPAREN>
| <ID> <OPAREN> arg_list() <CPAREN> }

现在很清楚alpha和beta是什么。所以我们得到

void expression() :
{ }
{
  simpleExpression() expressionPrime()
}


void expressionPrime() :
{ }
{
  binary_arith_op() expression() 
|
  {}
}

但是在JavaCC中,我们不妨使用一个循环(即Kleene星)。

void expression() :
{ }
{
  simpleExpression() (binary_arith_op() simpleExpression())*
}

void simpleExpression() :
{ }
{ (<MINUS_SIGN>)? <ID> | <NUM> | <TRUE> | <FALSE> 
| <OPAREN> expression() <CPAREN>
| <ID> <OPAREN> arg_list() <CPAREN> }

同样适用于条件

void condition() :
{ }
{ 
    simpleCondition() ((<OR> | <AND>) simpleCondition())*
}

void simpleCondition() :
{ }
{
  <TILDE> condition()
| <OPAREN> condition() <CPAREN>
| expression() comp_op() expression()
}

这消除了左递归。

它仍然会给你留下一些选择冲突。这些可以使用语法先行来消除。您还需要处理运算符优先级,但这很简单。请参阅我的教程中的“经典”解决方案。