我正在尝试在生成的解析器中使用Menhir的增量解析 API和自省 API 。比如说,我想确定与特定 LR(1) 堆栈条目相关的语义值;即解析器先前使用的令牌。
给定一个抽象的解析检查点,封装在 Menhir 的 type'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
。因此,对于某些 type'a
, states
有 type'a lr1state
并且 valuev
有 type'a
...为了对值做任何有用的事情,必须通过检查状态
v
来获取有关类型的信息。到目前为止,类型是抽象的,所以没有办法检查. 检查 API(第 9.3 节)为此提供了更多工具。'a
s
'a lr1state
s
好,爽!所以我开始深入检查 API:
类型 'a 终端是一种广义代数数据类型 (GADT)。'a 终端类型的值表示终端符号(没有语义值)。索引 'a 是与此符号关联的语义值的类型...
type _ terminal = | T_A : unit terminal | T_B : int terminal
类型 'a 非终结符也是一个 GADT。'a 非终结符类型的值表示非终结符符号(没有语义值)。索引 'a 是与此符号关联的语义值的类型...
type _ nonterminal = | N_main : thing nonterminal
将这些拼凑在一起,我得到如下内容(其中“命令”是我的语法的非终结符之一,因此N_command
是 a 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
'ing on进行案例分析incoming_symbol s
,拉出v
单个特定类型的案例:string
.
tl;博士:我如何从这个 GADT 中提取字符串有效负载,并用它做一些有用的事情?