#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. Отличный ответ, как обычно. Я взял на себя смелость внести небольшую правку.