O primeiro compilador foi escrito por Grace Hopper em 1952, enquanto o intérprete Lisp foi escrito em 1958 pelo aluno de John McCarthy, Steve Russell. Escrever um compilador parece ser um problema muito mais difícil do que um intérprete. Se é assim, por que o primeiro compilador foi escrito seis anos antes do primeiro intérprete?
history
compiler
interpreters
anguyen
fonte
fonte
Respostas:
Isso pode ser verdade hoje, mas eu diria que não era o caso há 60 anos. Algumas razões pelas quais:
fonte
O ponto fundamental é que o ambiente de hardware de computação da década de 1950 tornou tal apenas um compilador viável, dado o processamento de computadores orientado a lotes.
Naquela época, as melhores interfaces de usuário eram limitadas principalmente a cartões perfurados e impressoras de teletipo . Em 1961, o sistema SAGE se tornou o primeiro monitor de tubo de raios catódicos (CRT) em um computador. Portanto, a natureza interativa de um intérprete não era preferível ou natural até muito mais tarde.
Numerosos computadores na década de 1950 usavam interruptores do painel frontal para carregar instruções, e a saída era simplesmente filas de lâmpadas / LEDs, e os amadores até usavam interruptores e LEDs do painel frontal na década de 1970. Talvez você esteja familiarizado com o infame Altair 8800 .
Outras limitações de hardware também inviabilizaram os intérpretes. Havia uma disponibilidade extremamente limitada de memória primária (por exemplo, RAM) em computadores na década de 1950. Antes do circuito integrado de semicondutores (que não veio até 1958), a memória era limitada à memória do núcleo magnético ou à memória da linha de atraso, medida em bits ou palavras , sem prefixo. Combinado com a lentidão da memória de armazenamento secundário (por exemplo, disco ou fita), seria considerado um desperdício, se não inviável, ter grande parte da memória usada para o intérprete, mesmo antes do carregamento do programa.
As limitações de memória ainda eram um fator importante quando o líder da equipe John Backus na IBM criou o compilador FORTRAN em 1954-57. Este compilador inovador foi bem-sucedido apenas porque era um compilador de otimização .
A maioria dos computadores na década de 1950 mal possuía um sistema operacional, sem falar em recursos modernos, como vínculo dinâmico e gerenciamento de memória virtual; portanto, a ideia de um intérprete era radical demais e impraticável na época.
Termo aditivo
As línguas da década de 1950 eram primitivas. Eles incluíam apenas um pequeno punhado de operações, muitas vezes influenciadas pelas instruções do hardware subjacente ou pela definição do problema do uso direcionado.
Naquela época, os computadores raramente eram computadores de uso geral no sentido em que pensamos nos computadores hoje. O fato de serem reprogramáveis sem a necessidade de reconstrução foi considerado um conceito revolucionário - anteriormente as pessoas usavam máquinas eletromecânicas (normalmente calculadoras) para calcular ou calcular respostas (a maioria das aplicações na década de 1950 era de natureza numérica).
Do ponto de vista da ciência da computação, compiladores e intérpretes são tradutores e têm aproximadamente a mesma complexidade em sua implementação.
fonte
As primeiras linguagens de programação eram bastante simples (sem recursão, por exemplo) e próximas à arquitetura da máquina, que por si só era simples. A tradução foi então um processo direto .
Um compilador era mais simples como um programa do que um intérprete que precisaria manter juntos os dados para a execução do programa e as tabelas para interpretar o código-fonte. E o intérprete ocuparia mais espaço , por si só, para o código-fonte do programa e para tabelas simbólicas.
A memória pode ser tão escassa (por razões de custo quanto de arquitetura) que os compiladores podem ser programas independentes que substituem o sistema operacional (usei um deles). O sistema operacional teve que ser recarregado após a compilação para executar o programa compilado. ... o que deixa claro que executar um intérprete para trabalho real simplesmente não era uma opção .
Para ser verdade, a simplicidade exigida dos compiladores era tal que os compiladores não eram muito bons (a otimização do código ainda estava na infância, quando considerada). O código de máquina escrito à mão tinha, pelo menos até o final dos anos sessenta em alguns lugares, a reputação de ser significativamente mais eficiente que o código gerado pelo compilador. Havia até um conceito de taxa de expansão de código que comparava o tamanho do código compilado ao trabalho de um programador muito bom. Geralmente era maior que 1 para a maioria dos compiladores (todos?), O que significava programas mais lentos e, muito mais importante, programas maiores que exigem mais memória. Isso ainda era um problema nos anos sessenta.
O interesse do compilador estava na facilidade de programação, especialmente para usuários que não eram especialistas em computação, como cientistas em vários campos. Esse interesse não era o desempenho do código. Mas, ainda assim, o tempo do programador era considerado um recurso barato. O custo foi no tempo do computador, até 1975-1980, quando o custo passou do hardware para o software. O que significa que mesmo o compilador não foi levado a sério por alguns profissionais .
O custo muito alto do tempo do computador foi mais um motivo para desqualificar os intérpretes , a tal ponto que a própria idéia teria sido ridícula para a maioria das pessoas.
O caso do Lisp é muito especial, porque era uma linguagem extremamente simples que o tornava viável (e o computador havia se tornado um pouco maior em 58). Mais importante, o intérprete Lisp era uma prova de conceito em relação à autodefinibilidade do Lisp ( meta-circularidade ), independentemente de qualquer questão de usabilidade.
O sucesso do Lisp é devido, em grande parte, ao fato de que essa autodefinibilidade o tornou um excelente banco de testes para estudar estruturas de programação e projetar novas linguagens (e também por sua conveniência para computação simbólica).
fonte
Eu discordo da premissa da pergunta.
O primeiro compilador do Adm. Hopper (o A-0) era mais como um vinculador ou uma linguagem macro. Ela armazenou sub-rotinas em uma fita (cada uma atribuiu um número) e seus programas seriam escritos como uma lista de sub-rotinas e argumentos. O compilador copiava as sub-rotinas solicitadas da fita e as reordena em um programa completo.
Ela usou a palavra "compilar" no mesmo sentido em que se compila uma antologia de poemas: coletando vários itens em um único volume.
Esse primeiro compilador não tinha um lexer ou analisador, tanto quanto posso dizer, o que o torna um ancestral distante de um compilador moderno. Mais tarde, ela criou outro compilador (o B-0, também conhecido como FLOW-MATIC) com o objetivo de uma sintaxe mais parecida com o inglês, mas não foi concluída até 1958 ou 1959 - na mesma época que o intérprete Lisp.
Portanto, acho que a pergunta em si está um pouco equivocada. Parece que compiladores e intérpretes co-evoluíram quase exatamente ao mesmo tempo, sem dúvida devido ao compartilhamento de idéias que teriam muitos cientistas pensando da mesma maneira naqueles dias.
Uma resposta melhor com citações aqui: https://stackoverflow.com/a/7719098/122763 .
fonte
A outra parte da equação é que os compiladores eram uma abstração de etapa acima de um montador. Primeiro, tivemos o código da máquina codificado. "Nós" éramos o montador. Cada salto e deslocamento, etc., eram calculados manualmente em hexadecimal (ou octal) e depois perfurados em fita ou cartões de papel. Então, quando as montadoras entraram em cena, foi uma enorme economia de tempo. O próximo passo foram os montadores de macro. Isso deu a capacidade de escrever uma macro que se expandisse em um conjunto de instruções da máquina. Então Fortran e Cobol foram um grande passo à frente. A falta de recursos (armazenamento, memória e ciclos de CPU) significava que os intérpretes de uso geral tinham que esperar o crescimento da tecnologia. A maioria dos primeiros intérpretes eram mecanismos de código de bytes (como Java ou CLR de hoje, mas com muito menos capacidade). O UCSD Pascal era uma linguagem muito popular (e rápida). O MS Basic era um mecanismo de código de bytes oculto.
Em termos de sobrecarga de instruções, dependia totalmente de qual processador estava sendo executado. A indústria passou por um grande tumulto entre RISC e CISC por um tempo. Eu, pessoalmente, escrevi assembler para IBM, Data General, Motorola, Intel (quando eles apareceram), TI e vários outros. Havia uma diferença bastante significativa nos conjuntos de instruções, registradores etc. que influenciaria o que era necessário para "interpretar" um código-p.
Como referência temporal, comecei a programar na companhia telefônica por volta de 1972.
fonte
Se você não está mantendo tudo na memória, o código compilado é muito mais rápido. Não se esqueça, que nesses tempos as funções estavam associadas ao código compilado. Se você não está compilando, não sabe de que funções precisará. Então, você está chamando funções de ... Ah, ainda não do disco, estamos no início dos 50 laços, mas dos cartões! Em tempo de execução!
Obviamente, é possível encontrar soluções alternativas, mas elas ainda não foram encontradas, pois os idiomas eram muito simples e não muito distantes do código da máquina. E compilar foi fácil e suficiente.
fonte
Antes da criação do primeiro compilador, as pessoas escreviam o código do assembler, o que era um enorme progresso em comparação com o código binário comum. Na época, havia um forte argumento de que o código compilado por um compilador seria menos eficiente que o código do assembler - naquele momento, a relação de (custo do computador) e (custo do programador) era muito, muito diferente da atual. Portanto, houve forte resistência contra os compiladores desse ponto de vista.
Mas os compiladores são muito mais eficientes que os intérpretes. Se você tivesse sugerido escrever um intérprete naquele momento, as pessoas pensariam que você é louco. Você pode imaginar comprar um computador de um milhão de dólares e depois desperdiçar 90% de seu poder para interpretar código?
fonte
Antes que um programa de loop possa ser interpretado, ele deve ser armazenado em uma mídia que pode ser lida repetidamente. Na maioria dos casos, o único meio adequado seria a RAM. Como o código normalmente é inserido em cartões perfurados que - para idiomas legíveis por humanos - provavelmente estão vazios, algum tipo de processamento deve ser executado no código antes que ele seja armazenado na RAM. Em muitos casos, processar o texto do cartão perfurado em um formato adequado para execução direta pelo processador não é realmente mais difícil do que processá-lo em um formato que possa ser tratado com eficiência por meio de um intérprete.
Observe que o objetivo dos primeiros compiladores não era produzir um arquivo de linguagem de montagem ou código de objeto em disco, mas terminar o código na RAM que estava pronto para ser executado. Isso é surpreendentemente fácil quando não há sistema operacional para atrapalhar. Um compilador pode gerar código começando em uma extremidade da memória e alocar variáveis e destinos de ramificação começando na outra. Se uma instrução estiver marcada com o rótulo "1234", o compilador armazenará na variável chamada "1234" uma instrução para pular para o endereço de geração de código atual, criando essa variável se ela não existir. Uma instrução "goto 1234" criará uma variável "1234" se ela não existir e, em seguida, saltará para a variável [que esperamos ter um salto para o local apropriado armazenado nela antes da execução da instrução].
goto
um rótulo que ainda não foi definido, pois sabe quando asgoto
compilações para onde vai pular - para uma variável. Essa pode não ser a maneira mais eficiente de gerar código, mas é adequada para os tamanhos de programas que os computadores deveriam manipular.fonte
Porque intérpretes precisam de compiladores para funcionar.
A afirmação acima não é realmente verdadeira. A rigor, você pode criar um intérprete sem nunca usar ou interagir com um compilador. Mas os resultados de fazer isso não se pareceriam muito com o que eu acho que você quer dizer com esses termos.
No sentido estrito, compiladores e intérpretes fazem coisas totalmente diferentes. Um compilador lê o texto de alguma fonte e o transforma em outro formato: linguagem assembly, código de máquina, outra linguagem de alto nível, estrutura de dados ou qualquer outra coisa. Enquanto isso, um intérprete recolhe algum tipo de estrutura de dados e executa instruções com base nela.
Atualmente, o que pensamos como um "compilador" é na verdade um compilador que foi emparelhado com um gerador de código : um programa que coleta dados de alguma fonte e gera código em algum formato com base no que vê. Esse é um uso bastante intuitivo para compiladores e foi uma das primeiras coisas para as quais os compiladores foram criados. Mas se você olhar de outra maneira, isso parece muito semelhante ao que um intérprete faz. Ele sempre gera código em vez de executar operações mais gerais, mas o princípio é o mesmo.
Se olharmos para o outro lado, um intérprete precisa obter seus dados de algum lugar . São apenas dados, para que você possa construí-lo da mesma maneira que qualquer outro tipo de dados. Como estamos falando de interpretação, parece natural que você possa construir seus dados com base nas instruções em um arquivo de texto. Mas, para fazer isso, você precisa ler algo no texto e criar sua estrutura de dados, e isso é um compilador . Ele está ligado ao intérprete em vez de a um gerador de código, mas é um compilador da mesma forma.
É por isso que os compiladores foram escritos primeiro. A idéia de interpretar estruturas de dados não era nova, mesmo quando os compiladores foram concebidos, mas os compiladores eram o "elo perdido" que permitia aos programadores construir essas estruturas a partir de texto.
fonte
Outro fator: quando os primeiros compiladores foram escritos, o custo do tempo da máquina era muito maior do que é agora. Os intérpretes usam muito mais tempo na máquina.
fonte