Quando qualcuno scrive un nuovo linguaggio di programmazione, in cosa lo scrivono?


162

Per favore, scusa la mia ignoranza. Mi diletto in PHP e mi sto bagnando i piedi navigando SO, e mi sento in dovere di fare una domanda che mi chiedo da anni:

Quando scrivi un linguaggio di programmazione completamente nuovo, in che cosa lo scrivi ?

Questo probabilmente suona davvero sciocco per tutti voi programmatori, per i quali ho un enorme rispetto, ma per me è una cosa imbarazzante di pollo e uova. cosa fai? Di 'a te stesso Oggi ho intenzione di inventare una nuova lingua! e poi accendi ... Blocco note? Tutti i compilatori sono costruiti su linguaggi precedentemente esistenti, in modo tale da disturbare uno che potesse tracciare tutti i linguaggi di programmazione mai concepiti su un mostruoso albero ramificato che alla fine è sorto a ... Non so, qualcosa di vecchio?

Con il mio debole intelletto, trovo questo affascinante ... Per favore, educami!

Risposte:


193

Non è una domanda stupida. È un'ottima domanda.

Come già risposto, la risposta breve è "Un'altra lingua".

Bene, questo porta ad alcune domande interessanti? E se fosse la prima lingua scritta per il tuo particolare hardware? Un vero problema per le persone che lavorano su dispositivi integrati. Come già risposto "una lingua su un altro computer". In effetti alcuni dispositivi embedded non avranno mai un compilatore, i loro programmi saranno sempre compilati su un altro computer.

Ma puoi respingerlo ancora di più. E i primi programmi mai scritti?

Bene, i primi compilatori per "linguaggi di alto livello" sarebbero stati scritti in quello che si chiama "linguaggio assembly". Il linguaggio assembly è un linguaggio in cui ogni istruzione nella lingua corrisponde a una singola istruzione per la CPU. Il suo linguaggio di livello molto basso ed estremamente prolisso e molto laborioso per scrivere.

Ma anche la scrittura del linguaggio assembly richiede un programma chiamato assembler per convertire il linguaggio assembly in "linguaggio macchina". Torniamo oltre. I primissimi assemblatori furono scritti in "codice macchina". Un programma costituito interamente da numeri binari che sono una corrispondenza diretta diretta con la lingua grezza del computer stesso.

Ma non finisce ancora. Anche un file con solo numeri non elaborati deve ancora essere tradotto. Hai ancora bisogno di ottenere quei numeri grezzi in un file nel computer.

Beh, che ci crediate o no, i primi computer avevano una fila di interruttori sul davanti. Hai premuto gli interruttori finché non rappresentavano un numero binario, quindi hai premuto un altro interruttore e questo ha caricato quel singolo numero nella memoria del computer. Quindi hai continuato a sfogliare fino a quando non hai caricato un programma per computer minimo in grado di leggere programmi da file su disco o schede perforate. Hai premuto un altro interruttore e ha avviato il programma in esecuzione. Quando andai all'università negli anni '80 vidi dei computer che avevano quella capacità ma che non ricevettero mai il compito di caricare un programma con gli switch.

E prima ancora che i programmi per computer dovevano essere cablati con schede plug !


20
+1, penso che questa risposta si adatti davvero allo spirito della domanda.
stderr,

30
Una volta ho preso un corso di Assembler II e il prof mi ha chiesto perché abbiamo scelto l'elettivo. Ho cercato la risposta divertente: "perché volevo una facile A." Pensavo di avere la risposta migliore, ma avevamo una pianta Honeywell in città e il ragazzo successivo disse "Scrivo microcodice tutto il giorno e volevo imparare una lingua di alto livello".
T.Rob

3
Consiglio vivamente Code: The Hidden Language of Computer Hardware and Software . Copre essenzialmente lo stesso materiale di questa risposta, dai tubi a vuoto fino ai compilatori per linguaggi di alto livello.
MatrixFrog

I computer si sono evoluti esattamente come gli esseri umani, anche se in un tempo relativamente infinitesimale.
Gaurav Ojha,

Ora questo sarà un commento non costruttivo, ma deve essere scritto ... questa è una risposta brillante e brillante in tutte le forme, forme e informazioni :-)
Lukáš Řádek

