如何正确解析 VB Case 语句?
How to correctly parse a VB Case statement?
我正在尝试解析 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;
问题是 rangeClause
中的 expression
优先,因此:
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 次测试。
然后我想,"hey that's potentially ambiguous!"然后把它变成这样:
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。
如果需要额外的上下文,the complete VBAParser.g4 grammar is on github。
事实证明 re-ordering 确实有效,但为了避免解析中的歧义,IS whiteSpace comparisonOperator
必须排在第一位:
rangeClause :
(IS whiteSpace?)? comparisonOperator whiteSpace? expression
| selectStartValue whiteSpace TO whiteSpace selectEndValue
| expression
问题在于 expression
(以及扩展 selectStartValue
和 selectEndValue
),它将递归匹配 Is =
,因为 comparisonOperator comparisonOperator
是表达式匹配。可能有一些工作可以完成 prevent comparisonOperator comparisonOperator
匹配 expression
(它在 VBA AFAIK 中永远无效),但上面的工作是快速而肮脏的修复。
基本上上面所有语法所做的就是确保 "invalid" comparisonOperator comparisonOperator
匹配为 rangeClause
before 它可以匹配为expression
.
我正在尝试解析 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;
问题是 rangeClause
中的 expression
优先,因此:
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 次测试。
然后我想,"hey that's potentially ambiguous!"然后把它变成这样:
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。
如果需要额外的上下文,the complete VBAParser.g4 grammar is on github。
事实证明 re-ordering 确实有效,但为了避免解析中的歧义,IS whiteSpace comparisonOperator
必须排在第一位:
rangeClause :
(IS whiteSpace?)? comparisonOperator whiteSpace? expression
| selectStartValue whiteSpace TO whiteSpace selectEndValue
| expression
问题在于 expression
(以及扩展 selectStartValue
和 selectEndValue
),它将递归匹配 Is =
,因为 comparisonOperator comparisonOperator
是表达式匹配。可能有一些工作可以完成 prevent comparisonOperator comparisonOperator
匹配 expression
(它在 VBA AFAIK 中永远无效),但上面的工作是快速而肮脏的修复。
基本上上面所有语法所做的就是确保 "invalid" comparisonOperator comparisonOperator
匹配为 rangeClause
before 它可以匹配为expression
.