Quando alguém escreve uma nova linguagem de programação, em que a escreve?


162

Por favor, desculpe minha ignorância. Estou mexendo no PHP e me molhando navegando SO e me sinto compelido a fazer uma pergunta que venho pensando há anos:

Quando você escreve uma linguagem de programação totalmente nova, em que a escreve ?

Provavelmente isso soa muito bobo para todos os programadores, por quem eu tenho um enorme respeito, mas é uma coisa desconcertante para mim. O que você faz? Diga para si mesmo Hoje vou inventar um novo idioma! e depois acender ... Bloco de Notas? Todos os compiladores são construídos com linguagens existentes anteriormente, de modo a incomodar alguém que possa mapear todas as linguagens de programação já criadas em uma árvore ramificada monstruosa que eventualmente se baseia em ... Não sei, algo antigo?

Com meu intelecto débil, acho isso fascinante ... Por favor, me eduque!

Respostas:


193

Não é uma pergunta estúpida. É uma excelente pergunta.

Como já foi respondida, a resposta curta é "Outro idioma".

Bem, isso leva a algumas perguntas interessantes? E se for o primeiro idioma escrito para o seu hardware específico? Um problema muito real para pessoas que trabalham em dispositivos incorporados. Como já respondeu "um idioma em outro computador". De fato, alguns dispositivos incorporados nunca terão um compilador, seus programas sempre serão compilados em um computador diferente.

Mas você pode empurrá-lo para trás ainda mais. E os primeiros programas já escritos?

Bem, os primeiros compiladores para "linguagens de alto nível" teriam sido escritos no que é chamado de "linguagem assembly". A linguagem Assembly é uma linguagem em que cada instrução no idioma corresponde a uma única instrução para a CPU. Sua linguagem de nível muito baixo e extremamente detalhada e muito trabalhosa para escrever.

Mas mesmo a escrita da linguagem assembly requer um programa chamado assembler para converter a linguagem assembly em "linguagem de máquina". Voltaremos mais. Os primeiros montadores foram escritos em "código de máquina". Um programa que consiste inteiramente de números binários que são uma correspondência direta direta com o idioma bruto do próprio computador.

Mas ainda não acaba. Mesmo um arquivo com apenas números brutos ainda precisa ser traduzido. Você ainda precisa inserir esses números brutos em um arquivo no computador.

Bem, acredite ou não, os primeiros computadores tinham uma linha de switches na frente deles. Você acionou os comutadores até que eles representassem um número binário, depois acionou outro comutador e carregou esse número único na memória do computador. Em seguida, você continuou alternando até carregar um programa de computador mínimo, capaz de ler programas de arquivos em disco ou cartões perfurados. Você apertou outro botão e o programa foi iniciado. Quando fui para a universidade, nos anos 80, vi computadores que tinham essa capacidade, mas nunca receberam o trabalho de carregar um programa com os comutadores.

E mesmo antes disso, os programas de computador precisavam ser conectados com placas de tomada !


20
+1, acho que essa resposta realmente se encaixa no espírito da pergunta.
stderr

30
Certa vez, fiz uma aula de Assembler II e o professor perguntou por que escolhemos a eletiva. Eu fui para a resposta engraçada: "porque eu queria um fácil A." Achei que eu tinha a melhor resposta, mas tínhamos uma fábrica da Honeywell na cidade e o cara seguinte disse: "Eu escrevo microcódigo o dia todo e queria aprender um idioma de alto nível".
T.Rob

3
Eu recomendo o Code: O idioma oculto do hardware e software do computador . Ele cobre essencialmente o mesmo material que esta resposta, desde tubos de vácuo até compiladores para linguagens de alto nível.
MatrixFrog #

Os computadores evoluíram exatamente como os seres humanos, embora em uma quantidade comparativamente infinitesimal de tempo.
Gaurav Ojha 21/10

Agora isso vai ser um comentário não-construtiva, mas tem de ser escrito ... esta é uma brilhante resposta brilhante em todas as formas, formulários e informações :-)
Lukáš Radek

