Erlang编译器如何处理模式匹配?它输出什么?

gzszwxb4  于 2022-12-08  发布在  Erlang
关注(0)|答案(2)|浏览(172)

我刚才问了一个关于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}]},我假设这是一条指令,叫做'test'...总之,这个输出本质上是字节码级语言的AST,二进制编码只是一个1-1的转换。
这一切都是如此令人兴奋,我不知道我可以这么容易地看到Erlang编译器把东西分解成什么。

vnzz0bqm

vnzz0bqm1#

好吧,我深入到编译器源代码中寻找答案,令我惊讶的是,使用compile:file()函数的'S'参数生成的asm文件实际上是按原样进行咨询的(file:consult()),然后逐个检查元组以进行进一步的操作(第661行- beam_consult_asm(St)-〉- compile.erl)。进一步,在那里有一个生成的Map表(erlang源代码的compile文件夹),它显示每个字节码标签的序列号,并猜测这是用来生成字节码的实际二进制签名的。很棒。但你一定会喜欢consult()函数,你几乎可以拥有随机语言的lispy类型语法,完全避免了对解析器/词法分析器的需要,只需将源代码咨询到编译器中,然后用它做一些事情,,. code as data data as code.,,

utugiqy6

utugiqy62#

编译器有一个所谓的 * 模式匹配编译器 *,它将接受一个模式,并将其编译为一系列分支、开关等。Erlang的代码在编译器中以v3_kernel.erl存在。它使用Simon佩顿Jones的“函数式编程语言的实现”,可在以下网址获得:
http://research.microsoft.com/en-us/um/people/simonpj/papers/slpj-book-1987/
另一篇有价值的论文是彼得·塞斯托夫的,
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必须进行检查,如果不匹配则失败。

相关问题