我正在尝试解析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
in 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
没有=
实际上是非法的VBA代码):
rangeClause : expression (whiteSpace TO whiteSpace expression)? #caseFromTo | (IS whiteSpace comparisonOperator whiteSpace)? expression #caseIs ;
然后在代码中使用CaseFromToContext
和CaseIsContext
编写类(必须,以保持编译),但它又在我的项目中破坏了~1000次测试.
然后我想,"嘿,这可能是模棱两可的!" 把它变成了这个:
rangeClause : expression whiteSpace TO whiteSpace expression #caseFromTo | IS whiteSpace comparisonOperator whiteSpace expression #caseIs | expression #caseExpr ;
......但没有运气,同样的结果.
如何rangeClause
理解这种烦人的Case Is = foobar
语法?我正在使用ANTLR 4.3,但我们计划很快升级到ANTLR 4.6.
如果需要其他上下文,则完整的VBAParser.g4语法在github上.