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.
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:
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: