Compiler construction 模式匹配-实现

Compiler construction 模式匹配-实现,compiler-construction,erlang,pattern-matching,Compiler Construction,Erlang,Pattern Matching,我想知道模式匹配通常是如何实现的。例如,在Erlang中,您认为它是在字节码级别实现的(有一个字节码,以便高效地完成),还是由编译器生成为一系列指令(一系列字节码) 这是一个非常有用的东西,我只需要把它放到我正在构建的玩具语言中。我能建议的最好办法是编译一些测试函数并查看生成的代码 erlc -S test.erl 生成可读性较好的test.S 为了回答这个问题,模式匹配是通过更原始的操作以有效的方式建立的。下面是匹配{X[H | T]}的函数子句的部分代码 {test,is_tuple,{f

我想知道模式匹配通常是如何实现的。例如,在Erlang中,您认为它是在字节码级别实现的(有一个字节码,以便高效地完成),还是由编译器生成为一系列指令(一系列字节码)


这是一个非常有用的东西,我只需要把它放到我正在构建的玩具语言中。

我能建议的最好办法是编译一些测试函数并查看生成的代码

erlc -S test.erl
生成可读性较好的test.S

为了回答这个问题,模式匹配是通过更原始的操作以有效的方式建立的。下面是匹配{X[H | T]}的函数子句的部分代码

{test,is_tuple,{f,1},[{x,0}]}.
{test,test_arity,{f,1},[{x,0},2]}.
{get_tuple_element,{x,0},0,{x,1}}.
{get_tuple_element,{x,0},1,{x,2}}.
{test,is_nonempty_list,{f,4},[{x,2}]}.

您可以看到如果编译一些代码会发生什么

-module(match).
-export([match/1]).
match(X) -> {a,Y} = X.
当你想看的时候

结果是

module 'match' ['match'/1,
                'module_info'/0,
                'module_info'/1]
    attributes []
'match'/1 =
    %% Line 3
    fun (_cor0) ->
        case _cor0 of
          <{'a',Y}> when 'true' ->
              _cor0
          ( <_cor1> when 'true' ->
                primop 'match_fail'
                    ({'badmatch',_cor1})
            -| ['compiler_generated'] )
        end
'module_info'/0 =
    fun () ->
        call 'erlang':'get_module_info'
            ('match')
'module_info'/1 =
    fun (_cor0) ->
        call 'erlang':'get_module_info'
            ('match', _cor0)

和结果

{module, match}.  %% version = 0

{exports, [{match,1},{module_info,0},{module_info,1}]}.

{attributes, []}.

{labels, 8}.


{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}}.


{function, module_info, 0, 5}.
  {label,4}.
    {func_info,{atom,match},{atom,module_info},0}.
  {label,5}.
    {move,{atom,match},{x,0}}.
    {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.


{function, module_info, 1, 7}.
  {label,6}.
    {func_info,{atom,match},{atom,module_info},1}.
  {label,7}.
    {move,{x,0},{x,1}}.
    {move,{atom,match},{x,0}}.
    {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
如您所见,
{test,is_tuple,…
{test,test_arity,…
{get_tuple_元素,…
{test,is_eq_精确,…
是如何在beam中执行此匹配的指令,并将其直接转换为beam的字节码


Erlang编译器是在Erlang本身中实现的,您可以在模块的源代码中查看编译的每个阶段,并在Depended模块中查看详细信息。

如果您想构建自己的模式匹配器,有一个和一个都描述了如何将模式编译为有效的决策树(也称为嵌套开关语句).

中对编译模式匹配进行了很好的描述。这本书有点旧,但很好。除其他外,它还包含编译列表理解的描述


Erlang编译器使用了书中的这两种算法。

答案很好,这里有很多很棒的信息(特别是编译指令)。谢谢。太好了。非常感谢,看起来有很多有用的东西。谢谢。我已经下载了这本书一段时间了,但从来没有时间阅读。你怎么知道Erlang使用了它的算法?很抱歉没有更早地回复。我知道的原因是我为当前编译器实现了编译模式匹配,并且这就是我学习算法的地方。这很有效;)。感谢你在erlang上的工作,这有点奇怪,但确实是一股新鲜空气。让我的生活变得更美好sure@rvirding这包括二进制数据的模式匹配器吗?@MartinBerger二进制数据的模式匹配器是后来添加的,但它是编译模式的一部分它比匹配其他数据类型更复杂,因为模式可以以许多不同的方式重叠更多,例如,您可以在二进制文件的开头匹配不同大小的整数。
module 'match' ['match'/1,
                'module_info'/0,
                'module_info'/1]
    attributes []
'match'/1 =
    %% Line 3
    fun (_cor0) ->
        case _cor0 of
          <{'a',Y}> when 'true' ->
              _cor0
          ( <_cor1> when 'true' ->
                primop 'match_fail'
                    ({'badmatch',_cor1})
            -| ['compiler_generated'] )
        end
'module_info'/0 =
    fun () ->
        call 'erlang':'get_module_info'
            ('match')
'module_info'/1 =
    fun (_cor0) ->
        call 'erlang':'get_module_info'
            ('match', _cor0)
> c(match, 'S').
$ erlc -S match.erl
{module, match}.  %% version = 0

{exports, [{match,1},{module_info,0},{module_info,1}]}.

{attributes, []}.

{labels, 8}.


{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}}.


{function, module_info, 0, 5}.
  {label,4}.
    {func_info,{atom,match},{atom,module_info},0}.
  {label,5}.
    {move,{atom,match},{x,0}}.
    {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.


{function, module_info, 1, 7}.
  {label,6}.
    {func_info,{atom,match},{atom,module_info},1}.
  {label,7}.
    {move,{x,0},{x,1}}.
    {move,{atom,match},{x,0}}.
    {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.