2009-02-25 11 views
18

cóż, mam nadzieję, że nie łamie to zasady spamowania. właśnie zadał pytanie, w jaki sposób kompilator Erlang implementuje wzorzec dopasowania, i mam kilka świetnych odpowiedzi, z których jedna jest skompilowany kod bajtowy (otrzymany z parametru przekazanego do c() dyrektywy):erlang BEAM bytecode

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

to wszystko po prostu erlangowe krotki. Spodziewałem się, że nie będzie to tajemnicza binarna rzecz. więc pytam o to tutaj pod wpływem impulsu (mogłem spojrzeć na źródło kompilatora, ale zadawanie pytań zawsze kończy się lepiej dzięki dodatkowemu wglądowi), w jaki sposób ten wynik jest tłumaczony na poziomie binarnym?

powiedzmy na przykład {test,is_tuple,{f,3},[{x,0}]}. Zakładam, że jest to jedna instrukcja, zwana "testem" ... w każdym razie, więc ten wynik byłby zasadniczo AST języka na poziomie kodu bajtowego, z którego kodowanie binarne jest tylko tłumaczeniem 1-1? To wszystko jest tak ekscytujące, że nie miałem pojęcia, że ​​mogę to łatwo zobaczyć, do czego kompilator erlang włamuje się.

Dzięki tak dużo

+0

+1, ponieważ jestem również zainteresowany, a następnie z poprzedniego pytania przez Google :) –

Odpowiedz

12

ok więc sięgnął do kodu źródłowego kompilatora, aby znaleźć odpowiedź, i ku mojemu zdziwieniu pliku asm produkowane z parametrem „S” do kompilacji: file() jest faktycznie konsultowany w as (plik: consult()), a następnie krotki są sprawdzane jeden po drugim dla dalszego działania (linia 661 - beam_consult_asm (St) -> - compile.erl). dalej jest tam wygenerowana tabela mapowania (kompilacja folderu źródła erlang), która pokazuje, jaki jest numer seryjny każdej etykiety kodu bajtowego, i Im guessing to jest używane do generowania rzeczywistej sygnatury binarnej kodu bajtowego. świetne rzeczy. ale musisz po prostu uszczęśliwić funkcję consult(), możesz prawie mieć składnię typu lispy dla losowego języka i całkowicie uniknąć potrzeby użycia parsera/lexera i po prostu sprawdź kod źródłowy w kompilatorze i zrób z nim ... kod jako dane danych jako kod ...

+3

Czy spojrzał na Lisp-Flavored Erlang Roberta Virdinga (http://forum.trapexit.org/viewtopic.php?p= 40268) –

+0

Tak, widziałem to, jeszcze go nie użyłem, chociaż jest dość wysoko na mojej liście rzeczy do zrobienia w krótkim czasie. dzięki, tho – deepblue

5

Kompilator ma tak zwany kompilator dopasowania wzoru , który pobiera wzorzec i kompiluje go do tego, co jest w istocie serią gałęzi, przełączników i tym podobnych. Kod dla Erlang jest w v3_kernel.erl w kompilatorze. Wykorzystuje Simon Peyton Jones, "Wdrożenie funkcjonalnych języków programowania", dostępne na stronie internetowej

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

Innym godnym papier jest jeden Petera Sestoft,

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

czerpiącej kompilator dopasowywania wzorca poprzez sprawdzenie częściowej oceny prostszego systemu. Może to być łatwiejsza lektura, szczególnie jeśli znasz ML.

Podstawowym założeniem jest to, że jeśli masz, powiedzmy:

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

Załóżmy teraz, że mamy połączenie f(X, Y). Powiedz X = a. Wtedy tylko 1 i 2 mają zastosowanie. Sprawdzamy więc Y = b, a następnie Y = c. Jeśli z drugiej strony X /= a to wiemy, że możemy pominąć 1 i 2 i rozpocząć testowanie 3 i 4. Kluczem jest to, że jeśli coś jest nie mecz to mówi nam coś o tym, gdzie mecz może być kontynuowany, a także kiedy pasujemy. Jest to zbiór ograniczeń, które możemy rozwiązać poprzez testowanie.

Kompilatory dopasowujące wzorce starają się zoptymalizować liczbę testów, więc jest ich tak mało, jak to możliwe, zanim skończymy. Statycznie wpisane język mają pewne zalety tutaj, ponieważ mogą one wiedzieć, że:

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

a następnie, jeśli mamy

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

i nie pasuje f(a), f(b) wtedy f (c) moszczu meczu. Erlang musi sprawdzić, a następnie zawieść, jeśli nie pasuje.