Я пытаюсь использовать Menhir API добавочного синтаксического анализа и API самоанализа в сгенерированном синтаксическом анализаторе. Я хочу, скажем, определить семантическое значение, связанное с конкретной записью стека LR(1); токен, который ранее использовался синтаксическим анализатором.
Имея абстрактную контрольную точку синтаксического анализа, инкапсулированную в тип 'a env
Менгира, я могу извлечь «элемент стека» из автомата LR; это выглядит так:
type element = | Element: 'a lr1state * 'a * position * position -> element
Элемент type описывает одну запись в стеке автомата LR(1). В элементе стека формы
Element (s, v, startp, endp)
s
— это (не начальное) состояние, аv
— семантическое значение. Значениеv
связано с входящим символом A состоянияs
. Другими словами, значениеv
было помещено в стек непосредственно перед переходом в состояниеs
. Таким образом, для некоторого типа'a
состояниеs
имеет тип'a lr1state
, а значениеv
имеет тип'a
...Чтобы сделать что-нибудь полезное со значением
v
, нужно получить информацию о типе'a
путем проверки состоянияs
. Пока что тип'a lr1state
является абстрактным, поэтому нет возможности проверитьs
. API проверки (§9.3) предлагает дополнительные инструменты для этой цели.
Хорошо! Итак, я иду и углубляюсь в API проверки:
Терминал представляет собой обобщенный алгебраический тип данных (GADT). Значение типа 'терминал представляет терминальный символ (без семантического значения). Индекс 'a - это тип семантических значений, связанных с этим символом...
type _ terminal = | T_A : unit terminal | T_B : int terminal
Тип нетерминала также является GADT. Значение типа 'a nonterminal представляет собой нетерминальный символ (без семантического значения). Индекс 'a - это тип семантических значений, связанных с этим символом...
type _ nonterminal = | N_main : thing nonterminal
Собрав их вместе, я получаю что-то вроде следующего (где команда — это один из нетерминалов моей грамматики, и, таким образом, N_command
— это string nonterminal
):
let current_command (env : 'a env) =
let rec f i =
match Interpreter.get i env with
| None -> None
| Some Interpreter.Element (lr1state, v, _startp, _endp) ->
match Interpreter.incoming_symbol lr1state with
| Interpreter.N Interpreter.N_command -> Some v
| _ -> f (i + 1)
in
f 0
К сожалению, это вызывает у меня очень запутанные ошибки типа:
File "src/incremental.ml", line 110, characters 52-53:
Error: This expression has type string but an expression was expected of type
string
This instance of string is ambiguous:
it would escape the scope of its equation
Это немного выше моего уровня! Я почти уверен, что понимаю, почему я не могу сделать то, что пытался сделать выше; но я не понимаю, каковы мои альтернативы. На самом деле, в руководстве Menhir конкретно упоминается об этой сложности:
Эту функцию можно использовать для получения доступа к семантическому значению
v
в элементе стекаElement (s, v, _, _)
. В самом деле, анализируя случай символаincoming_symbol s
, можно получить информацию о типе'a
, следовательно, получить возможность сделать что-то полезное со значениемv
.
Хорошо, но это то, что, как я думал, я сделал выше: анализ случая путем match
обработки incoming_symbol s
, извлечения случая, когда v
относится к одному конкретному типу: string
.
Вкратце: как мне извлечь полезную нагрузку строки из этого GADT и сделать с ней что-нибудь полезное?