Как выйти из подчиненного правила после выполнения определенной части правила?

#midi #rebol #rebol3 #firmata

#midi #ребол #ребол3 #firmata

Вопрос:

В настоящее время разбираю Midi-сообщения для протокола Firmata в Rebol 3 и столкнулся с ситуацией, которую я раньше не видел.

По сути, у меня есть общее правило для копирования байтов между байтами кадрирования. Однако это правило поглощает байты кадрирования. Я сократил код до следующего:

 data: #{
    F06C00010101040E7F000101010308040E7F00010101040E7F0001010103
    08040E7F000101010308040E7F00010101040E7F00010101040E7F0001010103
    08040E7F000101010308040E7F000101010308040E7F00010101040E7F000101
    01040E7F00010101020A7F00010101020A7F00010101020A7F00010101020A7F
    00010101020A06017F00010101020A06017FF7
}

sysex-start: #{F0}
sysex-end: #{F7}
capability-query: #{6B}
capability-response: #{6C}
capability-end: #{7F}

received-rule: [
    sysex-start
    capability-response-rule 
    sysex-end
]

capability-response-rule: [
    capability-response
    [
        capability-end |
        some [copy pin 1 skip]
    ]
]
parse data received-rule
 

Проблема в том, что some [copy pin 1 skip] это поглощает sysex-end двоичный файл.

  • Есть ли способ, которым я могу реструктурировать правило (не переходя sysex-end в подчиненное правило)?
  • Есть ли ключевое слово parse, которое помогло бы в этом случае выйти из подчиненного правила?

(Примечание: я знаю, что я не интерпретирую данные в соответствии со спецификацией.)

Комментарии:

1. В качестве примечания я склонен считать, что правило синтаксического анализа легче читать, если вы задаете | его собственную строку и выравниваете ее по скобкам в группе, в которую оно входит, когда вы помещаете альтернативы в их собственные строки. YMMV.

Ответ №1:

Вам нужно будет прервать цикл, когда он так или иначе попадет в sysex-end.

Вы либо сопоставляете sysex-end каждый раз в цикле и прерываете его при попадании, либо сопоставляете только со всем, что не является sysex-end .

Первый вариант, очевидно, переносит sysex-end в подчиненное правило, но он кажется простым. Если я переделаю вашу проблему следующим образом:

 problem-rule: [
    (matched-bytes: none)
    copy matched-bytes some [skip]
]
 

Тогда первым решением с использованием ключевого слова NOT может быть:

 alternative-1: [
    (matched-bytes: none)
    copy matched-bytes some [
        not sysex-end
        skip
    ]
]
 

Вторая альтернатива не приведет к sysex-end в подчиненное правило. Вы создаете набор битов! чтобы соответствовать всему, кроме sysex-end (247 соответствует шестнадцатеричному F7):

 not-sysex-end: bits: make bitset! [0 - 246 248 - 255]
alternative-2: [
    (matched-bytes: none)
    copy matched-bytes some [not-sysex-end]
]
 

Я недостаточно знаком с битовыми наборами Rebol 3, чтобы знать, есть ли лучший способ указать это.

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

Комментарии:

1. Да, я привык к наборам битов при синтаксическом анализе строк, но не делал так много двоичного синтаксического анализа. Работает хорошо!

Ответ №2:

вы могли бы (по крайней мере, в Rebol2) использовать

 pin-set: complement charset to-string #{F7} 

received-rule: [
    sysex-start
    capability-response-rule 
    sysex-end
]

capability-response-rule: [
    capability-response
    [
        capability-end |
        some  [copy pin pin-set  ]
    ]
]
parse data received-rule
 

== true