19

我刚刚问了一个关于 Erlang 编译器如何实现模式匹配的问题,我得到了一些很好的回应,其中之一是编译后的字节码(通过传递给c()指令的参数获得):

{function, match, 1, 2}.
  {label,1}.
    {func_info,{atom,match},{atom,match},1}.
  {label,2}.
    {test,is_tuple,{f,3},[{x,0}]}.
    {test,test_arity,{f,3},[{x,0},2]}.
    {get_tuple_element,{x,0},0,{x,1}}.
    {test,is_eq_exact,{f,3},[{x,1},{atom,a}]}.
    return.
  {label,3}.
    {badmatch,{x,0}}

它只是简单的 Erlang 元组。我期待一些神秘的二进制东西,你猜不是。我在这里一时冲动地问这个问题(我可以查看编译器源代码,但通过额外的洞察力提出问题总是会更好),这个输出是如何在二进制级别翻译的?

比如说{test,is_tuple,{f,3},[{x,0}]}。我假设这是一条指令,称为“测试”......无论如何,所以这个输出本质上是字节码级语言的 AST,二进制编码只是 1-1 翻译?

这一切都太令人兴奋了,我不知道我可以这么容易地看到 Erlang 编译器把事情分解成什么。

4

2 回答 2

12

好的,所以我研究了编译器源代码以找到答案,令我惊讶的是,使用 compile:file() 函数的“S”参数生成的 asm 文件实际上是按原样查询的 (file:consult()) 和然后逐一检查元组以进行进一步操作(第 661 行 - beam_consult_asm(St) -> - compile.erl)。然后那里有一个生成的映射表(erlang源的编译文件夹),显示每个字节码标签的序列号是什么,我猜这是用来生成字节码的实际二进制签名。好东西。但是你只需要喜欢consult()函数,你几乎可以有一个随机语言的lispy类型语法,并且完全不需要解析器/词法分析器,只需在编译器中查阅源代码并用它做一些事情......代码作为数据数据作为代码...

于 2009-02-25T23:47:04.517 回答
5

编译器有一个所谓的模式匹配编译器,它将采用一个模式并将其编译成本质上是一系列分支、开关等。Erlang 的代码v3_kernel.erl在编译器中。它使用 Simon Peyton Jones,“函数式编程语言的实现”,可在线获取

http://research.microsoft.com/en-us/um/people/simonpj/papers/slpj-book-1987/

另一篇有价值的论文是 Peter Sestoft 的论文,

http://www.itu.dk/~sestoft/papers/match.ps.gz

它通过检查更简单系统的部分评估来派生模式匹配编译器。它可能更容易阅读,尤其是如果您了解 ML。

基本思想是,如果您有,请说:

% 1
f(a, b) ->
% 2
f(a, c) ->
% 3
f(b, b) ->
% 4
f(b, c) ->

假设现在我们有一个电话f(X, Y)。说X = a。那么只有1和2适用。所以我们检查Y = b然后Y = c。另一方面,如果X /= a我们知道我们可以跳过1 和 2 并开始测试 3 和 4。关键是,如果某些内容不匹配,它会告诉我们匹配可以在哪里继续以及何时匹配。这是一组我们可以通过测试解决的约束。

模式匹配编译器寻求优化测试的数量,因此在我们得出结论之前尽可能少。静态类型语言在这里有一些优势,因为他们可能知道:

-type foo() :: a | b | c.

然后如果我们有

-spec f(foo() -> any().
f(a) ->
f(b) ->
f(c) ->

我们不匹配f(a), f(b),那么 f(c)必须匹配。Erlang 必须检查,如果不匹配则失败。

于 2012-01-08T14:49:43.803 回答