Xtext/ANTLR: как исправить эту ошибку? Следующее определение токена никогда не может быть сопоставлено ранее?

Я сделал грамматику, и редактор не показывает никаких ошибок, когда я выбираю «Создать артефакты XText», я получаю следующую ошибку:

ошибка (208): ../mestra.dmxlightshow/src-gen/mestra/parser/antlr/internal/InternalDmxLightShow.g:3668:1: следующие определения токенов никогда не могут быть сопоставлены, поскольку предыдущие токены соответствуют одному и тому же вводу: ошибка RULE_MIDI_CHANNEL (208) : RULE_MIDI_CHANNEL

MIDI_CHANNEL/MidiChannel используется только в следующих фрагментах:

MidiNoteTrigger:
    'Note' onOff=ON_OFF 'Channel' mc=MidiChannel ('Note' note=MidiNote | 'NoteRange' noteRange=MidiNoteRange) velocity=MIDI_VALUE;

MidiCcTrigger:
    'CC' 'Channel' mc=MidiChannel 'Number' ccNumber=(MIDI_VALUE) ('Value' value=MidiValue | 'ValueRange' valueRange=MidiValueRange);

MidiAftertouchTrigger:
    'Aftertouch' 'Channel' mc=MidiChannel ('Value' value=MidiValue | 'ValueRange' valueRange=MidiValueRange);

MidiProgramChangeTrigger:
    'PrgChg' 'Channel' mc=MidiChannel 'Bank' bank=MidiValue 'Program' program=MidiValue;

MidiChannel: 
    channel=('OMNI' | MIDI_CHANNEL);