23

A resposta mais comum é C. A maioria dos idiomas é implementada em C ou em um híbrido de C com retornos de chamada e um "lexer" como Flex e um gerador de analisador como YACC . Esses são os idiomas usados ​​para uma finalidade - descrever a sintaxe de outro idioma. Às vezes, quando se trata de idiomas compilados, eles são implementados primeiro em C. Em seguida, a primeira versão do idioma é usada para criar uma nova versão, e assim por diante. (Como Haskell .)


1
Alguns idiomas são escritos em assembler, como picolisp. ( blog.kowalczyk.info/article/picoLisp-Arc-before-Arc.html )
Prof. Falken

1
E os programas lex / yacc (flex / bison)? Estes são considerados suplementos para a criação de idiomas em C?
Dave

1
Você tem alguma coisa para provar que a resposta mais comum é C?
21410 RichardOD

Comecei a examinar a lista aqui: google.com/Top/Computers/Programming/Languages/Open_Source Então fechei acidentalmente a janela do meu editor no idioma 10 e perdi a motivação para continuar. De qualquer forma, cerca da metade até o momento foi implementada em C e o restante, na maioria das vezes, inicializando elas mesmas.
Falken

3
Eu acho que você tem que mencionar Lex / Yacc (ou alternativas). Geralmente, não se começa a escrever uma linguagem em C, mas com um lexer e um analisador, que são então suportados pelo código C.
21810 Steve

14

Muitos idiomas são iniciados - escritos por si mesmos . Quanto ao motivo pelo qual você gostaria de fazer isso, geralmente é uma boa idéia comer seu próprio alimento para cães .

O artigo da wikipedia a que me refiro discute a questão do frango e do ovo . Eu acho que você achará bastante interessante.


5
O que não é possível quando você está apenas começando.
22640 Michael Borgwardt

1
Sim, obviamente. Mas muitos idiomas são escritos dessa maneira, uma vez que é possível. Eu queria salientar isso como ninguém mais tinha, e acho que é um ponto importante.
21410 RichardOD

+1 para usar o termo autoinicialização. É interessante que você precise compilar seu compilador duas vezes. A primeira vez é obviamente com o compilador básico que você possui e a segunda com o compilador que você acabou de criar. Digamos que você adicionou otimização ao seu compilador. O compilador que você criou pode produzir código com essas otimizações, mas ele não está executando o código otimizado até que você o compile novamente com o compilador de otimização.
Les

@ Les- Sim, o bootstrapping é um conceito interessante.
`` #

2
Comentário aleatório aqui. A resposta para a pergunta antiga sobre quem veio primeiro (a galinha ou o ovo) é que a galinha veio primeiro. A razão é que, para reproduzir / replicar algo, você deve primeiro ter o reprodutor / replicador já instalado para executar a reprodução / replicação.
SpicyWeenie

10

Praticamente qualquer idioma, embora o uso de um adequado para trabalhar com gráficos e outras estruturas de dados complexas facilite muitas coisas. Os compiladores de produção geralmente são escritos em C ou C ++ por motivos de desempenho, mas linguagens como OCaml, SML, Prolog e Lisp são sem dúvida melhores para a prototipagem da linguagem.

Também existem vários "pequenos idiomas" usados ​​no design de idiomas. Lex e yacc são usados ​​para especificar sintaxe e gramáticas, por exemplo, e são compilados em C. (Existem portas para outros idiomas, como ocamllex / ocamlyacc, e muitas outras ferramentas similares).

Como um caso especial, os novos dialetos Lisp geralmente são criados nas implementações existentes do Lisp, pois podem pegar carona na maioria da mesma infraestrutura. Escrever um intérprete de esquema pode ser feito no esquema em uma página de código, quando é possível adicionar facilmente novos recursos.

