Linguaggio di programmazione ad alto livello

Da Wikipedia, l'enciclopedia libera.

In informatica, un linguaggio di programmazione ad alto livello è un linguaggio di programmazione diverso dal linguaggio macchina, direttamente eseguibile da un computer, ma più vicino o familiare alla logica del nostro linguaggio naturale. L'idea di fondo è che i programmi ad alto livello possono essere ricondotti a programmi in linguaggio macchina in modo automatico, ovvero da un altro programma. Il linguaggio ad alto livello quindi astrae dalle caratteristiche fisiche della macchina in cui si opera e si ottiene come codifica: tabelle di associazioni tra nomi e gruppi di istruzioni base a partire dal linguaggio macchina stesso.

Quest'idea fu introdotta in informatica negli anni cinquanta, soprattutto grazie al lavoro di John Backus presso la IBM, dove fu sviluppato il primo compilatore per il linguaggio Fortran. In seguito, Backus ricevette per questo motivo il premio Turing.

Problemi del linguaggio macchina[modifica | modifica wikitesto]

I linguaggi macchina sono formati da istruzioni elementari, che vengono codificate in forma numerica e che consentono di effettuare operazioni aritmetiche, conversioni di bit e poco altro. Scrivere programmi in tale linguaggio è quindi estremamente sconveniente: un'operazione basilare può richiedere anche tre o quattro istruzioni; si rende così necessario molto codice anche per i programmi più semplici. Il fatto che tale codice sia solamente numerico comporta inoltre grosse possibilità di errori e difficoltà nell'individuarne. È necessario inoltre avere continuamente a che fare con le caratteristiche fisiche della macchina in cui si programma: bisogna ad esempio specificare manualmente gli indirizzi di memoria in cui salvare le informazioni e i registri del processore in cui mantenere i dati temporanei.

Infine, ogni computer può comprendere solo il proprio linguaggio macchina, poiché esso è diverso da processore a processore. Esiste quindi anche lo svantaggio di dover riscrivere interamente un programma per farlo funzionare su un'altra piattaforma.

Impatto dei linguaggi ad alto livello[modifica | modifica wikitesto]

L'idea dei linguaggi ad alto livello è già sottesa ai linguaggi assembly, che tuttavia non sono altro che "traslitterazioni" dei corrispondenti linguaggi macchina, che per esempio fanno corrispondere un codice mnemonico (quindi più leggibile) a ogni codice di istruzione binario. Nei linguaggi di programmazione ad alto livello veri e propri, invece, una singola istruzione consente di effettuare un'operazione semplice, ma completa. Le istruzioni non sono in forma numerica, sono bensì parole (generalmente in lingua inglese), il cui significato corrisponde all'operazione che effettuano. A differenza dei linguaggi assembly, quindi, il processo di traduzione può avere una complessità arbitraria, per cui il linguaggio ad alto livello può essere anche completamente diverso (per sintassi e semantica) dal sottostante linguaggio macchina.

In sostanza, la programmazione ad alto livello ebbe l'effetto di svincolare completamente (o quasi) le caratteristiche dei linguaggi di programmazione da quelle dell'hardware destinato a eseguirli. Fra le conseguenze principali si possono elencare le seguenti:

  • la progettazione di processori fu completamente liberata da qualsiasi requisito relativo alla leggibilità dei linguaggi macchina, in quanto si poteva ragionevolmente assumere che nessuno (o quasi) avrebbe più scritto o letto direttamente codice in linguaggio macchina o assembly; l'efficienza divenne di fatto l'unica preoccupazione reale dei progettisti hardware;
  • i linguaggi di programmazione ad alto livello ebbero un'evoluzione completamente indipendente da quella dell'hardware; lo scopo generale di tale evoluzione fu quello di rendere tali linguaggi sempre più "facili" da utilizzare per il programmatore umano;
  • si introdusse il concetto che i linguaggi di programmazione e i programmi potessero essere portabili, ovvero eseguibili su diversi computer (a patto di disporre di compilatori o interpreti per tali computer).

In generale, la maggior parte dei linguaggi di programmazione ad alto livello moderni conserva alcuni concetti di fondo che è possibile ricondurre ad alcune caratteristiche tipiche del linguaggio macchina. Concetti come quelli di variabile e assegnamento sono una versione astratta dello spostamento di dati fra celle di memoria; e il fatto che il paradigma di programmazione dominante sia quello imperativo si può facilmente giustificare con la considerazione che anche i linguaggi macchina sono imperativi.

