Не удается создать переменную только с одной буквой

#antlr #antlr4

#антлр #antlr4

Вопрос:

Я бы хотел, чтобы переменные могли быть объявлены только с одной буквой в имени. Когда я пишу целое число aa; все работает, но когда я набираю целое число a;, тогда grun говорит: несоответствующий ввод ‘a’ ожидающий идентификатор. Я видел обратную задачу, но это не помогло. Я думаю, что мой код правильный, но я не вижу, где я ошибаюсь. Это мой лексер:

 lexer grammar Symbols;

...

LineComment: '//' ~[u000Au000D]* -> channel(HIDDEN) ;
DelimetedComment: '/*' .*? '*/' -> channel(HIDDEN) ;

String: '"' .*? '"' ;
Character: ''' (EscapeSeq | .) ''' ;
IntegerLiteral: '0' | (ADD?| SUB) DecDigitNoZero DecDigit  ;
FloatLiteral: ((ADD? | SUB) (DecDigitNoZero DecDigit*)? DOT DecDigit  | IntegerLiteral) [F] ;
DoubleLiteral: ((ADD? | SUB) (DecDigitNoZero DecDigit*)? DOT DecDigit  | IntegerLiteral) [D]  ;
LongLiteral: IntegerLiteral [L] ;
HexLiteral: '0' [xX] HexDigit (HexDigit | UNDERSCORE)* ;
BinLiteral: '0' [bB] BinDigit (BinDigit | UNDERSCORE)* ;
OctLiteral: '0' [cC] OctDigit (OctDigit | UNDERSCORE)* ;
Booleans: TRUE | FALSE ;
Number: IntegerLiteral | FloatLiteral | DoubleLiteral | BinLiteral | HexLiteral | OctLiteral | LongLiteral ;
EscapeSeq: UniCharacterLiteral | EscapedIdentifier;
UniCharacterLiteral: '\' 'u' HexDigit HexDigit HexDigit HexDigit ;
EscapedIdentifier: '\' ('t' | 'b' | 'r' | 'n' | ''' | '"' | '\' | '


Комментарии:

1. Это невозможно воспроизвести с помощью грамматики, которую вы опубликовали. Пожалуйста, опубликуйте всю свою грамматику.

2. @BartKiers Готово

3. спасибо, это было то, что я подозревал: правило, определенное до того, как ваше ID правило было сопоставлено, как уже объяснялось в sepp2k.

Ответ №1:

Когда вы получаете сообщение об ошибке типа "Неожиданный ввод 'foo', ожидаемый БАР", и вы думаете "Но 'foo' - это БАР", первое, что вам следует сделать, это распечатать поток токенов для вашего ввода (вы можете сделать это, запустив grun Symbols tokens -tokens inputfile ). Если вы сделаете это, вы увидите, что a в вашем вводе распознается как a HexDigit , а не как an ID .

Почему это происходит? Поскольку оба HexDigit и ID соответствуют вводу, a а ANTLR (как и большинство генераторов лексер) разрешает неоднозначности в соответствии с правилом максимального Мунка: когда несколько правил могут соответствовать текущему вводу, он выбирает то, которое дает наибольшее совпадение (именно поэтому работают переменные с более чем одной буквой), а затем разрешает связи, выбираятот, который определяется первым, что HexDigit в данном случае.

Обратите внимание, что лексеру все равно, какие правила лексера используются синтаксическим анализатором и когда. Лексер решает, какие токены создавать, исключительно на основе содержимого грамматики лексера, поэтому лексер не знает и не заботится о том, что синтаксический анализатор хочет ID получить прямо сейчас. Он просматривает все совпадающие правила, а затем выбирает одно в соответствии с максимальным правилом Мунка, и все.

В вашем случае вы на самом деле никогда не используете HexDigit грамматику в своем синтаксическом анализаторе, поэтому нет никаких причин, по которым вы когда-либо хотели HexDigit бы создать токен. Поэтому HexDigit не должно быть правилом лексера - оно должно быть fragment :

 fragment HexDigit : [0-9a-fA-F];
 

Это также относится к другим вашим правилам, которые не используются в анализаторе, включая все ...Digit правила.

PS: Ваше Number правило никогда не будет соответствовать из-за этих же правил. Вероятно, вместо этого это должно быть правило синтаксического анализатора (или другие числовые правила должны быть фрагментами, если вам все равно, какой у вас числовой литерал).

Комментарии:

1. Отличный ответ, как обычно. Я взял на себя смелость внести небольшую правку.

) ;
HexDigit: [0-9a-fA-F] ;
BinDigit: [01] ;
OctDigit: [0-7];
DecDigit: [0-9];
DecDigitNoZero: [1-9];

ID: [a-z] ([a-zA-Z_] | [0-9])*;
TYPE: [A-Z] ([a-zA-Z] | UNDERSCORE | [0-9])* ;

DATATYPE: Number | String | Character | Booleans ;

Комментарии:

1. Это невозможно воспроизвести с помощью грамматики, которую вы опубликовали. Пожалуйста, опубликуйте всю свою грамматику.

2. @BartKiers Готово

3. спасибо, это было то, что я подозревал: правило, определенное до того, как ваше ID правило было сопоставлено, как уже объяснялось в sepp2k.

Ответ №1:

Когда вы получаете сообщение об ошибке типа «Неожиданный ввод ‘foo’, ожидаемый БАР», и вы думаете «Но ‘foo’ — это БАР», первое, что вам следует сделать, это распечатать поток токенов для вашего ввода (вы можете сделать это, запустив grun Symbols tokens -tokens inputfile ). Если вы сделаете это, вы увидите, что a в вашем вводе распознается как a HexDigit , а не как an ID .

Почему это происходит? Поскольку оба HexDigit и ID соответствуют вводу, a а ANTLR (как и большинство генераторов лексер) разрешает неоднозначности в соответствии с правилом максимального Мунка: когда несколько правил могут соответствовать текущему вводу, он выбирает то, которое дает наибольшее совпадение (именно поэтому работают переменные с более чем одной буквой), а затем разрешает связи, выбираятот, который определяется первым, что HexDigit в данном случае.

Обратите внимание, что лексеру все равно, какие правила лексера используются синтаксическим анализатором и когда. Лексер решает, какие токены создавать, исключительно на основе содержимого грамматики лексера, поэтому лексер не знает и не заботится о том, что синтаксический анализатор хочет ID получить прямо сейчас. Он просматривает все совпадающие правила, а затем выбирает одно в соответствии с максимальным правилом Мунка, и все.

В вашем случае вы на самом деле никогда не используете HexDigit грамматику в своем синтаксическом анализаторе, поэтому нет никаких причин, по которым вы когда-либо хотели HexDigit бы создать токен. Поэтому HexDigit не должно быть правилом лексера — оно должно быть fragment :


Это также относится к другим вашим правилам, которые не используются в анализаторе, включая все ...Digit правила.

PS: Ваше Number правило никогда не будет соответствовать из-за этих же правил. Вероятно, вместо этого это должно быть правило синтаксического анализатора (или другие числовые правила должны быть фрагментами, если вам все равно, какой у вас числовой литерал).

Комментарии:

1. Отличный ответ, как обычно. Я взял на себя смелость внести небольшую правку.