В начале каждого правила (кроме MidiChannel) есть ключевое слово ("Time", "Note", "CC", "Aftertouch", "PrgCh", поэтому я надеялся, что следующие правила будут уникальными.

И определение MIDI_CHANNEL:

terminal MIDI_CHANNEL:
    ('1' '0'..'6') |
    (    '0'..'9');

Как я могу исправить эту ошибку?

Полная грамматика ниже:

ТЕСТЫ, ПРОВЕДЕННЫЕ МНОЙ

  1. Меняем правило на другое имя и выписываем числа:

    терминал MIDI_CHANNEL_NUMBER: ('1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12 ' | '13' | '14' | '15' | '16');

    Результат: та же ошибка с другим именем (MIDI_CHANNEL_NUMBER)

  2. Удалена ссылка на MIDI_CHANNEL_NUMBER (поэтому правило никогда не используется):

    Результат: ОШИБКА ЕЩЕ ПРИСУТСТВУЕТ. Я не ожидал этого, так как он нигде не используется.

  3. Удаление номеров с 10 по 16 из списка

    Результат: Ошибка все еще присутствует.

  4. Удалено ( и )

    Результат: Ошибка все еще присутствует.

  5. Изменение значений на «x» и «y»

    Результат: Ошибка исчезает. Но мне нужны не значения x и y, а от 1 до 16.

ПОЛНАЯ ГРАММАТИКА

// Grammar 
grammar mestra.DmxLightShow with org.eclipse.xtext.common.Terminals

generate dmxLightShow 'http://www.DmxLightShow.mestra'

// Main structure

Mestra:
    'songs:'    songs   +=Song+ 
    'triggers:' triggers+=RuleTrigger+ 
    'commands:' commands+=Command+;

// Song structure

Song:
    'song' name=ID ':'
      'bank' bank=MIDI_VALUE 'program' program=MIDI_VALUE ';'
      rules=Rules
      ('order'      sequenceRefs+=[Sequence] (',' sequenceRefs+=[Sequence])* ';'
       'sequences:' sequences   += Sequence+)?;

Sequence:
    'sequence' name=ID ':'
       rules=Rules
      ('order'  stepRefs+=[Step] (',' stepRefs+=[Step])* ';'
       'steps:' steps   += Step+)?;

Step:
    'step' name=ID  ':'
       rules=Rules;

// Rules

Rules: 
    {Rules} rules+=Rule*;

Rule:
    'rule' (ruleTriggers=RuleTriggers ':')? ruleCommands=RuleCommands ';';

RuleTriggers:
    triggerRefs+=[RuleTrigger] (',' triggerRefs+=[RuleTrigger])*;

RuleCommands:
    commandsRefs+=[Command] (',' commandsRefs+=[Command])*;

// Rule Triggers

RuleTrigger:
    name=ID type=(/* DmxRuleTrigger | */ MidiRuleTrigger) ';';

// DmxRuleTrigger: // Not supported

MidiRuleTrigger:
    type=(MidiTimeTrigger | MidiNoteTrigger | MidiCcTrigger | MidiAftertouchTrigger | MidiProgramChangeTrigger) ';';

MidiTimeTrigger:
    'Time' time=Time;

MidiNoteTrigger:
    'Note' onOff=ON_OFF 'Channel' mc=MidiChannel ('Note' note=MidiNote | 'NoteRange' noteRange=MidiNoteRange) velocity=MIDI_VALUE;

MidiCcTrigger:
    'CC' 'Channel' mc=MidiChannel 'Number' ccNumber=(MIDI_VALUE) ('Value' value=MidiValue | 'ValueRange' valueRange=MidiValueRange);

MidiAftertouchTrigger:
    'Aftertouch' 'Channel' mc=MidiChannel ('Value' value=MidiValue | 'ValueRange' valueRange=MidiValueRange);

MidiProgramChangeTrigger:
    'PrgChg' 'Channel' mc=MidiChannel 'Bank' bank=MidiValue 'Program' program=MidiValue;

MidiChannel: 
    channel=('OMNI' | MIDI_CHANNEL);

MidiValue:
    value=MIDI_VALUE;

MidiValueRange:
    start=MIDI_VALUE '-' end=MIDI_VALUE;

MidiNote: 
    'Note' note=MIDI_NOTE;

MidiNoteRange: 
    'NoteRange' start=MIDI_NOTE '-' end=MIDI_NOTE;

Time:
    'Time' time=INT type=('ms' | 's' );

// Commands

Command:
    name=ID type=(DmxCommand /* | MidiCommand */ ) ';';

// MidiCommand: // Not supported

DmxCommand:
    parGroup=ParGroup dmxSubCommands=DmxSubCommands ';';

ParGroup:
    (parGroup=  'AllGroupsAll' | 
                {ParGroup} 'AllGroupsCenter' |
                {ParGroup} 'AllGroupsAllExceptEgoRisers' |
                {ParGroup} 'AllGroupsLeft' |
                {ParGroup} 'AllGroupsRight' |
                {ParGroup} 'LedBarAll' |
                {ParGroup} 'LedBarCenter' |
                {ParGroup} 'LedBarLeft' |
                {ParGroup} 'LedBarRight' |
                {ParGroup} 'DrumsAll' |
                {ParGroup} 'DrumsLeft' |
                {ParGroup} 'DrumsRight' |
                {ParGroup} 'EgoRisersAll' |
                {ParGroup} 'EgoRisersLeft' |
                {ParGroup} 'EgoRisersRight' |
                {ParGroup} 'FrontAll' |
                {ParGroup} 'FontCorners' |
                {ParGroup} 'FrontMiddle' |
                {ParGroup} 'FrontInner' |
                {ParGroup} 'FrontOuter' |
                {ParGroup} 'FrontLeft1Inside' |
                {ParGroup} 'FrontLeft2' |
                {ParGroup} 'FrontLeft3' |
                {ParGroup} 'FrontLeft4Outside' |
                {ParGroup} 'FrontLeftAll' |
                {ParGroup} 'FrontLeftInner' |
                {ParGroup} 'FrontLeftOuter' |
                {ParGroup} 'BannerAll' |
                {ParGroup} 'BannerLeft' |
                {ParGroup} 'BannerRight' |
                {ParGroup} 'FrontRight1Inside' |
                {ParGroup} 'FrontRight2' |
                {ParGroup} 'FrontRight3' |
                {ParGroup} 'FrontRight4Outside' |
                {ParGroup} 'FrontRightAll' |
                {ParGroup} 'FrontRightInner' |
                {ParGroup} 'FrontRightOuter');

DmxSubCommands:
    {DmxSubCommands} 
    (mode=DmxModeSubCommand)? 
    (preset=DmxPresetSubCommand)?  
    (delayTime=DmxDelayTimeSubCommand)? 
    (strobeTime=DmxStrobeTimeSubCommand)? 
    (stepNumber=DmxStepNumberSubCommand)? 
    (hold=DmxHoldSubCommand)? 
    (once=DmxOnceSubCommand)? 
    (DefaultColor=DmxDefaultColorSubCommand)? 
    (AlternateColor=DmxAlternateColorSubCommand)?;

DmxModeSubCommand:
    'Mode' DmxModeSubCommandData;

DmxModeSubCommandData:
    type=('trigger' | 'loop' | 'once' | 'restart');

DmxPresetSubCommand:
    'Preset' DmxPresetSubCommandData;

DmxPresetSubCommandData:
    presetName=                          'def2alt' |
               {DmxPresetSubCommandData} 'alt2def' |
               {DmxPresetSubCommandData} 'switch_def_alt' |
               {DmxPresetSubCommandData} 'def2act' |
               {DmxPresetSubCommandData} 'actual2def' |
               {DmxPresetSubCommandData} 'switch_def_actual' |
               {DmxPresetSubCommandData} 'alt2actual' |
               {DmxPresetSubCommandData} 'actual2alt' |
               {DmxPresetSubCommandData} 'switch_alt_actual' |
               {DmxPresetSubCommandData} 'solid' |           
               {DmxPresetSubCommandData} 'dual_colors_def_alt' |
               {DmxPresetSubCommandData} 'dual_colors_alt_def' |
               {DmxPresetSubCommandData} 'chase_left2right' |
               {DmxPresetSubCommandData} 'chase_right2left' |
               {DmxPresetSubCommandData} 'switch_left_right_left' |
               {DmxPresetSubCommandData} 'switch_right_left_right' |
               {DmxPresetSubCommandData} 'fade_alt2def' |
               {DmxPresetSubCommandData} 'fade_def2alt' |
               {DmxPresetSubCommandData} 'fade_def_alt_def' |
               {DmxPresetSubCommandData} 'fade_alt_def_alt' |
               {DmxPresetSubCommandData} 'fade_chase_left2right' |
               {DmxPresetSubCommandData} 'fade_chase_right2left' |
               {DmxPresetSubCommandData} 'fade_chase_left_right_left' |
               {DmxPresetSubCommandData} 'fade_chase_right_left_right' |
               {DmxPresetSubCommandData} 'rainbow_no_fade_left2right' |
               {DmxPresetSubCommandData} 'rainbow_no_fade_right2left' |
               {DmxPresetSubCommandData} 'rainbow_fade_left2right' |
               {DmxPresetSubCommandData} 'rainbow_fade_right2left';

DmxDelayTimeSubCommand:
    'DelayTime' time=Time;

DmxStrobeTimeSubCommand:
    'StrobeTime' time=Time;

DmxStepNumberSubCommand:
    'StepNumber' (last='Last' | value=INT);

DmxHoldSubCommand:
    'Hold' onOff=ON_OFF;

DmxOnceSubCommand:
    'Once' onOff=ON_OFF;

DmxDefaultColorSubCommand:
    'DefaultColor' color=DmxColor;

DmxAlternateColorSubCommand:
    'AlternateColor' color=DmxColor;

DmxColor: 
    ShortDmxColor | LongDmxColor;

ShortDmxColor:
    {ShortDmxColor} (intensity='I')? (red='R')? (green='G')? (blue='B')? (white='W')?;

LongDmxColor:
    intensity=DMX_VALUE red=DMX_VALUE green=DMX_VALUE blue=DMX_VALUE (white=DMX_VALUE)?;

// Terminals

terminal MIDI_VALUE: 
    ('1' '2'      '0'..'7') |
    ('1' '0'..'1' '0'..'9') |
    (    '1'..'9' '0'..'9') |  
    (             '0'..'9');

terminal DMX_VALUE: 
    ('2' '5'      '0'..'5') |
    ('2' '0'..'4' '0'..'9') |
    ('1' '0'..'9' '0'..'9') |
    (    '1'..'9' '0'..'9') |  
    (             '0'..'9');

terminal MIDI_CHANNEL:
    ('1' '0'..'6') |
    (    '0'..'9');

terminal MIDI_NOTE: 
    ('C' | 'D' | 'E' | 'F' | 'G' | 'A' | 'B') 
    ('b' | '#') 
    ('0'..'9') | ('1' '0'..'1');

terminal ON_OFF: 
    ('ON' | 'OFF');

person Michel Keijzers    schedule 23.07.2019    source источник


Ответы (1)


правила MIDI_VALUE и DMX_VALUE и MIDI_CHANNEL пересекаются друг с другом.

возможные решения

  1. используйте INT + валидатор (для всех)
  2. используйте правило типа данных, например MIDI_CHANNEL: INT (без терминального ключевого слова) + преобразователь значений
  3. использовать терминальные правила, которые не перекрываются, и правила типов данных MIDI_CHANNEL: TERMINAL1|TERMINAL2| ....
person Christian Dietrich    schedule 24.07.2019
comment
Ах, похоже, это очень связано с моим другим вопросом ... я проверю (когда у меня будет время, завтра или в пятницу) - person Michel Keijzers; 24.07.2019