如何正确解析VB Case语句?

时间:2017-01-11 17:16:02

标签: parsing antlr4

我试图解析VBA代码,规范的5.4.2.10部分定义了Select Case语句,我们已经定义如下:

// 5.4.2.10 Select Case Statement
selectCaseStmt :
    SELECT whiteSpace? CASE whiteSpace? selectExpression endOfStatement
    caseClause*
    caseElseClause?
    END_SELECT
;
selectExpression : expression;
caseClause :
    CASE whiteSpace rangeClause (whiteSpace? COMMA whiteSpace? rangeClause)* endOfStatement block
;
caseElseClause : CASE whiteSpace? ELSE endOfStatement block;
rangeClause :
    expression
    | selectStartValue whiteSpace TO whiteSpace selectEndValue   
    | (IS whiteSpace?)? comparisonOperator whiteSpace? expression
;
selectStartValue : expression;
selectEndValue : expression;

问题是expression中的rangeClause优先,并且这样做:

Select Case foo
    Case Is = 42
        Exit Sub
End Select

...最终被选中并被视为{undeclared-variable} {EQ} {literal},这是一个问题,因为Is应该是词法分析器,而不是比较表达式的LHS:

expression whiteSpace? (EQ | NEQ | LT | GT | LEQ | GEQ | LIKE | IS) whiteSpace? expression    # relationalOp

我尝试重新排序替代方案,以便expression分支的优先级更低,如下所示:

rangeClause :
    selectStartValue whiteSpace TO whiteSpace selectEndValue   
    | (IS whiteSpace?)? comparisonOperator whiteSpace? expression
    | expression
;

但是这会以各种方式打破整个语法(在我的项目中打破了~1000次测试),所以我尝试将rangeClause更改为此(删除了可选标记,因为Is没有{ {1}}实际上是非法的VBA代码):

=

然后在代码中使用rangeClause : expression (whiteSpace TO whiteSpace expression)? #caseFromTo | (IS whiteSpace comparisonOperator whiteSpace)? expression #caseIs ; CaseFromToContext类(必须,以保持编译),但在我的项目中它再次破坏了〜1000次测试。

然后我想,"嘿,这可能是模棱两可的!"把它变成了这个:

CaseIsContext

......但没有运气,同样的结果。

如何让rangeClause : expression whiteSpace TO whiteSpace expression #caseFromTo | IS whiteSpace comparisonOperator whiteSpace expression #caseIs | expression #caseExpr ; 理解这种烦人的rangeClause语法?我使用的是ANTLR 4.3,但我们计划很快升级到ANTLR 4.6。

如果需要其他上下文,the complete VBAParser.g4 grammar is on github

1 个答案:

答案 0 :(得分:1)

事实证明重新排序确实有效,但为了避免歧义,IS whiteSpace comparisonOperator必须先行:

rangeClause :
    (IS whiteSpace?)? comparisonOperator whiteSpace? expression
    | selectStartValue whiteSpace TO whiteSpace selectEndValue 
    | expression

问题在于expression(以及扩展名selectStartValueselectEndValue),它将递归地匹配Is =,因为comparisonOperator comparisonOperator是表达式匹配。可能有一些工作可以用来阻止 comparisonOperator comparisonOperator匹配expression(它在VBA AFAIK中永远不会有效),但上面的工作是一个快速而肮脏的修复。 / p>

基本上所有上述语法都确保“无效”comparisonOperator comparisonOperator在之前与rangeClause 匹配,它可以匹配为expression。< / p>