ANTLR4: невозможно сопоставить INT и BOOLEAN - PullRequest
0 голосов
/ 13 апреля 2019

Я написал следующую грамматику для вычисления комбинации логических и реляционных операторов в Java.

В грамматике я могу использовать оператор равенства (=) только для типов STRING , а не для типов INT и BOOLEAN . Может кто-нибудь, пожалуйста, помогите мне определить, что не так?

Я могу ("a" == "b") и не могу ("a" == 567). Левый операнд является переменной, и я подставлю значения во время выполнения.

grammar testGrammar;

/*
 * Parser rules
 */

conditionalExpression: leftOperand=conditionalExpression operator=LOGICAL_OPERATORS rightOperand=conditionalExpression #LogicalOperators
| '(' conditionalExpression ')' #ParenthesisExpression
| leftOperand=STRING operator=BOOLEAN_RELATIONAL_OPERATORS rightOperand=BOOLEAN #RelationalBooleanOperators
| leftOperand=STRING operator=STRING_RELATIONAL_OPERATORS rightOperand=STRING #RelationalStringOperators
| leftOperand=STRING operator=INT_RELATIONAL_OPERATORS rightOperand=INT #RelationalIntOperators
;

/*
 * Lexer rules
 */
STRING: '"'CHAR(CHAR)*'"';
INT:DIGIT+;
BOOLEAN: BOOLEAN_TRUE | BOOLEAN_FALSE;
LOGICAL_OPERATORS: LOGICAL_OR | LOGICAL_AND | LOGICAL_NOT;

STRING_RELATIONAL_OPERATORS: RELATIONAL_EQUALS | RELATIONAL_NOT_EQUAL;

INT_RELATIONAL_OPERATORS: RELATIONAL_EQUALS | RELATIONAL_NOT_EQUAL | RELATIONAL_GREATER_THEN
| RELATIONAL_GREATER_THEN_OR_EQUAL | RELATIONAL_LESS_THEN | RELATIONAL_LESS_THEN_OR_EQUAL;

BOOLEAN_RELATIONAL_OPERATORS: RELATIONAL_EQUALS | RELATIONAL_NOT_EQUAL;

fragment RELATIONAL_EQUALS: '==';
fragment RELATIONAL_NOT_EQUAL: '!=';
fragment RELATIONAL_GREATER_THEN: '>';
fragment RELATIONAL_LESS_THEN: '<';
fragment RELATIONAL_GREATER_THEN_OR_EQUAL: '>=';
fragment RELATIONAL_LESS_THEN_OR_EQUAL: '<=';

fragment LOGICAL_AND: '&&';
fragment LOGICAL_OR: '||';
fragment LOGICAL_NOT: '!';

fragment CHAR: [a-zA-Z_];
fragment DIGIT: [0-9];

fragment BOOLEAN_TRUE: 'true';
fragment BOOLEAN_FALSE: 'false';



1 Ответ

0 голосов
/ 13 апреля 2019

У вас есть несколько правил лексера, которые будут соответствовать вводу == или !=. ANTLR (как и большинство генераторов лексеров) разрешает неоднозначности в правилах лексеров, сначала выбирая те из них, которые дают самое длинное совпадение (в этом случае все правила приводят к совпадению длины 2), а затем разрешая связи, выбирая единицу это идет первым в грамматике. Поэтому, когда лексер видит == или !=, он всегда генерирует токен типа STRING_RELATIONAL_OPERATORS.

Обратите внимание, что лексеру не важно, какие токены парсер хочет сейчас - лексер функционирует независимо от парсера. Он только смотрит на текущий ввод и определенные правила лексера, чтобы решить, какой тип токена создать. Таким образом, одна и та же последовательность символов всегда будет создавать один и тот же вид токена.

Чтобы исправить свою грамматику, вы должны определить свои правила лексера, чтобы они не перекрывались, а затем сгруппировать их, как вам нравится в правилах синтаксического анализатора. Таким образом, вы можете иметь одно правило лексера на оператор (возможно, неявно, используя строковые литералы в правилах синтаксического анализатора), а затем просто использовать ('==' | '!=' | ...) в синтаксическом анализаторе.

Я бы также рекомендовал иметь только одно правило синтаксического анализа для реляционных выражений. Прямо сейчас у вас есть по одному для каждого типа, чтобы запретить сравнение выражений разных типов, но этот подход не масштабируется (что вы будете делать, когда вводите переменные, например?). Вместо этого вам следует просто разрешить некорректно выраженное выражение в анализаторе, а затем отклонить его в средстве проверки типов, которое вы пишете отдельно.

PS: для того, чтобы найти эти типы проблем в лексере, это помогает напечатать поток токенов, который был сгенерирован для данного ввода. Вы можете достичь этого, перебирая поток токенов в своем Java-коде или запуская grun YourGrammarName tokens -tokens yourInputFile в командной строке.

...