23

La risposta più comune è C. La maggior parte dei linguaggi sono implementati in C o in un ibrido di C con callback e un "lexer" come Flex e un generatore di parser come YACC . Queste sono lingue utilizzate per uno scopo: descrivere la sintassi di un'altra lingua. A volte, quando si tratta di lingue compilate, vengono prima implementate in C. Quindi la prima versione della lingua viene utilizzata per creare una nuova versione e così via. (Come Haskell .)


1
Alcune lingue sono scritte in assemblatore, come picolisp. ( blog.kowalczyk.info/article/picoLisp-Arc-before-Arc.html )
Prof. Falken,

1
E i programmi lex / yacc (flex / bison)? Questi sono considerati integratori per la creazione di lingue in C?
Dave,

1
Hai qualcosa per dimostrare che la risposta più comune è C?
RichardOD,

Ho iniziato a consultare l'elenco qui: google.com/Top/Computers/Programming/Languages/Open_Source Poi ho accidentalmente chiuso la finestra dell'editor in circa la lingua 10 e ho perso la motivazione per passare. Ad ogni modo, circa la metà finora è stata implementata in C e il resto principalmente bootstrap a se stessi.
Prof. Falken,

3
Penso che devi menzionare Lex / Yacc (o alternative). Generalmente non si inizia a scrivere una lingua in C, ma piuttosto con un lexer e un parser che sono quindi supportati con il codice C.
Steve Rowe,

14

Molte lingue sono avviate, ovvero scritte in se stesse . Per quanto riguarda il motivo per cui vorresti farlo, è spesso una buona idea mangiare il tuo cibo per cani .

L'articolo di Wikipedia a cui mi riferisco parla della questione del pollo e delle uova . Penso che lo troverai abbastanza interessante.


5
Ciò non è possibile quando hai appena iniziato.
Michael Borgwardt,

1
Sì, ovviamente. Ma molte lingue sono scritte in questo modo una volta che è possibile. Volevo evidenziarlo come nessun altro, e penso che sia un punto importante.
RichardOD,

+1 per l'utilizzo del termine bootstrap. È interessante compilare il compilatore due volte. La prima volta è ovviamente con il compilatore bare-bones che hai e la seconda volta con il compilatore che hai appena creato. Supponiamo che tu abbia aggiunto l'ottimizzazione al tuo compilatore. Il compilatore che hai creato può produrre codice con quelle ottimizzazioni, ma non esegue esso stesso il codice ottimizzato fino a quando non lo compili nuovamente con il compilatore ottimizzatore.
Les

@ Les- Sì il bootstrap è un concetto interessante.
RichardOD,

2
Commento casuale qui. La risposta alla domanda secolare su chi è venuto per primo (pollo o uovo) è che il pollo è arrivato per primo. Il motivo è che per riprodurre / replicare qualcosa, devi prima avere il riproduttore / replicatore già in atto per eseguire la riproduzione / replica.
SpicyWeenie

10

Praticamente qualsiasi linguaggio, anche se usarne uno adatto a lavorare con grafici e altre strutture di dati complessi renderà molte cose più facili. I compilatori di produzione sono spesso scritti in C o C ++ per motivi di prestazioni, ma linguaggi come OCaml, SML, Prolog e Lisp sono probabilmente migliori per la prototipazione del linguaggio.

Esistono anche diverse "piccole lingue" utilizzate nella progettazione linguistica. Lex e yacc sono usati per specificare sintassi e grammatiche, per esempio, e si compilano in C. (Ci sono porte per altre lingue, come ocamllex / ocamlyacc e molti altri strumenti simili.)

Come caso speciale, i nuovi dialetti Lisp sono spesso basati su implementazioni Lisp esistenti, poiché possono trasferire sulla maggior parte della stessa infrastruttura. La scrittura di un interprete Scheme può essere eseguita in Scheme in una pagina di codice, a quel punto si possono facilmente aggiungere nuove funzionalità.

