Сложности интеграции грамматики ANTLR4 для выбора с удалениями - PullRequest
0 голосов
/ 01 ноября 2018

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

Базовая структура языка: [Источник] [Маска] [Команда] [Назначение] . Маска является необязательной, поэтому супер простой пример ввода может выглядеть следующим образом: Fixture 1 @ 50 , который обходит маску. Приспособление 1 является источником, @ является командой, а 50 является местом назначения, которое в этом случае является значением интенсивности.

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

Светильник с 1 по 50 - 25 - 30 - 35 + 40> 45 @ 50

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

Пользователь может так же легко набрать следующее:

1 Через 50 - 25 - 30 - 35 + 40> 45 @ 50

Поскольку sourceType (fixture) не предоставлен, его вывод.

Чтобы попытаться справиться с вышеуказанными ситуациями, я написал следующее:

grammar LiteMic;

/*
 * Parser Rules
 */

start       : expression;

expression  : source command destination 
            | source mask command destination
            | command destination
            | source command; 

destination : sourceType number 
            | sourceType number sourceType number 
            | number;

command     : COMMAND;

mask        : SOURCETYPE;

operator    : ADD                                       #Add
            | SUB                                       #Subtract
            ;

plus : ADD;
minus : SUB;

source          : singleSource (plus source)*
                | rangeSource (plus source)*
                ;

singleSource    : sourceType number             #SourceWithType
                | number                        #InferedSource
                ;

rangeSource     : sourceRange (removeSource)*
                ;

sourceRange   : singleSource '>' singleSource;

removeSource     : '-' source;

sourceType      : SOURCETYPE;

number : NUMBER;


compileUnit
    :   EOF
    ;

/*
 * Lexer Rules
 */

SOURCETYPE      : 'Cue'
                | 'Playback' 
                | 'List'
                | 'Intensity'
                | 'Position'
                | 'Colour'
                | 'Beam'
                | 'Effect'
                | 'Group'
                | 'Fixture'
                ;


COMMAND     : '@' 
            | 'Record' 
            | 'Update' 
            | 'Copy' 
            | 'Move' 
            | 'Delete' 
            | 'Highlight' 
            | 'Full'
            ;

ADD         : '+'               ;       
SUB         : '-'               ;
THRU        : '>'               ;

/* A number: can be an integer value, or a decimal value */
NUMBER     : [0-9]+ ;

/* We're going to ignore all white space characters */
WS : [ \t\r\n]+ -> skip
   ;

Запуск команды для grun gui приводит к следующему: enter image description here

У меня был некоторый успех, когда я смог переопределить Listener для AddRangeSource, поскольку я могу циклически проходить и добавлять правильные типы, но все это разваливается, когда я пытаюсь удалить диапазон.

1> 50 - 30> 35 @ 50

Это создает проблему, поскольку удаление диапазона соответствует «addRangeSource».

enter image description here

Я почти уверен, что упускаю что-то очевидное, и я пробираюсь через книгу, которую я купил на Амазоне, но мне все еще не ясно, как архивировать то, что я ищу, и я смотрю на это уже неделю.

Для большей ясности ниже приведено дерево для более сложного запроса, который кажется нормальным, если не считать выбора. enter image description here

У кого-нибудь есть какие-нибудь указатели / предложения о том, где я ошибаюсь?

Ура, Майк

1 Ответ

0 голосов
/ 11 ноября 2018

Вы можете решить проблему, немного реорганизовав грамматику:

  • Слияние rangeSource с sourceRange:

    rangeSource : singleSource '>' singleSource;
    

    Примечание: Это правило также соответствует вводу, например Beam 1 > Group 16, который может быть непреднамеренным, в этом случае вы можете использовать это:

    rangeSource : sourceType? number '>' number;
    
  • Переименуйте source в sourceList (и не забудьте изменить его в правиле expression):

    expression : sourceList command destination 
               | sourceList mask command destination
               | command destination
               | sourceList command; 
    
  • Добавить правило source, соответствующее singleSource или rangeSource:

    source : singleSource | rangeSource;
    
  • Положите + и - на одном уровне (как addSource и removeSource):

    addSource : plus source;
    removeSource : minus source;
    
  • Изменить sourceList, чтобы принять список addSource / removeSource:

    sourceList : source (addSource|removeSource)*;
    

Я попробовал это, и у него нет проблем с анализом даже более сложного запроса.

...