I linguaggi di programmazione

Un linguaggio di programmazione è un linguaggio formale e rigoroso (ossia con delle rigide regole da rispettare), che consente di tradurre un algoritmo in una forma comprensibile ad una macchina.

Il primo linguaggio di programmazione è stato il linguaggio binario (o linguaggio macchina).
Ogni sua istruzione è composta da sequenze di simboli 0 e 1, molto difficili da comprendere e ricordare, ognuna delle quali con un preciso sognificato per un particolare tipo di processore (esecutore).
L'insieme di queste istruzioni costituisce il set di istruzioni (instrunction set) di una specifica macchina.
Per tale ragione, essendo il set di istruzioni specifico di una determinata famiglia di processori, questi programmi sono eseguibili solo sulle macchine che riconoscono quel set di istruzioni e non sono portabili su altre macchine.
In altri termini, per poterli eseguire su altre macchine occorre riscrivere il programma.

Un esempio di programma in linguaggio macchina potrebbe essere il seguente:

 1. 00010100 00101100 10010111 10101100 
 2. 10010101 11110101 01101001 11111001 
 3. 11100010 01011010 10011011 10010110
 4. 10010101 11110101 01101001 11111001 
 5. 00010101 01110101 01101001 01111001 
 6. 10010101 10010101 01001001 11001001 
 7. 00110000 11110100 01101001 11111001 
 8. 10010101 10110100 01111001 11001001 
 9. 11110101 11110101 01001001 11111111 
10. 10011111 00010101 01101001 11111001 
11. 11011100 00010110 01011010 10111001 
12. 10011110 01010101 01101001 11011001 
13. 11011011 00110101 01101001 10101001 

Si può facilmente dedurre la difficoltà nello scrivere un programma in linguaggio macchina e nella comprensione di un programma scritto da altri o da se stessi in tempi passati. Di conseguenza, ne deriva una notevole la difficoltà nell'apportare modifiche e l'altissima probabilità di introdurre anomalie (malfunzionamenti o bugs).
Possiamo, quindi, riassumere gli svantaggi della programmazione in linguaggio macchina elencando i concetti di:

  • produttività
  • portabilità
  • manutenzione

Occorre, comunque, elencare anche qualche vantaggio dei programmi scritti in questo linguaggio.
Tra essi abbiamo sicuramente l'elevata efficienza, essendo le righe di codice istruzioni che lavorano direttamente sul processore e sui suoi registri.
La programmazione in linguaggio macchina è, per queste ragioni, confinata alla scrittura di alcuni driver di periferiche, per le quali è richiesta elevatissima efficienza.

Il linguaggio assembly

Un primo passo verso i linguaggi di programmazione più semplici e maggiormente utilizzati al giorno d'oggi è stata l'introduzione dei linguaggi simbolici, di cui il primo è stato il linguaggio assembly.
Esso è composto da istruzioni simboliche, ossia non più composte da sequenze di numeri ma di parole più comprensibili all'essere umano, ognuna delle quali corrispondente ad una specifica istruzione del linguaggio macchina.
In altri termini esiste una corrispondenza uno ad uno tra istruzioni in linguaggio macchina ed istruzioni in linguaggio assenbly.
Da questo deriva che anche il linguaggio assembly è specifico di una famiglia di processori e, di conseguenza, i programmi non sono portabili su macchine con architettura di processore differente.
I programmi in linguaggio assembly non sono direttamente eseguibili da una macchina, in quanto la macchina non è in grado di comprendere le istruzioni simboliche, essendo il suo linguaggio composto solo da parole/istruzioni espresse attraverso i simboli 0 e 1.
Per poterli eseguire, quindi, è necessario un lavoro di traduzione delle istruzioni simboliche in istruzioni binarie.
Questo lavoro è svolto da un software che prende il nome di assembler o assemblatore.

Un esempio di programma in linguaggio assembly, che scrive sulla finestra del terminale il messaggio "Hello world!", potrebbe essere il seguente:

 1. section .text
 2.     global _start               ; dichiarazione del punto di ingresso
 3. _start:                         ; punto di ingresso
 4.     mov edx, len                ; lunghezza del messaggio da scrivere
 5.     mov ecx, msg                ; messaggio da scrivere
 6.     mov ebx, 1                  ; dove scrivere (stdout)
 7.     mov eax, 4                  ; chiamata di sistema (system call number - sys_write)
 8.     int 0x80                    ; chiamata kernel
 9.     mov eax, 1                  ; chiamata di sistema (system call number - sys_exit)
