解决相互左递归文法

Resolve mutual left recursive grammar

问题

我正在使用 Antlr4 开发 grammar for the VBA language based on the Microsoft specification。我试图严格遵守语法规范,但由于这一原因,有一个相互左递归错误需要解决。这是显示问题的完整语法的一个子集:

lExpression
    :   simpleNameExpression
    |   Me //instanceExpression 5.6.11
    |   memberAccessExpression
    |   indexExpression
    |   dictionaryAccessExpression
    |   withExpression
    ;

memberAccessExpression      :   lExpression '.' unrestrictedName;

indexExpression             :   lExpression '(' argumentList ')';

dictionaryAccessExpression  :   lExpression '!' unrestrictedName;

我可以将子表达式移动到主 lExpression 规则中以克服最初的问题,但我会在其他规则中引起问题,例如:

callStatement               
    :   Call? (simpleNameExpression | memberAccessExpression | indexExpression | withExpression);

它标识规则中允许的特定子表达式。还有其他地方也会出现这种情况,我就举这家为例。

想法 1

这样写callStatement

callStatement               
    :   Call? lExpression;

然后找到一种方法来禁用 callStatement 中的 lExpression 成为 MedictionaryAccessExpression

想法 2

这样写callStatement

callStatement               
    :   Call? (simpleNameExpression | lExpression '.' unrestrictedName | lExpression '(' argumentList ')' | withExpression);

但我不确定 Antlr 是否会喜欢它。

想法

我也许可以使用语义谓词 and/or 重写来改进这一点,但我在这方面还很新手。

如有任何想法,我们将不胜感激。

你能不能不让memberAccessExpressionindexExpressiondictionaryAccessExpression保持原样,这样callStatement就可以使用它们,结束在[=17里面扩展这些规则=]:

lExpression
    :   simpleNameExpression
    |   Me //instanceExpression 5.6.11
    |   lExpression '.' unrestrictedName
    |   lExpression '(' argumentList ')'
    |   lExpression '!' unrestrictedName
    |   withExpression
    ;

memberAccessExpression      :   lExpression '.' unrestrictedName;

indexExpression             :   lExpression '(' argumentList ')';

dictionaryAccessExpression  :   lExpression '!' unrestrictedName;

callStatement
    :   Call? (simpleNameExpression | memberAccessExpression | indexExpression | withExpression)
    ;

[...] Is it possible to use a rewrite rule in lExpression to add the memberAccessExpression etc nodes to the parse tree?

唉,v4 不支持重写规则。但是,您可以使用 rule labels 以便在您的听众或访问者内部很清楚您是哪种选择:

lExpression
    :   simpleNameExpression               #SimpleNameExpressionAlt
    |   Me                                 #MeExpressionAlt
    |   lExpression '.' unrestrictedName   #MemberAccessExpressionAlt
    |   lExpression '(' argumentList ')'   #IndexExpressionAlt
    |   lExpression '!' unrestrictedName   #DictionaryAccessExpressionAlt
    |   withExpression                     #WithExpressionAlt
    ;

然后在侦听器中覆盖 enterMemberAccessExpressionAlt:

public class YourListener extends YourBaseListener {

  @Override
  public void enterMemberAccessExpressionAlt(YourParser.MemberAccessExpressionAltContext ctx) {
    // ...
  }
}