Fondamentalmente, i compilatori sono solo programmi che leggono qualcosa e lo traducono in qualcos'altro: convertire il sorgente LaTeX in DVI, convertire il codice C in assembly e quindi in linguaggio macchina, convertire una specifica grammaticale in codice C per un parser, ecc. Il suo progettista specifica la struttura del formato sorgente (analisi), il significato di tali strutture, come semplificare i dati (ottimizzazione) e il tipo di output da generare. Gli interpreti leggono la fonte ed eseguono direttamente. (Gli interpreti sono in genere più semplici da scrivere, ma molto più lenti.)


4

In realtà puoi scrivere in quasi tutte le lingue che ti piacciono. Non c'è nulla che ti impedisca di scrivere un compilatore C in Ruby. "Tutto" non devi fare altro che analizzare il programma ed emettere il codice macchina corrispondente. Se riesci a leggere / scrivere file, probabilmente il tuo linguaggio di programmazione sarà sufficiente.

Se stai iniziando da zero su una nuova piattaforma, puoi eseguire la compilazione incrociata: scrivi un compilatore per la tua nuova piattaforma, che viene eseguito in Java o nativamente su x86. Sviluppa sul tuo PC e poi trasferisci il programma sulla tua nuova piattaforma di destinazione.

I compilatori più elementari sono probabilmente Assembler e C.


Questa "qualsiasi" lingua dovrebbe tuttavia supportare chiamate ricorsive. Altrimenti implementare un analizzatore di sintassi e un parser sarà una vera sfida.

2
Se selezioni una lingua non adatta per un'attività, è colpa tua. Questo può accadere per qualsiasi progetto, non solo per compilatori / interpreti.
ziggystar,

4

"Scrivere un nuovo linguaggio di programmazione" tecnicamente non comporta alcun codice. Sta solo arrivando una specifica per come appare la tua lingua e come funziona. Una volta che hai un'idea di come è la tua lingua, puoi scrivere traduttori e interpreti per far sì che la tua lingua "funzioni".

Un traduttore inserisce un programma in una lingua e produce un programma equivalente in un'altra lingua. Un interprete inserisce un programma in una lingua e lo esegue.

Ad esempio, un compilatore C traduce in genere il codice sorgente C (la lingua di input) in un programma di linguaggio assembly (la lingua di output). L'assemblatore prende quindi il programma del linguaggio assembly e produce il linguaggio macchina. Una volta ottenuto l'output, non è necessario che i traduttori eseguano il programma. Poiché ora disponi di un programma in linguaggio macchina, la CPU funge da interprete.

Molte lingue sono implementate in modo diverso. Ad esempio, javacè un traduttore che converte il codice sorgente Java in bytecode JVM. JVM è un interprete [1] che esegue il bytecode Java. Dopo aver eseguito javace ottenuto il bytecode, non è javacpiù necessario . Tuttavia, ogni volta che vuoi eseguire il tuo programma, avrai bisogno di JVM.

Il fatto che i traduttori non debbano essere tenuti in giro per eseguire un programma è ciò che rende possibile "bootstrap" la tua lingua senza che finisca per funzionare "sopra" livelli e livelli di altre lingue.

[1] La maggior parte delle JVM traducono dietro le quinte, ma in realtà non sono traduttori in quanto l'interfaccia verso la JVM non è "lingua di input -> lingua di output".


3

Generalmente puoi usare qualsiasi lingua tu voglia. PHP è stato scritto in C, per esempio. Se non si ha accesso a nessun compilatore, è necessario ricorrere alla scrittura del linguaggio assembly e alla compilazione manuale del codice macchina.


2
Non è necessario compilare il codice macchina. è la lingua nativa della CPU per definizione.
Stu Thompson,

1
Vero. Quello che intendevo dire era "compilare il codice macchina dal linguaggio assembly o qualcosa di simile a mano". Potrei sbagliarmi, ma immagino che poche persone digitino subito il codice come binario / esadecimale.
Kaivosukeltaja,

2

Molte lingue furono prima scritte in un'altra lingua disponibile e poi reimplementate in sé e avviate in quel modo (o semplicemente mantenute l'implementazione in lingua straniera, come PHP e perl), ma alcune lingue, come il primo assemblatore, furono compilate a mano in codice macchina come il primo compilatore C è stato compilato a mano in assembly.