Fundamentalmente, compiladores são apenas programas que lêem algo e o traduzem para outro - convertendo a fonte LaTeX em DVI, convertendo código C em assembly e depois em linguagem de máquina, convertendo uma especificação gramatical em código C para um analisador, etc. Seu designer especifica a estrutura do formato de origem (análise), o que essas estruturas significam, como simplificar os dados (otimização) e o tipo de saída a ser gerada. Os intérpretes leem a fonte e a executam diretamente. (Os intérpretes geralmente são mais simples de escrever, mas muito mais lentos.)


4

Na verdade, você pode escrever em quase qualquer idioma que desejar. Não há nada que impeça você de escrever um compilador C em Ruby. "Tudo" que você precisa fazer é analisar o programa e emitir o código de máquina correspondente. Se você pode ler / gravar arquivos, sua linguagem de programação provavelmente será suficiente.

Se você estiver começando do zero em uma nova plataforma, poderá fazer a compilação cruzada: escreva um compilador para sua nova plataforma, executada em Java ou nativamente no x86. Desenvolva no seu PC e transfira o programa para sua nova plataforma de destino.

Os compiladores mais básicos são provavelmente Assembler e C.


Esse idioma "qualquer" deve, no entanto, suportar chamadas recursivas. Caso contrário, implementar um analisador de sintaxe e um analisador será um verdadeiro desafio.

2
Se você selecionar um idioma inadequado para uma tarefa, a culpa será sua. Isso pode acontecer para qualquer projeto, não apenas para compiladores / intérpretes.
ziggystar

4

"Escrever uma nova linguagem de programação" tecnicamente não envolve nenhum código. Está apenas chegando com uma especificação de como é o seu idioma e como ele funciona. Depois de ter uma idéia de como é o seu idioma, você pode escrever tradutores e intérpretes para realmente fazer o seu idioma "funcionar".

Um tradutor insere um programa em um idioma e gera um programa equivalente em outro idioma. Um intérprete insere um programa em algum idioma e o executa.

Por exemplo, um compilador C normalmente traduz o código-fonte C (o idioma de entrada) para um programa em linguagem assembly (o idioma de saída). O assembler pega o programa de linguagem assembly e produz a linguagem de máquina. Depois de obter sua saída, você não precisa dos tradutores para executar seu programa. Como agora você possui um programa de linguagem de máquina, a CPU atua como intérprete.

Muitos idiomas são implementados de maneira diferente. Por exemplo, javacé um tradutor que converte o código-fonte Java em bytecode da JVM. A JVM é um intérprete [1] que executa o bytecode Java. Depois de executar javace obter o bytecode, você não precisa javacmais. No entanto, sempre que você quiser executar seu programa, precisará da JVM.

O fato de que os tradutores não precisam ser mantidos por perto para executar um programa é o que torna possível "inicializar" seu idioma sem que ele acabe sendo executado "em cima de" camadas e camadas de outros idiomas.

[1] A maioria das JVMs faz tradução nos bastidores, mas na verdade não são tradutores, pois a interface da JVM não é "idioma de entrada -> idioma de saída".


3

Geralmente você pode usar praticamente qualquer idioma que desejar. O PHP foi escrito em C, por exemplo. Se você não tiver acesso a nenhum compilador, precisará recorrer à linguagem assembly e compilá-la manualmente em código de máquina.


2
Você não precisa compilar o código da máquina. é o idioma nativo da CPU, por definição.
Stu Thompson

1
Verdade. O que eu quis dizer foi "compilar o código da máquina a partir da linguagem assembly ou algo semelhante à mão". Eu posso estar errado, mas acho que poucas pessoas digitam o código como binário / hexadecimal imediatamente.
27709 Kaivosukeltaja

2

Muitas linguagens foram escritas primeiro em outra linguagem disponível e depois reimplementadas em si mesmas e inicializadas dessa maneira (ou apenas mantiveram a implementação na linguagem estrangeira, como PHP e perl), mas algumas linguagens, como o primeiro assembler, foram compiladas manualmente em código de máquina como o primeiro compilador C foi compilado manualmente para montagem.

