我刚才问了一个关于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编译器把东西分解成什么。
2条答案
按热度按时间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.,,
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的话。
基本思路是,如果你有,就说:
假设现在我们有一个调用
f(X, Y)
。比如X = a
。那么只有1和2是适用的。所以我们检查Y = b
,然后检查Y = c
。如果另一方面X /= a
,那么我们知道我们可以 * 跳过 * 1和2,开始测试3和4。关键是如果某个东西 * 不 * 它告诉我们匹配可以在哪里继续以及何时进行匹配。它是一组约束,我们可以通过测试来解决。模式匹配编译器寻求优化测试的数量,这样在我们得出结论之前就有尽可能少的测试。静态类型语言在这方面有一些优势,因为它们可能知道:
然后如果我们有
并且我们没有匹配
f(a), f(b)
,那么f(c)* 必须 * 匹配。Erlang必须进行检查,如果不匹配则失败。