2009-02-25 24 views
18

beh spero di non aver infranto alcune regole di spamming qui con questo. ho solo chiesto una domanda su come il compilatore erlang implementa il pattern matching, e ho avuto alcuni grandi risposte, uno dei quali è il bytecode compilato (ottenuto con un parametro passato alla direttiva c()):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}} 

è tutto semplicemente tuple di erlang. Mi aspettavo qualche cosa binaria criptica, suppongo di no. quindi, sto chiedendo questo su impulso qui (potrei guardare la fonte del compilatore ma fare domande finisce sempre meglio con una visione extra), come viene tradotto questo output a livello binario?

dire {test,is_tuple,{f,3},[{x,0}]} per esempio. Im supponendo che questa sia un'istruzione, chiamata 'test' ... comunque, quindi questo output sarebbe essenzialmente l'AST del linguaggio di livello bytecode, da cui la codifica binaria è solo una traduzione 1-1? Questo è tutto così eccitante, non avevo idea di poter vedere facilmente in che modo il compilatore di erlang rompe le cose.

grazie tanto

+0

+1 visto che sono anche interessati, e seguii dalla tua domanda precedente tramite Google :) –

risposta

12

ok così ho scavato nel codice sorgente del compilatore per trovare la risposta, e con mia sorpresa il file asm prodotto con il parametro 'S' per la compilazione: File() è in realtà consultato in come è (file: consult()) e quindi le tuple vengono controllate una ad una per ulteriori azioni (riga 661 - beam_consult_asm (St) -> - compile.erl). più avanti c'è poi una tabella di mappatura generata lì (cartella di compilazione del sorgente di erlang) che mostra qual è il numero di serie di ogni etichetta di bytecode, e Suppongo che questo sia usato per generare l'effettiva firma binaria del bytecode. grandi cose. ma devi semplicemente amare la funzione consult(), puoi quasi avere una sintassi di tipo lispy per un linguaggio casuale ed evitare la necessità di un parser/lexer completo e basta consultare il codice sorgente nel compilatore e fare cose con esso ... codice come dati di dati come codice ...

+3

Hai guardato di Robert Virding Lisp-aromatizzato Erlang (http://forum.trapexit.org/viewtopic.php?p= 40268) –

+0

sì, l'ho visto, non l'ho ancora usato nonostante sia piuttosto alto nel mio elenco di cose da fare a breve termine. grazie – deepblue

5

Il compilatore ha un cosiddetto compilatore di corrispondenza modello che prenderà un modello e lo compila verso il basso a ciò che è essenzialmente una serie di rami, interruttori e così via. Il codice per Erlang è in v3_kernel.erl nel compilatore. Esso utilizza Simon Peyton Jones, "l'attuazione del Funzionale Linguaggi di Programmazione", disponibile online all'indirizzo

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

Un'altra carta degna è quella di Peter Sestoft,

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

che deriva un schema partita compilatore esaminando la valutazione parziale di un sistema più semplice. Potrebbe essere una lettura più facile, soprattutto se conosci ML.

L'idea di base è che se avete, diciamo:

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

Supponiamo ora abbiamo una chiamata f(X, Y). Dì X = a. Quindi solo 1 e 2 sono applicabili. Quindi controlliamo Y = b e poi Y = c. Se d'altra parte X /= a allora sappiamo che possiamo saltare 1 e 2 e iniziare i test 3 e 4. La chiave è che se qualcosa non corrisponde a ci dice qualcosa su dove la partita può continuare così come quando noi corrispondiamo. È un insieme di vincoli che possiamo risolvere testando.

I compilatori di corrispondenze di pattern cercano di ottimizzare il numero di test in modo da renderne il minimo possibile prima di concludere. Staticamente tipizzato lingua hanno alcuni vantaggi qui in quanto possono sapere che:

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

e poi se abbiamo

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

e non abbiamo fatto corrispondere f(a), f(b) allora f (c) must partita. Erlang deve controllare e poi fallire se non corrisponde.