Che cos'è esattamente un linguaggio di programmazione? Cosa ci consente di scrivere in una lingua simile?


26

Va bene, sono nuovo nella programmazione e ammetto che questa è una domanda abbastanza astratta.

Il linguaggio naturale che parliamo ogni giorno esiste perché le persone possono capirsi. Come possono i computer capire il mio codice scritto in una determinata lingua?

Diciamo che il signor A crea una nuova lingua. Come viene accettato dalle macchine? Il creatore deve comunicare con la macchina usando il linguaggio macchina per creare una nuova lingua? Cosa garantisce che possiamo scrivere in una lingua mentre veniamo correttamente compresi dalla macchina?


1
Cosa ci consente di scrivere in una lingua simile? - "Cervelli: il nuovo riempitivo per la testa delle meraviglie!" - Spike Milligan.
Stephen C,

6
Un po 'ampio, ma comunque una buona domanda. Troppe persone usano semplicemente le lingue senza mai chiedersi come funzionano. Bene, sei curioso.
riwalk

4
Questa è una domanda di riferimento generale , facilmente e banalmente risolta da Wikipedia .
Aaronaught,

Risposte:


39

Puoi riassumere praticamente l'intera risposta alla tua serie di domande con la parola "compilatore" . Un compilatore è un programma speciale la cui funzione è prendere il codice sorgente come input, applicare le regole del linguaggio determinate dal progettista del linguaggio per capire cosa significa il codice e produrre codice con lo stesso significato in un'altra lingua come output. Questo è generalmente codice macchina o una qualche forma di bytecode (il "codice macchina" per macchine virtuali), sebbene esistano compilatori specializzati che traducono il codice in altre lingue di alto livello. Sono oltre lo scopo di questa domanda, però.

Non tutte le lingue hanno un compilatore. Alcuni hanno invece un interprete , che fa tutte le stesse cose che fa un compilatore, tranne che invece di produrre codice macchina dopo aver determinato cosa significa il programma, esegue semplicemente immediatamente il programma. Ma i principi di base per analizzare (leggere) il codice e determinare cosa significa sono gli stessi.

Rispondere in modo più approfondito di questo entrerebbe nella teoria del compilatore, che è un argomento molto ampio. Se sei interessato all'argomento, dovresti iniziare leggendo l'articolo di Wikipedia per "compilatore" e controllando i collegamenti da esso, e se hai domande specifiche, sentiti libero di farle qui.


11
+1 - Aggiungo anche che quando scrivi una nuova lingua, devi scrivere il compilatore o l'interprete in un'altra lingua. Le versioni successive del compilatore o dell'interprete possono quindi essere scritte nelle versioni precedenti della lingua e compilate con il compilatore più vecchio. Il primo assemblatore è stato scritto in codice macchina. Il primo compilatore C è stato scritto in assemblea (molto probabilmente) ecc.
Scott Whitlock,

1
Vorrei cambiare la definizione di compilatore. Non emettono tutti il ​​codice macchina. Soprattutto al giorno d'oggi con così tanti compilatori che emettono "codice intermedio", come MSIL. Ci sono persino compilatori che emettono JavaScript!
Neil N

3
Sarei titubante nel dire che i compilatori producono codice macchina per definizione, anche quando spiegano a un principiante. È come dire che le funzioni restituiscono numeri reali, una semplificazione inutile. Tutta la costruzione del compilatore vale quando si produce codice che non è per un computer effettivamente costruito in silicio ma definito solo in modo astratto (sia esso una macchina virtuale o un linguaggio di alto livello; c'è una ragione per cui si dice che lo standard C definisce una macchina astratta , e lì è un compilatore dal LLVM IR di livello molto basso al friggin 'JavaScript). I principianti devono ottenerlo, prima è meglio è.

2
La semplificazione che la maggior parte dei libri del compilatore utilizza è che un compilatore applica le regole del linguaggio per convertire da una lingua di origine a una lingua di destinazione come output. (Non è raro compilare in C, ad esempio, specialmente per un corso introduttivo).
JasonTrue,

4
@delnan, ancora di più: ogni lingua è un codice macchina , per la propria macchina astratta. Non importa quanto sia alta la lingua.
SK-logic,

11

Come hai sottolineato, gli esseri umani comunicano tra loro attraverso una lingua "naturale" come inglese, francese, tedesco. Sono chiamati naturali perché li acquisiamo naturalmente piuttosto che inventarli intenzionalmente (l'esperanto è un'eccezione).

Un linguaggio formale è uno inventato per uno scopo o altro. Un linguaggio di programmazione come C, ad esempio, è un linguaggio formale inventato ai fini della programmazione dei computer.

Tutte le lingue possono essere descritte usando una grammatica. Una gerarchia di grammatiche è stata descritta da Noam Chomsky nel 1956. È composta dai seguenti livelli:

Grammatiche di tipo 0 (grammatiche senza restrizioni). Sono i più generici e equivalgono a una macchina di Turing. In quanto tale, il problema di decidere se una determinata stringa fa parte di una grammatica senza restrizioni è indecidibile.

Grammatiche di tipo 1 (grammatiche sensibili al contesto). Quasi tutte le lingue naturali come l'inglese sono sensibili al contesto. Un esempio di sensibilità al contesto in inglese sono le due frasi: "Il tempo vola come una freccia". e "La frutta vola come una banana". In generale, per i computer è difficile comprendere i linguaggi sensibili al contesto.

Grammatiche di tipo 2 (senza contesto). I linguaggi senza contesto sono la base teorica della sintassi della maggior parte dei linguaggi di programmazione.

Grammatiche di tipo 3 (grammatiche regolari). La famiglia delle lingue regolari può essere ottenuta da espressioni regolari. I linguaggi regolari sono comunemente usati per definire modelli di ricerca e la struttura lessicale dei linguaggi di programmazione.

Le grammatiche di tipo 2 (senza contesto) e di tipo 3 (regolari) sono spesso eseguite dai computer perché i loro parser possono essere implementati in modo efficiente.

BNF (Backus Normal Form o Backus – Naur Form) è una tecnica di notazione per grammatiche senza contesto, spesso utilizzata per descrivere la sintassi dei linguaggi utilizzati nell'informatica.

Ad esempio un identificatore potrebbe essere descritto come:

<identifier> ::= <letter> { <letter> | <digit> }

il che significa che deve iniziare con una lettera e può contenere lettere o cifre aggiuntive.

In precedenza, una lettera è definita una "a" | 'b' | 'c' ecc. e la cifra viene definita da '0' a '9' usando lo stesso tipo di notazione.

L'istruzione "for" potrebbe essere definita come:

 <for_statement> ::=
    'for' '(' <expression> ';' <expression> ';' <expression> ')' <statement> 

Analizzatori e parser lessicali (i primi stadi di un compilatore o interprete) sono quindi costruiti per accettare la grammatica specifica descritta dal BNF per un particolare linguaggio. Gli analizzatori lessicali vengono in genere utilizzati per separare i vari token di una lingua (come una parola chiave, un identificatore o un numero) e il parser viene utilizzato per capire come funzionano i token insieme, ad esempio come viene costruita un'istruzione "for" .


+1 ottima scrittura. Ma non sono sorpreso che questo non sia stato accettato come risposta. Questo è quello che pensavo fosse OP, ma in base alla risposta che hanno scelto, sembra che volessero qualcosa di molto più alto livello.
Matthew Rodatus,

5

Per prima cosa, definiamo "linguaggio" in termini di ciò che è. La lingua richiede prima un vocabolario (un elenco di parole che definiscono concetti che sono gli oggetti della comunicazione), quindi una sintassi (un "primer" o un insieme di regole che definiscono la struttura della comunicazione).

A questo livello elementare, C # non è poi così diverso dall'inglese. Ciò che rende C # un "linguaggio di programmazione" è il suo intento, e quindi il suo design; è progettato per essere digerito in singoli comandi di basso livello. In quanto tale, il vocabolario predefinito è limitato, la sintassi è applicata in modo molto rigido e l'intero linguaggio è progettato per essere consumato in un modo predefinito molto noto dal suo "pubblico" (il computer; più precisamente il compilatore, che digerirà il codice sorgente in un "linguaggio intermedio" di semplici comandi che possono essere ulteriormente tradotti in codice macchina dal "runtime"). Non scrivi prosa o poesia in C #; dici al computer di fare un lavoro nel modo più inequivocabile possibile.

Per i computer, sì, uno strumento, generalmente chiamato compilatore, è necessario per prendere ciò che scrivi nel codice e convertirlo nelle istruzioni che il computer può usare. L'informatica, come la maggior parte della tecnologia, è un processo intrinsecamente iterativo, "stratificato". Quando i computer sono stati inventati per la prima volta, sono stati programmati inserendo manualmente le istruzioni binarie. Tali istruzioni sono diventate standardizzate per ciascun processore in "codici macchina" esadecimali; la differenza sta solo nel modo in cui le cifre binarie sono raggruppate per essere mostrate agli umani. Quindi, nel codice assembler, l'elenco dei comandi e alcuni identificatori di base come i nomi dei registri sono stati sostituiti con i loro codici esadecimali durante la scrittura dei programmi; ASM può ancora essere convertito 1: 1 in codice macchina nativo. Il salto di qualità è stato la programmazione "imperativa" di terza generazione, che fondamentalmente prende concetti più comprensibili dall'uomo, astratti come variabili e cicli logici e li digerisce nelle istruzioni native, usando schemi basati su parole chiave e sintassi. Le prime lingue come COBOL, FORTRAN, Pascal e C possono ancora essere "tradotte" da un essere umano in un particolare linguaggio macchina (di solito 8086 ASM). Poi è arrivata la rivoluzione della programmazione orientata agli oggetti, che è fondamentalmente regole di sintassi aggiuntive che definiscono il codice come concettualmente incapsulato in "oggetti" che hanno una combinazione di stato e logica. da un essere umano in un particolare linguaggio macchina (di solito 8086 ASM). Poi è arrivata la rivoluzione della programmazione orientata agli oggetti, che è fondamentalmente regole di sintassi aggiuntive che definiscono il codice come concettualmente incapsulato in "oggetti" che hanno una combinazione di stato e logica. da un essere umano in un particolare linguaggio macchina (di solito 8086 ASM). Poi è arrivata la rivoluzione della programmazione orientata agli oggetti, che è fondamentalmente regole di sintassi aggiuntive che definiscono il codice come concettualmente incapsulato in "oggetti" che hanno una combinazione di stato e logica.