Eu tenho interesse em iniciar desde que li sobre isso. Para saber mais, tentei fazer isso sozinho escrevendo meu próprio superconjunto de BF, que eu chamei de EBF . a primeira versão do EBF tinha 3 primitivos extras e eu compilei manualmente o primeiro binário. Eu encontrei um ritmo de duas etapas ao fazê-lo. Eu implementei um recurso no idioma atual em uma versão e tive uma versão agradável, onde reescrevi o código para utilizar a funcionalidade implementada. A linguagem era expressiva o suficiente para ser usada para criar um intérprete LISP .

Eu tenho a versão compilada manualmente junto com a fonte na primeira tag de lançamento e o código é bem pequeno. A última versão é 12 vezes maior em tamanho e código e permite um código mais compacto, portanto, seria difícil acertar a compilação manual da versão atual.

Edmund Grimley Evans fez algo semelhante com sua linguagem HEX

Uma das coisas interessantes de se fazer isso é que você entende por que algumas coisas são como são. Meu código era produto se pequenos ajustes incrementais e parecia mais evoluir ao invés de ter sido projetado do zero. Eu mantenho isso em mente ao ler o código hoje, o que acho um pouco estranho.


1

Geralmente, com uma linguagem de programação de uso geral adequada para o desenvolvimento de sistemas, por exemplo, C, Haskell, ML, Lisp, etc., mas a lista de opções é longa. Além disso, geralmente com algumas linguagens específicas de domínio para implementação de linguagem, por exemplo, geradores de analisador e analisador lexical, linguagens intermediárias como LLVM , etc. E provavelmente alguns scripts de shell, estruturas de teste e um sistema de configuração de compilação, por exemplo, autoconf.


1

A maioria dos compiladores foram escritos em C ou AC, como programa, se não c, então assembly lang é o caminho a seguir. No entanto, ao escrever uma nova linguagem do zero e você não possui uma lib macro ou código fonte de uma linguagem de protótipo, é necessário definir suas próprias funções Agora em que idioma? Você pode simplesmente escrever um formulário "do código-fonte chamado psedocode na máquina, que se parece com uma gramática bnf das especificações lang estruturadas orientadas a objetos, como Fortran basic algo lisp. Então, a imagem escrevendo um código cruzado semelhante a qualquer uma dessas sintaxes da linguagem. É código psedo


1
Eu não acredito código psedo é suposto ser legível por máquina
Richard Tingle

0

Operações binárias ou de montagem ainda mais devem ser convertidas em funções, que é o trabalho de montadores / compiladores e, em seguida, em objeto, a partir de dados e funções, se você não tiver um arquivo de origem para ver "como a funcionalidade desses objetos deve ser representada no seu implementação de linguagem, Então você precisa reconhecer "ver" implementar ou definir suas próprias funções, procedimentos e estruturas de dados. O que requer muito conhecimento, você precisa se perguntar o que é uma função. Sua mente se torna a simulação de linguagem. Isso separa um programador mestre do resto.


0

Eu também tive essa pergunta alguns meses atrás. E li alguns artigos e assisti a alguns vídeos que me ajudaram a começar a escrever minha própria linguagem chamada soft. Ainda não está completo, mas aprendi muitas coisas nessa jornada.

O básico que você deve saber é como o compilador funciona quando ele precisa executar um trecho de código. O compilador possui muitas fases, como análise lexical, analisador semântico, AST (Abstract Syntax Tree) etc.

O que fiz no meu novo idioma pode ser encontrado aqui - http://www.singhajit.com/writing-a-new-programming-language/

Se você está escrevendo um idioma pela primeira vez, tudo de bom e você tem um longo caminho a percorrer.


0

O que são linguagens de programação em geral?

linguagens de programação são apenas uma maneira de conversar com computadores. grosso modo, a princípio, porque os computadores só conseguiam entender zeros e uns (devido ao fato de os computadores serem feitos de transistores como comutadores, que podiam apenas levar dois estados, chamamos esses dois estados de 0 e 1) e trabalhar com 0,1 era difícil para como seres humanos, os cientistas da computação decidiram fazer um mapeamento individual de todas as instruções em binário (0,1) para uma forma mais legível para humanos, que eles chamavam de linguagem assembly.

