我正在尝试在生成的解析器中使用Menhir的增量解析 API和自省 API 。比如说,我想确定与特定 LR(1) 堆栈条目相关的语义值;即解析器先前使用的令牌。
给定一个抽象的解析检查点,封装在 Menhir 的 type'a env中,我可以从 LR 自动机中提取一个“堆栈元素”;它看起来像这样:
type element = | Element: 'a lr1state * 'a * position * position -> elementtype 元素描述了 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 节)为此提供了更多工具。'as'a lr1states
好,爽!所以我开始深入检查 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 中提取字符串有效负载,并用它做一些有用的事情?