Sono stato interessato al bootstrap da quando l'ho letto. Per saperne di più ho provato a farlo da solo scrivendo il mio superset di BF, che ho chiamato EBF , in sé. la prima versione di EBF aveva 3 primitive extra e ho compilato a mano il primo binario. Ho trovato un ritmo a due passi mentre lo facevo. Ho implementato una funzione nella lingua corrente in una versione e ho avuto una versione dolce in cui ho riscritto il codice per utilizzare la funzionalità implementata. La lingua era abbastanza espressiva per essere utilizzata per creare un interprete LISP .

Ho la versione compilata a mano insieme alla fonte nel tag della prima versione e il codice è piuttosto piccolo. L'ultima versione ha dimensioni 12 volte maggiori e il codice e consente un codice più compatto, quindi compilare manualmente la versione corrente sarebbe difficile da ottenere.

Edmund Grimley Evans ha fatto qualcosa di simile con il suo linguaggio HEX

Una delle cose interessanti nel fare questo da soli è che capisci perché alcune cose sono come sono. Il mio codice era prodotto se piccole regolazioni incrementali sembra più evoluto piuttosto che progettato da zero. Lo tengo a mente quando leggo il codice oggi, che penso un po 'fuori.


1

Di solito con un linguaggio di programmazione generico adatto allo sviluppo di sistemi, ad esempio C, Haskell, ML, Lisp, ecc., Ma l'elenco delle opzioni è lungo. Inoltre, di solito con alcuni linguaggi specifici del dominio per l'implementazione del linguaggio, ad esempio generatori di analizzatori lessicali e analizzatori, linguaggi intermedi come LLVM , ecc. E probabilmente alcuni script di shell, framework di test e un sistema di configurazione build, ad esempio autoconf.


1

La maggior parte dei compilatori erano wriiten come programma C o AC se non c, quindi assembly lang è la strada da percorrere Tuttavia quando si scrive un nuovo lang da zero e non si dispone di una macro lib o di un codice sorgente da un linguaggio prototipo, è necessario definire le proprie funzioni Ora in che lingua? Puoi semplicemente scrivere una Forma "di codice sorgente chiamato psedocode sulla macchina che assomiglia a una grammatica bnf dalla specifica di lang strutturata orientata agli oggetti come Fortran basic algo lisp. Quindi un'immagine che scrive un codice incrociato simile a una di queste sintassi del linguaggio Questo è codice psedo


1
Non credo che il codice psedo dovrebbe essere leggibile da una macchina
Richard Tingle il

0

Anche ulteriori operazioni binarie o di assemblaggio devono essere tradotte in funzioni, ovvero il lavoro di assemblatori / compilatori, quindi in oggetto, da dati e funzioni, se non si dispone di un file di origine per vedere "come deve essere rappresentata la funzionalità di questi oggetti nel proprio implementazione del linguaggio, quindi devi riconoscere "vedi" implementare, o definire le tue funzioni, procedure e strutture di dati, il che richiede molta conoscenza, devi chiederti qual è una funzione. La tua mente diventa quindi la simulazione del linguaggio. Questo separa un programmatore Master dal resto.


0

Anch'io avevo questa domanda qualche mese fa. E ho letto alcuni articoli e guardato alcuni video che mi hanno aiutato a iniziare a scrivere la mia lingua chiamata soft. Non è ancora completo ma ho imparato molte cose da questo viaggio.

Le cose di base che dovresti sapere è come funziona il compilatore quando deve eseguire uno snippet di codice. Il compilatore ha molte fasi come analisi lessicale, analizzatore semantico, AST (Abstract Syntax Tree) ecc.

Quello che ho fatto nella mia nuova lingua può essere trovato qui - http://www.singhajit.com/writing-a-new-programming-language/

Se stai scrivendo una lingua per la prima volta, allora tutto il meglio e hai ancora molta strada da fare.


0

Quali sono i linguaggi di programmazione in generale?

i linguaggi di programmazione sono solo un modo per parlare con i computer. all'inizio parlando in modo approssimativo perché i computer potevano capire solo zeri e quelli (a causa del fatto che i computer sono fatti di transistor come interruttori che potevano prendere solo due stati, chiamiamo questi due stati 0 e 1) e lavorare con 0,1 era difficile per noi come umani, così gli scienziati informatici hanno deciso di fare una mappatura uno-a-uno da ogni istruzione binaria (0,1) a una forma più leggibile dall'uomo che loro chiamavano linguaggio assembleare.

