我正在使用Antlr4基于grammar为VBA语言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);
它标识规则中允许的特定子表达式。还有其他地方也会发生这种情况,我只选择这一个作为例子。
像这样写callStatement
:
callStatement
: Call? lExpression;
然后找到一种方法来禁用lExpression
中callStatement
或Me
中的dictionaryAccessExpression
。
像这样写callStatement
:
callStatement
: Call? (simpleNameExpression | lExpression '.' unrestrictedName | lExpression '(' argumentList ')' | withExpression);
但我不确定Antlr是否会喜欢这样。
我或许可以使用语义谓词和/或重写来改善这一点,但我在这方面非常环保。
任何想法都会非常感激。
答案 0 :(得分:1)
你能不能保持indexExpression
,dictionaryAccessExpression
和callStatement
不变,以便lExpression
可以使用它们,最后在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)
;
内扩展这些规则:
lExpression
: simpleNameExpression #SimpleNameExpressionAlt
| Me #MeExpressionAlt
| lExpression '.' unrestrictedName #MemberAccessExpressionAlt
| lExpression '(' argumentList ')' #IndexExpressionAlt
| lExpression '!' unrestrictedName #DictionaryAccessExpressionAlt
| withExpression #WithExpressionAlt
;
[...]是否可以在lExpression中使用重写规则将memberAccessExpression等节点添加到解析树?
唉,v4不支持重写规则。但是,您可以使用rule labels,以便在您的听众或访问者中明确您的选择:
enterMemberAccessExpressionAlt
然后在监听器中,您将覆盖public class YourListener extends YourBaseListener {
@Override
public void enterMemberAccessExpressionAlt(YourParser.MemberAccessExpressionAltContext ctx) {
// ...
}
}
:
sharedInstance