2015-01-05 3 views
2

При реализации реальных языков (TM), я часто сталкиваюсь с ситуацией, как это:значения Pass в качестве аргументов правил

(* language Foo *) 
type A = ... (* parsed by parse_A *) 
type B = ... (* parsed by parse_B *) 
type collection = { as : A list ; bs : B list } 

(* parser ParseFoo.mly *) 
parseA : ... { A (...) } 
parseB : ... { B (...) } 

parseCollectionElement : parseA { .. } | parseB { .. } 

parseCollection : nonempty_list (parseCollectionElement) { ... } 

Очевидно (в функциональном стиле), было бы лучше, чтобы пройти частично разобран collection записывать для каждого вызова семантических действий parseA и parseB и соответственно обновлять элементы списка.

Это возможно даже с использованием menhir, или нужно использовать уродливый взлом использования изменяемой глобальной переменной?

ответ

1

Ну, вы совершенно ограничены тем, что вам разрешено делать в ментальных/окамлачских семантических действиях. Если вы обнаружите, что это действительно расстраивает, вы можете попробовать parsec-подобные парсеры, например. mparser, которые позволяют вам полностью использовать OCaml в своих правилах.

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

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

+0

Звучит разумно. Вместо того, чтобы передавать частично обработанную коллекцию вперед в смену, я, очевидно, также могу обновить ее при сокращении по пользовательскому рекурсивному правилу ... Я рассмотрю ее и дам вам знать, если это сработает. – choeger