10.     int 0x80                    ; chiamata kernel
11. section .data
12.     msg db 'Hello, world!', 0xa ; messaggio da scrivere 
13.     len equ $ - msg             ; lunghezza del messaggio

Si può chiaramente dedurre che, sebbene la comprensione del programma sia ancora di un certo livello di difficoltà, lo stesso è sicuramente più chiaro dell'equivalente programma scritto in linguaggio macchina.

Tale programma, come anticipato poc'anzi, non è direttamente comprensibile ed eseguibile da un computer.
Esso deve pertanto essere tradotto, attraverso un assembler (compilatore), nel programma equivalente in linguaggio macchina. Solo dopo tale operazione, il programma risultante potrà essere eseguito.
Graficamente possiamo rappresentare quanto detto attraverso la figura seguente:

Assembler: traduzione assembly/macchina

I linguaggi di programmazione di alto livello

Sullo stesso modello del linguaggio assembly, sono stati sviluppati, nel corso del tempo, diversi linguaggi di programmazione cosiddetti di alto livello, ad indicare la loro maggiore vicinanza al linguaggio naturale utilizzato dall'uomo, in contrapposizione ai linguaggi di basso livello, ossia quelli più distanti dal linguaggio naturale e più vicini al linguaggio macchina.
Tra questi occorre citare C, C++, C#, Java, Python, PHP, Perl, Basic, Cobol, Fortran, Ada, Algol, Pascal, Lisp, Prolog, Simula, Smalltalk, Eiffel, ...

Questi linguaggi sono un po' meno espressivi del linguaggio naturale, ma seguono delle regole di composizione delle istruzioni molto rigide.
Si definiscono, infatti, anche linguaggi formali, proprio perchè soggetti a regole sintattiche e semantiche rigorose, che hanno l'obiettivo di eliminare ogni ambiguità.
Nei linguaggi naturali, infatti, possiamo avere diverse parole con stesso significato (sinonimi), oppure la stessa parola con significati diversi in contesti differenti.
Tutto ciò non può essere ammesso con i linguaggi di programmazione.

Esempio:
La frase "La vecchia porta la sbarra"

può essere intesa come:
  • una vecchia signora che trasporta una sbarra
oppure
  • una vecchia porta che sbarra una strada
oppure la frase "Marco guarda Luigi in cortile con il binocolo"
presenta diverse ambiguità:
  • chi ha il binocolo? Marco o Luigi?
  • Chi è in cortile? Marco o Luigi?

Tutto questo, con i linguaggi di programmazione non deve avvenire.
Il frammento di codice che segue, infatti, direbbe, in modo chiaro ed inequivocabile, a qualunque esecutore, esattamente cosa fare.

if (piove == true) then {     // se piove allora
    ombrello = true;          // prendi l'ombrello
} else {                      // altrimenti
    ombrello = false;         // non prendere l'ombrello
}


Ma ... perchè tanti linguaggi di programmazione?

La risposta è semplice. Ogni linguaggio ha delle caratteristiche specifiche ed è più indicato per alcuni contesti o tipologie di applicazioni e meno per altri.
Questo significa che il programmatore è libero di scegliere il linguaggio che meglio si addice all'applicazione da sviluppare, in termini di funzionalità di cui dispone, facilità di programmazione e conoscenza/gradimento del programmatore stesso.
In tal modo, inoltre, il programmatore può concentrarsi maggiormente sul problema da risolvere senza preoccuparsi dei dettagli tecnici della macchina su cui il programma dovrà essere eseguito.

Affinchè tali programmi possano, però, essere eseguiti da una macchina è necessaria una traduzione nel linguaggio macchina specifico del tipo di computer su cui dovrà essere possibile eseguirli.

Questo lavoro è fatto da altri programmi che, a seconda del momento e delle caratteristiche della traduzione prendono il nome di:

  • compilatori (e linker)
  • interpreti
Riassumendo graficamente, abbiamo la situazione illustrata nelle figure seguenti:
Traduzione linguaggi di alto livello: compilatore/interprete


Linguaggi di alto e basso livello

,