Рекурсивный анализ в красном

Я хочу проанализировать-пропустить Forth-стиль, если это из ввода, Forth-стиль означает каждый, если начинается с if и заканчивается thenпри условии, что все данные введены правильно, обработка несоответствий не требуется.

Проблема в каждой части if может рекурсивно содержать любое количество других if"S.

Вот мое лучшее решение с тестовыми примерами:

Red []

skip-nested-ifs: [skip to ['if | 'then] skip-nested-ifs-helper]
skip-nested-ifs-helper: ['then | skip-nested-ifs skip-nested-ifs-helper ]


rules: skip-nested-ifs

test-cases: [
   [if a then]
   [if a else b then]
   [if a if b then then]
   [if a if b then 5 then]
   [if a if b then 5 if c then then]
   [if a else if b then then]
   [if a else if b then 5 then]
   [if a else if b then if c then then]
   [if a if b if c then if d then then then]
]

forall test-cases [
   prin [mold test-cases/1 ""]
   print either parse test-cases/1 rules [ "OK" ] [ "FAIL" ]
]

Выход:

[if a then] OK
[if a else b then] OK
[if a if b then then] OK
[if a if b then 5 then] FAIL
[if a if b then 5 if c then then] FAIL
[if a else if b then then] OK
[if a else if b then 5 then] FAIL
[if a else if b then if c then then] OK
[if a if b if c then if d then then then] OK

Так что три из них терпят неудачу, потому что они содержат что-то (5 в этом случае) между одним then и другой.

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

1 ответ

Решение

Я не уверен, исправимо ли ваше правило или нет, так как оно сильно зависит от рекурсии, но не может обеспечить поддержку итерации, которая необходима для теста № 5. Я не смог это исправить, так как skip используется для использования как терминальных, так и нетерминальных токенов (включая if), поэтому мне трудно следовать.

Я придумал другое решение. Это длиннее, но проходит все ваши тесты (используя красный):

rules: [
    'if skip 
    opt ['else [some rules | skip]]
    opt some rules
    'then
    opt [some rules | ahead 'then | skip]
]

Заметки:

  • Я попытался сделать правила грамматики как можно более явными.
  • Обратите внимание на использование some итеративно потреблять подвыражения.
  • ahead 'then охранное правило, есть, чтобы предотвратить skip от потребления дополнительного then который будет частью родительского выражения (в случае рекурсивного вызова).
  • Оно использует skip передать через терминал значение следующего then или же elseхотя из вашего описания не ясно, может ли там быть более одного значения. В любом случае, его легко расширить для соответствия более сложным шаблонам, если это необходимо.

Если вы хотите использовать такое правило для пропуска ввода, вы можете вызвать его следующим образом:

skip-ifs: [to 'if rules]

Надеюсь это поможет.

Другие вопросы по тегам