Можно ли заставить Менгира генерировать функтор? Или что-то в этом роде?
В качестве небольшого примера предположим, что у вас есть семейство языков, которые имеют одну и ту же структуру, за исключением типа значения и ключевых слов. Скажем, у меня есть подпись модуля:
module type M = sig
type value_type
type keyword
end
с некоторым функтором AST:
module AST (M : M) = struct
type t = ...
...
end
Я могу определить несколько вариантов AST с разными типами и ключевыми словами, создав их экземпляры с разными M
. например AST1 = AST(M1)
, AST2 = AST(M2)
и т. д.
Однако если мне нужен парсер для AST(M).t
, я ограничен созданием разных парсеров для каждого AST1
, AST2
и т. д., если только нет способа сделать параметрический парсер для M
.
Альтернативно я могу определить пересечение AST, которое затем можно преобразовать в каждый вариант. Но для этого необходимо пройти каждый AST после анализа, поэтому я надеялся, что Menhir, возможно, сможет сделать это за один шаг.
Вы можете определить параметризованный парсер, добавив в него заголовок %parameter
:
%parameter<M:sig
type value
type keyword
end>
В репозитории менгиров есть пример https://gitlab.inria.fr/fpottier/menhir/-/blob/master/demos/calc-param/parser.mly?ref_type=heads#L4.
С помощью этого параметра будет сгенерирован код синтаксического анализа внутри функтора Make
, который вы можете вызвать с помощью различной реализации.
Да, вам нужно создать парсер с помощью module Parser_for_M=Parser.Make(M)
.
Спасибо тебе за это! Чтобы продолжить, мне пришлось разделить токены в файл token.mly, скомпилировать его заранее, а затем вызвать из лексера. В примере удобно использовать файл dune, который научит вас, как настроить это в dune. Есть ли способ использовать существующую подпись модуля вместо того, чтобы каждый раз жестко кодировать подпись? то есть %parameter<M: SomeModule.SomeSignature>
вместо M: sig ... end
ах, неважно. Я понял это. Мне нужно использовать правильные имена модулей, указанные в файле дюны... <M : DuneName.SomeModule.SomeSignature>
О, спасибо вам большое! Я этого не видел. Я попробую. По сути, мне нужно было бы вызвать что-то вроде
Parser.Make(M)
, верно?