2017-01-11 2 views
4

Я пытаюсь разобрать VBA код, и 5.4.2.10 раздел спецификации определяет Select Case заявление, которое мы определили следующим образом:Как правильно разобрать оператор VB 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 без = фактически является незаконным кодом 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 в ближайшее время.

Если необходим дополнительный контекст, the complete VBAParser.g4 grammar is on github.

ответ

1

Оказывается, что изменение порядка фактически делает работу, но для того, чтобы сохранить неоднозначность из синтаксического анализа, то IS whiteSpace comparisonOperator должен прийти первым:

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

Проблема с expression (и расширением selectStartValue и selectEndValue), который будет рекурсивно соответствовать Is =, потому что comparisonOperator comparisonOperator соответствует выражению. Есть, вероятно, некоторые работы, которые можно сделать с , предотвращатьcomparisonOperator comparisonOperator от соответствия expression (это никогда не действует в VBA AFAIK), но вышеописанное работает как быстрое и грязное исправление.

В основном все выше грамматика делает это убедиться, что «недействительные» comparisonOperator comparisonOperator матчи как rangeClauseперед он может быть подобран как expression.

Смежные вопросы