2015-03-15 4 views
1

У меня есть грамматика antlr4, предназначенная для определенного для домена языка, встроенного в текстовый шаблон.Разрешить пробельные разделы ANTLR4

Есть два режима:

  • Текст (пробелы должны быть сохранены)
  • Код (пробелы должны быть проигнорированы)

Пример грамматики часть:

template 
    : '{' templateBody '}' 
    ; 

templateBody 
    : templateChunk* 
    ; 

templateChunk 
    : code # codeChunk // dsl code, ignore whitespace 
    | text # textChunk // any text, preserve whitespace 
    ; 

правило для code может содержать вложенную ссылку на template правило. Поэтому анализатор должен поддерживать вложенные пробелы/не-пробельные разделы.

Может режимы лексера может помочь - с некоторыми недостатками:

  • участки кода должны быть разобраны в другой проход компилятора
  • Я сомневаюсь, что вложенные разделы могут быть отображены правильно

Тем не менее наиболее перспективным подходом является обработка скрытых каналов.

Мой вопрос: Есть ли наилучшая практика для заполнения этих требований? Есть ли пример грамматики, который уже решил подобные проблемы?

Приложение:

Остальная часть грамматики может выглядеть следующим образом:

code 
    : '@' function 
    ; 

function 
    : Identifier '(' argument ')' 
    ; 

argument 
    : function 
    | template 
    ; 

text 
    : Whitespace+ 
    | Identifier 
    | .+ 
    ; 

Identifier 
    : LETTER (LETTER|DIGIT)* 
    ; 

Whitespace 
    : [ \t\n\r] -> channel(HIDDEN) 
    ; 

fragment LETTER 
    : [a-zA-Z] 
    ; 

fragment DIGIT 
    : [0-9] 
    ; 

В этом примере code имеет фиктивную реализацию, указывая на то, что он может содержать вложенные секции кода/шаблон. На самом деле code должен поддерживать

  • несколько аргументов
  • примитивные аргументы типа (Ints, строки ...)
  • карты и списки
  • оценка функции
  • ...
+0

Вы можете нажать/pop lexer, так что с ними все в порядке. Но вам придется публиковать правила 'code' и' text', чтобы мы могли увидеть, действительно ли вам нужен второй проход или нет. –

+0

Это, вероятно, отлично работает, если разделители «текста» нечувствительны к контексту (т. Е. Если любое обнаружение этих разделителей открывает/закрывает раздел «текст»). Мне становится сложно, если это зависит от состояния парсера, если разделители ограничивают «текст» или другую структуру языка. – CoronA

ответ

5

Вот как я решил проблему в конце:

Идея заключается в том, чтобы включить/отключить пробела в правилах синтаксического анализатора:

templateBody : {enableWs();} templateChunk* {disableWs();}; 

Таким образом, мы должны определить enableWs и disableWs в нашем парсере базового класса:

public void enableWs() { 
    if (_input instanceof MultiChannelTokenStream) { 
     ((MultiChannelTokenStream) _input).enable(HIDDEN); 
    } 
} 

public void disableWs() { 
    if (_input instanceof MultiChannelTokenStream) { 
     ((MultiChannelTokenStream) _input).disable(HIDDEN); 
    } 
} 

Теперь то, что это MultiChannelTokenStream?

  • Antlr4 определяет CommonTokenStream который представляет собой маркер потока чтение только из один канал.
  • MultiChannelTokenStream - токен, отображаемый с каналов с включенными каналами. Для реализации я взял исходный код CommonTokenStream и заменить каждую ссылку на channel по channels (сравнение равенства становится содержит сравнение)

Пример реализации с грамматикой выше, можно найти на antlr4multichannel

+0

Хорошее решение. [Вот другой подход] (http://stackoverflow.com/a/26533266/3764814), если вам всегда нужен полный текст, но ваше решение позволяет использовать больше сценариев (например, вы можете включить пробелы, но отключить комментарии). –

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