#antlr #antlr4
#antlr #antlr4
Вопрос:
Похоже, у меня проблема с пониманием слишком жадного соответствия правил. Я пытаюсь .g4
использовать лексический файл для раскраски синтаксиса. Вот минимальная (упрощенная) выдержка для того, чтобы сделать эту проблему воспроизводимой:
lexer grammar ANTLRv4Lexer;
Range
: '[' RangeChar ']'
;
fragment EscapedChar
: '\' ~[u]
| '\u' EscapedCharHex EscapedCharHex EscapedCharHex EscapedCharHex
;
fragment EscapedCharHex
: [0-9A-Fa-f]
;
fragment RangeChar
: ~']'
| EscapedChar
;
Punctuation
: [:;() ->*[]~|]
;
Identifier
: [a-zA-Z0-9]
;
Whitespace
: [ t]
-> skip
;
Newline
: ( 'r' 'n'?
| 'n'
)
-> skip
;
LineComment
: '//' ~[rn]*
;
(Неполный) тестовый файл выглядит следующим образом:
: (~ []\] | EscAny) -> more
;
// ------
fragment Id
: NameStartChar NameChar*
;
String2Part
: ( ~['\]
| EscapeSequence
)
;
Я не понимаю, почему оно соответствует Range
такому жадному:
[@0,3:3=':',<Punctuation>,1:3]
[@1,5:5='(',<Punctuation>,1:5]
[@2,6:6='~',<Punctuation>,1:6]
[@3,8:135='[]\] | EscAny) -> morern ;rnrn // ------rnrnfragment Idrn : NameStartChar NameChar*rn ;rnrnrnString2Partrnt: ( ~['\]',<Range>,1:8]
[@4,141:141='|',<Punctuation>,13:3]
[@5,143:156='EscapeSequence',<Identifier>,13:5]
[@6,162:162=')',<Punctuation>,14:3]
[@7,163:163=' ',<Punctuation>,14:4]
[@8,167:167=';',<Punctuation>,15:1]
[@9,170:169='<EOF>',<EOF>,16:0]
Я понимаю, почему в первой строке оно совпадает [
, ]
и \
, но почему оно, очевидно, трактуется ]
как RangeChar
?
Ответ №1:
Ваш лексер соответствует первому
при \]
использовании ~']'
альтернативы, а затем соответствует оставшемуся ]
как EscapedChar
. Причина, по которой это происходит, заключается в том, что эта интерпретация приводит к более длинному совпадению, чем то, где \
EscapedChar
и ]
является концом диапазона, и когда существует несколько допустимых способов сопоставления правила лексера, ANTLR всегда выбирает самый длинный (за исключением случаев, когда *?
это задействовано).
Чтобы исправить это, вы должны изменить RangeChar
, чтобы обратная косая черта разрешалась только как часть escape-последовательностей, т. Е. Заменить ~']'
на ~[]\]
.
Комментарии:
1. Большое вам спасибо. Я предположил, что он пропустит
~']'
в случае обратной косой черты, потомуEscapedChar
что совпадение будет длиннее.2. @ThomasS. Да, но принцип максимального мунка применим к правилу лексера, а не к фрагментам. То есть он идет по пути, который дает максимально возможное совпадение для
Range
, неRangeChar
.