Máquina SECD - SECD machine
A máquina SECD é um muito influente ( ver: a contribuição do § Landin ) máquina virtual e máquina abstrata concebida como um alvo para a linguagem de programação funcional compiladores . As letras significam S aderência, E MBIENTE, C ontrolo, D ump-os registos internos da máquina. Os registradores Stack, Control e Dump apontam para (algumas realizações de) pilhas e Environment aponta (algumas realizações de) um array associativo .
A máquina foi a primeira a ser projetada especificamente para avaliar expressões de cálculo lambda . Foi originalmente descrito por Peter J. Landin em "The Mechanical Evaluation of Expressions" em 1964. A descrição publicada por Landin era bastante abstrata e deixou muitas opções de implementação em aberto (como uma semântica operacional ).
Lispkit Lisp foi um compilador influente baseado na máquina SECD, e a máquina SECD tem sido usada como alvo para outros sistemas como Lisp / 370. Em 1989, pesquisadores da Universidade de Calgary trabalharam na implementação de hardware da máquina.
Contribuição de Landin
DA Turner (2012) aponta que The Revised Report on Algol 60 ( Naur 1963) especifica uma chamada de procedimento por uma regra de cópia que evita a captura de variável com uma mudança sistemática de identificadores. Este método funciona na implementação do Algol 60, mas em uma linguagem de programação funcional em que as funções são cidadãos de primeira classe, uma variável livre em uma pilha de chamadas pode ser referenciada erroneamente.
Turner observa que Landin resolveu isso com sua máquina SECD, na qual uma função é representada por um fechamento no heap.
Descrição informal
Quando a avaliação de uma expressão começa, a expressão é carregada como o único elemento de controle C
. O ambiente E
, a pilha S
e o despejo D
começam vazios.
Durante a avaliação, C
ele é convertido para notação polonesa reversa (RPN) com ap
(para aplicar ) sendo o único operador. Por exemplo, a expressão F (G X)
(um único elemento da lista) é alterada para a lista X:G:ap:F:ap
.
Avaliação de C
procede de forma semelhante a outras expressões RPN. Se o primeiro item C
for um valor, ele será colocado na pilha S
. Mais exatamente, se o item for um identificador, o valor colocado na pilha será a ligação para esse identificador no ambiente atual E
. Se o item for uma abstração, um fechamento é construído para preservar as ligações de suas variáveis livres (que estão em E
), e é esse fechamento que é colocado na pilha.
Se o item for ap
, dois valores são retirados da pilha e a aplicação concluída (primeiro aplicado ao segundo). Se o resultado do aplicativo for um valor, ele será colocado na pilha.
Se o aplicativo for uma abstração para um valor, entretanto, resultará em uma expressão de cálculo lambda que pode ser um aplicativo (em vez de um valor) e, portanto, não pode ser colocado na pilha. Nesse caso, o conteúdo atual de S
, E
e C
é enviado para o dump D
(que é uma pilha desses triplos), S
é reinicializado para vazio e C
é reinicializado para o resultado do aplicativo E
contendo o ambiente para as variáveis livres desta expressão, aumentada com a ligação que resultou do aplicativo. A avaliação então prossegue como acima.
A avaliação concluída é indicada por C
estar vazia, caso em que o resultado ficará na pilha S
. O último estado de avaliação salvo em D
é então exibido e o resultado da avaliação concluída é enviado para o conteúdo da pilha restaurado D
. A avaliação do estado restaurado continua como acima.
Se C
e D
estiverem vazios, a avaliação geral foi concluída com o resultado na pilha S
.
Registros e memória
A máquina SECD é baseada em pilha . As funções obtêm seus argumentos da pilha. Os argumentos para as instruções integradas são codificados imediatamente após eles no fluxo de instruções.
Como todos os dados-estruturas internas, a pilha é uma lista, com o S
registo apontando para o de lista cabeça ou começando. Devido à estrutura da lista, a pilha não precisa ser um bloco contínuo de memória, portanto, o espaço da pilha está disponível enquanto houver uma única célula de memória livre. Mesmo quando todas as células foram usadas, a coleta de lixo pode render memória livre adicional. Obviamente, implementações específicas da estrutura SECD podem implementar a pilha como uma estrutura de pilha canônica, melhorando assim a eficiência geral da máquina virtual, desde que um limite estrito seja colocado na dimensão da pilha.
O C
registro aponta para o cabeçalho do código ou lista de instruções que será avaliada. Uma vez que a instrução foi executada, o C
é apontado para a próxima instrução na lista - é semelhante a um ponteiro de instrução (ou contador de programa ) em máquinas convencionais, exceto que as instruções subsequentes são sempre especificadas durante a execução e não estão contidas por padrão em locais de memória subsequentes, como é o caso das máquinas convencionais.
O ambiente de variável atual é gerenciado pelo E
registro, que aponta para uma lista de listas. Cada lista individual representa um nível de ambiente: os parâmetros da função atual estão no topo da lista, as variáveis que estão livres na função atual, mas vinculadas por uma função circundante, estão em outros elementos de E
.
O dump, em cujo topo o D
registrador aponta, é usado como armazenamento temporário para valores de outros registradores, por exemplo, durante chamadas de função. Pode ser comparado à pilha de retorno de outras máquinas.
A organização da memória da máquina SECD é semelhante ao modelo usado pela maioria dos intérpretes de linguagem funcional : um número de células de memória, cada uma das quais pode conter um átomo (um valor simples, por exemplo 13 ), ou representar um vazio ou não lista vazia. No último caso, a célula contém dois ponteiros para outras células, um representando o primeiro elemento, o outro representando a lista, exceto para o primeiro elemento. Os dois ponteiros são tradicionalmente chamados de carro e cdr, respectivamente - mas os termos mais modernos cabeça e cauda costumam ser usados. Os diferentes tipos de valores que uma célula pode conter são diferenciados por uma tag . Freqüentemente, diferentes tipos de átomos (inteiros, strings, etc.) também são diferenciados.
Portanto, uma lista contendo os números 1 , 2 e 3 , geralmente escrita como (1 2 3)
, pode ser representada da seguinte forma:
Address Tag Content (value for integers, car & cdr for lists) 9 [ integer | 2 ] 8 [ integer | 3 ] 7 [ list | 8 | 0 ] 6 [ list | 9 | 7 ] ... 2 [ list | 1 | 6 ] 1 [ integer | 1 ] 0 [ nil ]
As células de memória 3 a 5 não pertencem à nossa lista, cujas células podem ser distribuídas aleatoriamente pela memória. A célula 2 é o topo da lista, ela aponta para a célula 1, que contém o valor do primeiro elemento, e a lista contendo apenas 2 e 3 (começando na célula 6). A célula 6 aponta para uma célula contendo 2 e para a célula 7, que representa a lista contendo apenas 3 . Ele faz isso apontando para a célula 8 que contém o valor 3 e apontando para uma lista vazia ( nil ) como cdr. Na máquina SECD, a célula 0 sempre representa implicitamente a lista vazia, portanto, nenhum valor de tag especial é necessário para sinalizar uma lista vazia (tudo que precisa pode simplesmente apontar para a célula 0).
O princípio de que o cdr em uma célula de lista deve apontar para outra lista é apenas uma convenção. Se carro e cdr apontarem para átomos, isso produzirá um par, geralmente escrito como(1 . 2)
Instruções
-
nil
empurra um ponteiro nulo para a pilha -
ldc
coloca um argumento constante na pilha -
ld
coloca o valor de uma variável na pilha. A variável é indicada pelo argumento, um par. O carro do par especifica o nível e o cdr a posição. Então(1 . 3)
dá (nível 1) terceiro parâmetro da função atual. -
sel
espera dois argumentos de lista e retira um valor da pilha. A primeira lista é executada se o valor exibido não for nulo, a segunda lista caso contrário. Antes que um desses ponteiros de lista seja transformado em novoC
, um ponteiro para a seguinte instrução é salvo no dump. -
join
exibe uma referência de lista do dump e torna este o novo valor deC
. Esta instrução ocorre no final de ambas as alternativas de asel
. -
ldf
recebe um argumento de lista que representa uma função. Ele constrói um encerramento (um par contendo a função e o ambiente atual) e o coloca na pilha. -
ap
exibe um fechamento e uma lista de valores de parâmetro da pilha. O fechamento é aplicado aos parâmetros instalando seu ambiente como o atual, empurrando a lista de parâmetros na frente dele, limpando a pilha e configurandoC
para o ponteiro de função do fechamento. Os valores anteriores deS
,E
e o próximo valor deC
são salvos no dump. -
ret
retira um valor de retorno da pilha, restauraS
,E
eC
do despejo e empurra o valor de retorno para a pilha atual. -
dum
empurra um "dummy", uma lista vazia, na frente da lista de ambiente. -
rap
funciona como , apenas que substitui uma ocorrência de um ambiente fictício pelo atual, tornando assim possíveis funções recursivas
Existem várias instruções adicionais para funções básicas como carro, cdr, construção de lista, adição de inteiro, E / S, etc. Todos eles pegam todos os parâmetros necessários da pilha.
Veja também
Referências
Leitura adicional
- Danvy, Olivier . Uma desconstrução racional da máquina SECD de Landin . Relatório de pesquisa BRICS RS-04-30, 2004. ISSN 0909-0878
- Field, Anthony J. Field e Peter G. Harrison. 1988 Functional Programming . Addison-Wesley. ISBN 0-201-19249-7
- Graham, Brian T. 1992 "The SECD Microprocessor: A Verification Case Study". Springer. ISBN 0-7923-9245-0
- Kogge, Peter M. A Arquitetura dos Computadores Simbólicos . ISBN 0-07-035596-7
- Landin, PJ (março de 1966). "As próximas 700 linguagens de programação" (PDF) . Com. ACM . 9 (3): 157–166. doi : 10.1145 / 365230.365257 .