por exemplo, se tivéssemos uma instrução como:

11001101

na montagem seria chamado:

LOAD_A 15

o que significa que carregar o conteúdo de registrar um na localização da memória 15. Como eu disse, era apenas uma convenção como escolher 0 e 1 para dois estados dos transistores ou qualquer outra coisa no computador. dessa maneira, tendo um programa com 50 instruções, lembrar a linguagem assembly seria mais fácil. para que o usuário escreva o código do assembly e algum programa (neste caso o assembler) traduza os códigos para instruções binárias ou linguagem de máquina, como eles chamam.

mas, com os computadores sendo aprimorados todos os dias, havia espaço para programas mais complicados com mais instruções, digamos 10000.

nesse caso, um mapeamento individual como um assembly não funcionaria; portanto, outras linguagens de programação de alto nível foram criadas. eles disseram, por exemplo, se para uma relação com dispositivos de E / S para imprimir algo na tela criada pelo usuário, são necessárias cerca de 80 instruções, vamos fazer algo aqui e poderíamos empacotar todo esse código em uma biblioteca e chamá-lo, por exemplo, printf e também crie outro programa que possa traduzir esse printf aqui para o código de assembly relacionado e a partir daí o assembly fará o resto. então eles chamam de compilador.

agora, todo usuário que deseja apenas imprimir algo na tela, não precisa escrever todas as instruções em binário ou montagem, apenas digita printf ("something") e todos os programas, como o compilador e o montador, fazem o resto. agora, mais tarde, outros códigos mais longos seriam empacotados da mesma maneira para facilitar o trabalho de outras pessoas, pois você pode simplificar uma linha de milhares de códigos em um código em python e empacotá-lo para o uso de outras pessoas.

então digamos que você empacotou muitos códigos diferentes em python e criou um módulo (biblioteca, pacote ou qualquer coisa que você queira chamar) e você chamou esse módulo mgh (apenas meu nome). Agora, digamos que criamos esse mgh de alguma forma que qualquer um que diga:

import mgh
mgh.connect(ip,port.data)...

poderia conectar-se facilmente a um servidor remoto com o número de IP e porta especificado e enviar os dados posteriormente (ou algo assim). agora as pessoas podem fazer tudo isso usando uma única linha, mas o que acontece é que muitos códigos estão sendo executados, que foram recuperados do arquivo mgh. e empacotá-lo não foi para acelerar o processo de execução, mas para facilitar o trabalho de outros programadores. então aqui, se alguém quiser usar seu código primeiro, ele deve importar o arquivo e, em seguida, o intérprete python reconhecerá todo o código nele e assim poderá interpretá-lo.

Agora, se você deseja criar uma linguagem de programação e executá-la, primeiro ela precisa de uma tradução. Por exemplo, digamos que você crie um programa que possa entender a sintaxe e convertê-lo em c, neste caso após a tradução. para c, o resto seria resolvido pelo compilador c, depois pelo assembler, vinculador, .... mesmo que você tenha que pagar o preço de ser mais lento, pois ele deve ser convertido em c primeiro.

Agora, outra coisa que você pode fazer é criar um programa que traduza todo o código para a linguagem assembly equivalente, exatamente como acontece com c, mas, neste caso, o programa poderá fazê-lo diretamente e a partir daí o resto será feito pelo vinculador. sabemos que esse programa é chamado de compilador.

Então, o que eu estou falando é que, o único código que o sistema entende é 0,1, então de alguma forma você deve converter sua sintaxe para isso, agora em nossos sistemas operacionais muitos programas diferentes como assembler, linker e ... foi criado para dizer que, se você pudesse converter seu código em assembly, eles poderiam cuidar do resto ou, como eu disse, você poderia usar outros compiladores de linguagens de programação convertendo seu código para esse idioma.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.