Al giorno d'oggi, siamo ben inseriti nella "quarta generazione" di lingue, che sono lingue scritte per definire la comunicazione con altri programmi invece che direttamente con la macchina. Ampiamente definito, questo include linguaggi "markup" come XML / HTML, linguaggi "scripting" come JavaScript e SQL e la maggior parte dei linguaggi "sandbox" come Java e .NET Framework (che vengono compilati in un IL che viene poi interpretato ulteriormente da un runtime che estrae i dettagli specifici della macchina e della piattaforma). Si potrebbe anche dire che comprende il regno dei linguaggi di programmazione funzionale, che sono FACILMENTE dipendenti da un runtime per fornire l'astrazione non solo di dettagli specifici della macchina, ma di dettagli specifici dell'operazione. Queste lingue di quarta generazione sono più o meno impossibili da tradurre per un essere umano in istruzioni native della macchina, e il punto è che non sarebbe uno sforzo utile; il punto di forza di queste lingue è il processo a più livelli in cui vengono utilizzati per comunicare a un computer cosa fare a livelli bassi.


Grazie. Ho uno sguardo alla storia dell'evoluzione del linguaggio di programmazione.
Erica Xu,

2
@KeithS: potresti voler riformattare l'ultimo paragrafo per renderlo un po 'più leggibile.
Ivan Vučica,

4

Ottima domanda. Una risposta adeguata costituisce una buona metà di ciò che viene chiamato "Informatica".

Per cominciare, consiglierei di scorrere la semantica denotazionale e operativa e di leggere questo libro . Ti darà una comprensione più o meno solida di ciò che è il linguaggio di programmazione e di come può essere definito formalmente.

Se quanto sopra è un po 'troppo accademico, puoi iniziare con Petzold, "Codice" , e poi tornare alla semantica.


1
Ti aspetti davvero che un ragazzo di 18 anni legga qualche teoria pesante solo per rispondere a questa domanda?
Lavoro

2
@Job, secondo la sua domanda precedente, sta ricevendo dosi di Scheme (e, presumibilmente, SICP) nell'università. Dovrebbe andare bene con un po 'di semantica allora. Ad ogni modo, non esiste una risposta adeguata a questa domanda senza una teoria pesante.
SK-logic,

+1 per menzionare "Codice". Quel libro dovrebbe essere richiesto per ogni studente CS di livello base.
Daniel Pryden,

4

Se scrivi un programma in un linguaggio di programmazione, un altro programma convertirà i simboli nel tuo programma in simboli comprensibili per il computer. A volte questo richiede diversi passaggi. Ad esempio in C:

  1. L'utente scrive il programma in un linguaggio di alto livello (C) che non è compreso dalla CPU, ma è compreso direttamente dal programmatore (speriamo!).

  2. Il compilatore converte C in linguaggio Assmebly, che non è compreso direttamente dalla CPU ma è facile da convertire in qualcos'altro.

  3. Assempler converte Assembly in sequenza di codici binari che sono direttamente compresi dalla CPU. Alcuni compilatori saltano il passaggio precedente (passaggio 2) e producono il file binario compilato direttamente dal codice sorgente.

Per garantire che il computer comprenda il tuo programma, il compilatore o l'interprete ti darà un errore e di solito si fermerà se incontra qualcosa che non è compilabile, come un errore di sintassi. Se il tuo programma non può essere compilato, non potrà mai arrivare allo stadio in cui il tuo programma proverà a eseguirlo e fallirà perché non lo "capisce".

Per creare una nuova lingua, devi prima progettare la tua lingua di alto livello e poi devi trovare un modo per mappare i simboli della tua nuova lingua ai comandi di linguaggio assembly che la tua CPU capisce.


2
Non proprio; i compilatori moderni non eseguono il passaggio 2 e producono semplicemente codice binario direttamente. Ma assembly e codice binario sono comunque quasi equivalenti; è possibile disassemblare (convertire il codice binario in assembly) con fedeltà molto elevata.
MSalters il
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.