Politiche di traduzione del linguaggio ad alto livello in linguaggio macchina[modifica | modifica wikitesto]

Com'è stato detto, il linguaggio ad alto livello non è direttamente comprensibile dal calcolatore. È quindi necessario effettuare una traduzione dal linguaggio del programmatore a quello della macchina.

Traduzione che avviene una sola volta: la compilazione[modifica | modifica wikitesto]

In questa politica di traduzione, un programma chiamato compilatore si occupa della traduzione. Questa avviene una sola volta: durante la compilazione le istruzioni in linguaggio di alto livello vengono tradotte in istruzioni macchina; ha così origine un file nel linguaggio macchina locale, che costituisce un eseguibile.

Traduzione in tempo reale: l'interpretazione[modifica | modifica wikitesto]

In questo modello, il listato non viene tradotto una sola volta, bensì tutte le volte che viene eseguito. Un programma apposito, l'interprete, durante l'esecuzione del programma traduce ogni istruzione di alto livello in istruzione macchina. In questo caso si ha una miglior portabilità, ma peggiori prestazioni.

Esiste anche un modello di compilazione intermedio che consiste nel tradurre il codice sorgente non direttamente in un codice macchina (direttamente eseguibile dall'hardware) ma in un codice intermedio (che cerca di avvicinarsi il più possibile al codice macchina). In questo caso è necessaria la presenza di un interprete che sia in grado di rendere possibile l'esecuzione del codice intermedio generato.

Uno dei primi esempi di compilatore che ha usato questo approccio è stato l' UCSD-PASCAL che generava un codice intermedio denominato P-Code.

Livelli di astrazione[modifica | modifica wikitesto]

Un linguaggio di programmazione può essere descritto come "più ad alto livello" di un altro se si discosta in modo più radicale dalle caratteristiche tipiche del linguaggio macchina. In questo senso, si possono in linea di principio classificare tutti i linguaggi in funzione del loro livello di astrazione. In gran parte, una tale classificazione rispecchierebbe da vicino l'evoluzione storica dei linguaggi e dei paradigmi di programmazione, con i linguaggi più antichi (FORTRAN, Cobol) evidentemente più vicini al linguaggio macchina rispetto alle ultime generazioni di linguaggi a oggetti come Java o Python. Proprio in virtù di questa evoluzione storica, spesso un linguaggio definito "ad alto livello" alla sua nascita in seguito "diventa di basso livello"; un esempio fra tutti è quello del C.

Fra i linguaggi a più alto livello in assoluto vanno probabilmente citati quelli corrispondenti a paradigmi di programmazione di origine matematica, come i linguaggi funzionali (LISP) e logici (Prolog).

Livello di astrazione ed efficienza[modifica | modifica wikitesto]

C'è chi dice che, in termini almeno generali, quanto più complessa è la traduzione da un dato linguaggio al linguaggio macchina, tanto più inefficiente tende a essere il linguaggio (in quanto il programmatore perde ogni percezione, anche indiretta, di ciò che accadrà realmente, a livello hardware, quando il programma verrà eseguito; e di conseguenza perde anche ogni possibilità di "ottimizzare" tale esecuzione).

Questa perdita di efficienza del software, tuttavia, si considera generalmente un costo accettabile per ottenere una serie di benefici (per alcuni dei quali si potrebbe usare ancora il termine "efficienza", seppure con connotazione leggermente diversa):

  • i linguaggi di alto livello forniscono tempi di sviluppo molto contenuti;
  • la distanza concettuale fra l'analisi e l'implementazione si riduce, con conseguente riduzione del rischio di non corretta traduzione delle specifiche in codice;
  • gli errori logici si individuano più facilmente, essendo espressi nella logica del dominio del problema;
  • si evitano per lo più gli errori macchina che sono intercettati e segnalati opportunamente dal linguaggio di alto livello;
  • i tempi di esecuzione si migliorano con l'efficienza degli algoritmi non eseguendo velocemente algoritmi inefficienti;
  • i profiler forniscono informazioni dettagliate su quali siano i colli di bottiglia, si valuterà se è necessario tradurne o riscriverne quelle parti in linguaggi di programmazione che ne consentano una esecuzione più rapida, avendo già ottenuto e verificato specifiche chiare e certe.

Voci correlate[modifica | modifica wikitesto]