per esempio se avessimo un'istruzione come:

11001101

in assemblea si chiamerebbe:

LOAD_A 15

il che significa che carica il contenuto del registro a nella posizione di memoria 15. come ho detto, era solo una convenzione come scegliere 0 e 1 per due stati dei transistor o qualsiasi altra cosa nel computer. in questo modo avere un programma con 50 istruzioni, ricordare il linguaggio assembly sarebbe più semplice. così l'utente scriverà il codice assembly e alcuni programmi (assemblatore in questo caso) tradurranno i codici in istruzioni binarie o linguaggio macchina come lo chiamano.

ma poi con i computer migliorati ogni giorno c'era spazio per programmi più complicati con più istruzioni, diciamo 10000.

in questo caso una mappatura one-to-one come assembly non funzionerebbe, quindi sono stati creati altri linguaggi di programmazione di alto livello. hanno detto per esempio se per una relazione con i dispositivi I / O per stampare qualcosa sullo schermo creato dall'utente ci vogliono circa 80 istruzioni, facciamo qualcosa qui e potremmo impacchettare tutto questo codice in una libreria e chiamarlo ad esempio printf e anche creare un altro programma che potrebbe tradurre questo printf qui nel relativo codice assembly e da lì l'assemblaggio farebbe il resto. così lo chiamano compilatore.

così ora ogni utente che vuole semplicemente stampare qualcosa sullo schermo non dovrebbe scrivere tutte le istruzioni in binario o assembly, digita semplicemente printf ("qualcosa") e tutti i programmi come il compilatore e l'assemblatore farebbero il resto. ora più tardi altri codici più lunghi verrebbero impacchettati allo stesso modo per facilitare il lavoro di altre persone visto che potresti semplicemente semplificare migliaia di righe di codice in un unico codice in Python e comprimerlo per l'uso di altre persone.

quindi supponiamo che tu abbia impacchettato molti codici diversi in Python e creato un modulo (libray, pacchetto o qualunque cosa tu voglia chiamarlo) e tu chiami quel modulo mgh (solo il mio nome). ora diciamo che abbiamo creato questo mgh in qualche modo che chiunque dica:

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

potrebbe facilmente connettersi a un server remoto con l'ip e il numero di porta specificati e inviare successivamente i dati (o qualcosa del genere). ora le persone potrebbero fare tutto usando una sola riga, ma ciò che accade è che vengono eseguiti molti codici che sono stati recuperati dal file mgh. e impacchettare non è stato per accelerare il processo di esecuzione ma piuttosto per facilitare il lavoro di altri programmatori. quindi qui se qualcuno vuole usare prima il tuo codice dovrebbe importare il file e quindi l'interprete python riconoscerebbe tutto il codice in esso e quindi potrebbe interpretarlo.

ora se vuoi creare un linguaggio di programmazione e vuoi eseguirlo, prima ha bisogno di una traduzione, ad esempio diciamo che crei un programma in grado di capire la sintassi e convertirlo in c, in questo caso dopo che è stato tradotto a c, il resto sarebbe curato dal compilatore c, quindi assemblatore, linker, .... anche se dovresti pagare il prezzo di essere più lento poiché deve prima essere convertito in c.

ora un'altra cosa che potresti fare è creare un programma in grado di tradurre tutto il codice nel linguaggio assembly equivalente proprio come succede con c ma in questo caso il programma potrebbe farlo direttamente e da lì il resto verrebbe fatto dal linker. sappiamo che questo programma si chiama compilatore.

quindi quello di cui sto parlando è che l'unico codice che il sistema comprende è 0,1, quindi in qualche modo dovresti convertire la sintassi in quello, ora nei nostri sistemi operativi molti programmi diversi come assemblatore, linker e ... hanno è stato creato per dirti che se tu potessi convertire il tuo codice in assembly, loro potrebbero occuparsi del resto o, come ho detto, potresti persino usare compilatori di altri linguaggi di programmazione convertendo il tuo codice in quella lingua.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.