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

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

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

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

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 и другим.

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


person user3033648    schedule 11.02.2017    source источник
comment
Вы использовали to в первом правиле намеренно, или вы действительно хотели thru?   -  person DocKimbel    schedule 12.02.2017
comment
parse-trace полезен для отладки синтаксического анализа   -  person Geeky I    schedule 12.02.2017
comment
@DocKimbel Я использую to намеренно, чтобы сопоставить then после, потому что, если then найдено первым, это означает, что текущий if завершен, иначе мы нажмем вложенный.   -  person user3033648    schedule 12.02.2017
comment
@user3033648 user3033648 Я просто хотел убедиться, что вы знаете, что to не использует правило аргумента, а просто останавливается перед (в данном случае ['if | 'then]).   -  person DocKimbel    schedule 12.02.2017


Ответы (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]

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

person DocKimbel    schedule 12.02.2017
comment
Спасибо за ваше решение, но последний пункт в правилах: opt [some rules | ahead 'then | skip] также пропускает следующий if, если он есть сразу после текущего, как здесь: [if a then if c then]. Я хочу пропустить только один текущий, если следующий будет обрабатываться отдельно. Как вы думаете, это возможно? - person user3033648; 18.02.2017
comment
Просто замените ahead 'then на ahead ['if | 'then], и он будет правильно анализировать даже такие разные шаблоны. - person DocKimbel; 20.02.2017
comment
Я попробовал opt [some rules | ahead ['if 'then] | skip] в качестве последней части правила, и половина тестов не прошла - person user3033648; 05.03.2017