Já ouvi falar da ideia de inicializar uma linguagem, ou seja, escrever um compilador / interpretador para a própria linguagem. Fiquei me perguntando como isso poderia ser feito e olhei em volta um pouco, e vi alguém dizer que só poderia ser feito por qualquer um
- escrever um compilador inicial em uma linguagem diferente.
- codificar manualmente um compilador inicial em Assembly, que parece um caso especial do primeiro
Para mim, nenhum desses parece estar realmente iniciando uma linguagem no sentido de que ambos requerem suporte externo. Existe uma maneira de realmente escrever um compilador em sua própria linguagem?
Respostas:
Você tem que ter algum idioma existente para escrever seu novo compilador. Se você estivesse escrevendo um compilador novo, digamos, C ++, você teria apenas escrevê-lo em C ++ e compilá-lo com um compilador existente em primeiro lugar. Por outro lado, se você estiver criando um compilador para uma nova linguagem, vamos chamá-lo de Yazzleof, você precisará escrever o novo compilador em outra linguagem primeiro. Geralmente, essa seria outra linguagem de programação, mas não precisa ser. Pode ser conjunto ou, se necessário, código de máquina.
Se você fosse inicializar um compilador para Yazzleof, geralmente não escreveria um compilador para a linguagem completa inicialmente. Em vez disso, você escreveria um compilador para Yazzle-lite, o menor subconjunto possível do Yazzleof (bem, um subconjunto bem pequeno, pelo menos). Então, no Yazzle-lite, você escreveria um compilador para a linguagem completa. (Obviamente, isso pode ocorrer iterativamente em vez de em um salto.) Como o Yazzle-lite é um subconjunto apropriado do Yazzleof, agora você tem um compilador que pode se compilar.
Há um artigo realmente bom sobre como inicializar um compilador do nível mais baixo possível (que em uma máquina moderna é basicamente um editor hexadecimal), intitulado Bootstrapping a simple compililer from nothing . Ele pode ser encontrado em https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html .
fonte
A explicação que você leu está correta. Há uma discussão sobre isso em Compiladores: Princípios, Técnicas e Ferramentas (o Livro do Dragão):
fonte
Um super interessante discussão deste está em Unix co-criador Ken Thompson 's Turing Award palestra.
Ele começa com:
e continua mostrando como ele escreveu uma versão do compilador C do Unix que sempre permitiria que ele fizesse login sem uma senha, porque o compilador C reconheceria o programa de login e adicionaria um código especial.
fonte
Ouvi falar em escrever um compilador extremamente limitado em outra linguagem e, em seguida, usá-lo para compilar uma versão mais complicada, escrita na nova linguagem. Esta segunda versão pode então ser usada para compilar a si mesma e a próxima versão. Cada vez que é compilado, a última versão é usada.
Esta é a definição de bootstrapping:
EDIT: O artigo da Wikipedia sobre inicialização do compilador cobre o conceito melhor do que eu.
fonte
Confira o podcast do episódio 61 do Software Engineering Radio (06-07-2007), que discute a parte interna do compilador GCC, bem como o processo de bootstrapping do GCC.
fonte
Donald E. Knuth, na verdade, construiu a WEB escrevendo o compilador nela e, em seguida, compilou-a manualmente em assembly ou código de máquina.
fonte
Pelo que entendi, o primeiro interpretador Lisp foi inicializado compilando manualmente as funções do construtor e o leitor de token. O resto do intérprete foi lido da fonte.
Você pode verificar por si mesmo lendo o jornal McCarthy original, Funções recursiva de expressões simbólicas e seu cálculo por Máquina, Parte I .
fonte
Outra alternativa é criar uma máquina de bytecode para sua linguagem (ou usar uma existente se seus recursos não forem muito incomuns) e escrever um compilador para bytecode, seja no bytecode ou na linguagem desejada usando outro intermediário - como um kit de ferramentas do analisador que produz o AST como XML e, em seguida, compila o XML para bytecode usando XSLT (ou outra linguagem de correspondência de padrões e representação baseada em árvore). Isso não remove a dependência de outro idioma, mas pode significar que mais do trabalho de bootstrap acabará no sistema final.
fonte
É a versão da ciência da computação do paradoxo do ovo e da galinha. Não consigo pensar em uma maneira de não escrever o compilador inicial em assembler ou alguma outra linguagem. Se pudesse ter sido feito, eu deveria ter feito Lisp.
Na verdade, acho que Lisp quase se qualifica. Verifique sua entrada na Wikipedia . De acordo com o artigo, a função Lisp eval poderia ser implementada em um IBM 704 em código de máquina, com um compilador completo (escrito no próprio Lisp) surgindo em 1962 no MIT .
fonte
Todos os exemplos de bootstrap de uma linguagem que consigo pensar ( C , PyPy ) foram feitos depois que havia um compilador funcionando. Você tem que começar de algum lugar, e a reimplementação de uma linguagem em si exige a escrita de um compilador em outra linguagem primeiro.
De que outra forma isso funcionaria? Não acho que seja conceitualmente possível fazer o contrário.
fonte
Alguns compiladores ou sistemas bootstrapped mantêm a forma de origem e a forma de objeto em seu repositório:
ocaml é uma linguagem que possui um intérprete de bytecode (ou seja, um compilador para o bytecode Ocaml) e um compilador nativo (para x86-64 ou ARM, etc ... assembler). Seu repositório svn contém o código-fonte (arquivos
*/*.{ml,mli}
) e a forma bytecode (arquivoboot/ocamlc
) do compilador. Portanto, quando você constrói, ele primeiro usa seu bytecode (de uma versão anterior do compilador) para compilar a si mesmo. Mais tarde, o bytecode compilado recentemente é capaz de compilar o compilador nativo. Portanto, o repositório Ocaml svn contém os*.ml[i]
arquivos fonte e oboot/ocamlc
arquivo bytecode.Os ferrugem de downloads do compilador (usando
wget
, então você precisa de uma conexão com a internet) uma versão anterior do seu binário para compilar em si.MELT é uma linguagem semelhante a Lisp para personalizar e estender o GCC . Ele é traduzido para o código C ++ por um tradutor bootstrapped. O código C ++ gerado do tradutor é distribuído, portanto, o repositório svn contém os
*.melt
arquivos fonte e os arquivosmelt/generated/*.cc
"objeto" do tradutor.O sistema de inteligência artificial CAIA da J.Pitrat é totalmente autogerado. Ele está disponível como uma coleção de milhares de
[A-Z]*.c
arquivos gerados (também com umdx.h
arquivo de cabeçalho gerado ) com uma coleção de milhares de_[0-9]*
arquivos de dados.Vários compiladores Scheme também são inicializados. Esquema 48, Esquema de frango, ...
fonte