Un linguaggio di programmazione è un sistema di notazione per la scrittura di programmi per computer. I linguaggi di programmazione sono per lo più linguaggi formali basati su testo, ma possono anche essere grafici.
La descrizione di un linguaggio di programmazione è solitamente divisa nelle due componenti della sintassi (forma) e della semantica (significato), che di solito sono definite da un linguaggio formale. Alcuni linguaggi sono definiti da un documento di specifica (ad esempio, il linguaggio di programmazione C è specificato da uno standard ISO) mentre altri linguaggi (come Perl) hanno un'implementazione dominante che viene trattata come riferimento.
Alcuni linguaggi hanno entrambi, con il linguaggio di base definito da uno standard e le estensioni prese dall'implementazione dominante che sono comuni. La teoria dei linguaggi di programmazione è il sottocampo dell'informatica che studia la progettazione, l'implementazione, l'analisi, la caratterizzazione e la classificazione dei linguaggi di programmazione.
Storia
Il primo linguaggio di programmazione della storia è il linguaggio meccanico adoperato da Ada Lovelace per la programmazione della macchina di Charles Babbage, al quale fu seguito il Plankalkül di Konrad Zuse, sviluppato da lui nella Svizzera neutrale durante la seconda guerra mondiale e pubblicato nel 1946. Plankalkül non venne mai realmente usato per programmare. La programmazione dei primi elaboratori veniva fatta invece in short codeRobert W. Sebesta, Concepts of Programming languages, 2006, pp.44. ISBN 0-321-33025-0, da cui poi si è evoluto l'assembly, che costituisce una rappresentazione simbolica del linguaggio macchina. La sola forma di controllo di flusso è l'istruzione di salto condizionato, che porta a scrivere programmi molto difficili da seguire logicamente per via dei continui salti da un punto all'altro del codice.
La maggior parte dei linguaggi di programmazione successivi cercò di superare tale livello basilare, dando la possibilità di rappresentare strutture dati e strutture di controllo più generali e più vicine alla maniera (umana) di rappresentare i termini dei problemi per i quali ci si prefigge di scrivere programmi. Tra i primi linguaggi ad alto livello a raggiungere una certa popolarità ci fu il Fortran, creato nel 1957 da John Backus, da cui derivò successivamente il BASIC (1964): oltre al salto condizionato, reso con l'istruzione IF, questa nuova generazione di linguaggi introduce nuove strutture di controllo di flusso come i cicli WHILE e FOR e le istruzioni CASE e SWITCH: in questo modo diminuisce molto il ricorso alle istruzioni di salto (GOTO), cosa che rende il codice più chiaro ed elegante, e quindi di più facile manutenzione.
Dopo la comparsa del Fortran nacquero una serie di altri linguaggi di programmazione storici, che implementarono una serie di idee e paradigmi innovativi: i più importanti sono il Lisp (1959) e l'ALGOL (1960). Tutti i linguaggi di programmazione oggi esistenti possono essere considerati discendenti da uno o più di questi primi linguaggi, di cui mutuano molti concetti di base; l'ultimo grande progenitore dei linguaggi moderni fu il Simula (1967), che introdusse per primo il concetto (allora appena abbozzato) di oggetto software. Nel 1970 Niklaus Wirth pubblica il Pascal, il primo linguaggio strutturato, a scopo didattico; nel 1972 dal BCPL nascono prima il B (rapidamente dimenticato) e poi il C, che invece fu fin dall'inizio un grande successo. Nello stesso anno compare anche il Prolog, finora il principale esempio di linguaggio logico, che pur non essendo di norma utilizzato per lo sviluppo industriale del software (a causa della sua inefficienza) rappresenta una possibilità teorica estremamente affascinante.
Con i primi mini e microcomputer e le ricerche a Palo Alto, nel 1983 vede la luce Smalltalk, il primo linguaggio realmente e completamente a oggetti, che si ispira al Simula e al Lisp: oltre a essere in uso tutt'oggi in determinati settori, Smalltalk viene ricordato per l'influenza enorme che ha esercitato sulla storia dei linguaggi di programmazione, introducendo il paradigma object-oriented nella sua prima incarnazione matura. Esempi di linguaggi object-oriented odierni sono Eiffel (1986), C++ (che esce nello stesso anno di Eiffel) e successivamente Java, classe 1995.
Descrizione Concetti fondamentali
Tutti i linguaggi di programmazione esistenti sono definiti da un lessico, una sintassi e una semantica e possiedono: Istruzione: un comando oppure una regola descrittiva: anche il concetto di istruzione è molto variabile fra i vari linguaggi. A prescindere dal particolare linguaggio però, ogni volta che un'istruzione viene eseguita, lo stato interno del calcolatore (che sia lo stato reale della macchina oppure un ambiente virtuale, teorico, creato dal linguaggio) cambia.
Alcuni concetti sono poi presenti nella gran parte dei linguaggi: Variabile e costante: un dato o un insieme di dati, noti o ignoti, già memorizzati o da memorizzare; a una variabile corrisponde sempre, da qualche parte, un certo numero (fisso o variabile) di locazioni di memoria che vengono allocate, cioè riservate, per contenere i dati stessi. Molti linguaggi inoltre attribuiscono alle variabili un tipo, con differenti proprietà (stringhe di testo, numeri, liste, ecc.) che può essere assegnato in maniera forte (tipizzazione forte) o in maniera debole (tipizzazione debole). Vi sono linguaggi di programmazione, come unlambda, che invece non utilizzano variabili. Alcuni linguaggi supportano l'uso dei cosiddetti puntatori a variabili.
Espressione: una combinazione di variabili e costanti, unite da operatori; le espressioni sono state introdotte inizialmente per rappresentare le espressioni matematiche, ma in seguito la loro funzionalità si è estesa. Un'espressione viene valutata per produrre un valore, e la sua valutazione può produrre "effetti collaterali" sul sistema e/o sugli oggetti che vi partecipano. Casi particolari di espressione sono le cosiddette espressioni regolari. Strutture dati, meccanismi che permettono di organizzare e gestire dati complessi. Strutture di controllo, che permettono di governare il flusso di esecuzione del programma, alterandolo in base al risultato o valutazione di un'espressione (che può ridursi al contenuto di una variabile, o essere anche molto complessa) (cicli iterativi quali ad esempio for, do, while e strutture condizionali quali ad esempio if, switch-case). Sottoprogramma: un blocco di codice che può essere richiamato da qualsiasi altro punto del programma. In tale ambito quasi tutti linguaggi offrono funzionalità di riuso di codice accorpando cioè sequenze di istruzioni all'interno di funzioni richiamabili secondo necessità all'interno di programmi o all'interno di librerie richiamabili in ogni programma. Funzionalità di input dati da tastiera e visualizzazione dati in output (stampa a video) attraverso i cosiddetti canali standard (standard input, standard output). Possibilità di inserire dei commenti sul codice scritto, sintatticamente identificati e delimitati, che ne spieghino le funzionalità a beneficio della leggibilità o intelligibilità.
Codice sorgente
Programmare in un dato linguaggio di programmazione significa generalmente scrivere uno o più semplici file di testo ASCII, chiamato codice sorgente che esprime l'algoritmo del programma tradotto nel linguaggio di programmazione. I font, i colori e in generale l'aspetto grafico sono irrilevanti ai fini della programmazione in sé: per questo i programmatori non usano programmi di videoscrittura, ma degli editor di testo (come emacs e brief) che invece offrono funzioni avanzate di trattamento testi (espressioni regolari, sostituzioni condizionali e ricerche su file multipli, possibilità di richiamare strumenti esterni ecc).
Se un dato editor è in grado di lavorare a stretto contatto con gli altri strumenti di lavoro (compilatore, linker, interprete ecc.: vedi più avanti) allora più che di semplice editor si parla di IDE o ambiente di sviluppo integrato. Va notato che alcuni linguaggi di programmazione recenti consentono anche una forma mista di programmazione, in cui alla stesura di codice sorgente ASCII si associano anche operazioni di programmazione visuale, attraverso le quali il programmatore descrive alcuni aspetti del programma disegnando a video attraverso il mouse; un'applicazione tipica di quest'ultima forma di programmazione è il disegno interattivo della GUI del programma (finestre, menù, e così via). Per essere eseguito dal processore il codice sorgente deve essere tradotto in linguaggio macchina che è il linguaggio in cui opera la macchina a livello fisico, e questo è possibile attraverso due possibili tecniche: la compilazione e l'interpretazione.
Il codice sorgente, contenente le istruzioni da eseguire e (spesso) alcuni dati noti e costanti, può essere poi eseguito passandolo a un interprete che eseguirà le istruzioni in esso contenute, il che è la prassi normale per i linguaggi di scripting; oppure può venire compilato, cioè tradotto in istruzioni di linguaggio macchina da un programma compilatore: il risultato è un file binario eseguibile (codice eseguibile) che non ha bisogno di altri programmi per andare in esecuzione, ed è anche molto più veloce di un programma interpretato. In passato, la compilazione è stata la norma per tutti i linguaggi di programmazione di uso generale; attualmente vi sono numerosi linguaggi interpretati e di uso generale, come il linguaggio Java o quelli della piattaforma .NET, che applicano un approccio ibrido fra le due soluzioni, utilizzando un compilatore per produrre del codice in un linguaggio intermedio (detto bytecode) che viene successivamente interpretato. La differenza di prestazioni tra i linguaggi interpretati e quelli compilati è stata ridotta con tecniche di compilazione just-in-time, sebbene si continui a utilizzare i linguaggi compilati (se non addirittura l'assembly) per le applicazioni che richiedono le massime prestazioni possibili.
Compilazione
La compilazione è il processo per cui il programma, scritto in un linguaggio di programmazione ad alto livello, viene tradotto in un codice eseguibile per mezzo di un altro programma detto appunto compilatore. La compilazione offre numerosi vantaggi, primo fra tutti il fatto di ottenere eseguibili velocissimi nella fase di run (esecuzione) adattando vari parametri di questa fase all'hardware a disposizione; ma ha lo svantaggio principale nel fatto che è necessario compilare un eseguibile diverso per ogni sistema operativo o hardware (piattaforma) sul quale si desidera rendere disponibile l'esecuzione ovvero viene a mancare la cosiddetta portabilità.
Interpretazione
Il difetto di questi linguaggi è la lentezza dell'esecuzione; però hanno il pregio di permettere di usare lo stesso programma senza modifica su più piattaforme. Si dice in questo caso che il programma è portabile.
La perdita di prestazioni che è alla base dei linguaggi interpretati è il doppio lavoro che è affidato alla macchina che si accinge a elaborare tale programma. Al contrario di un programma compilato, infatti, ogni istruzione viene controllata e interpretata a ogni esecuzione da un interprete. Si usano linguaggi interpretati nella fase di messa a punto di un programma per evitare di effettuare numerose compilazioni o invece quando si vuole creare software che svolgono operazioni non critiche che non necessitano di ottimizzazioni riguardanti velocità o dimensioni, ma che traggono più vantaggio dalla portabilità. I linguaggi di scripting e tutti quelli orientati al Web sono quasi sempre interpretati. PHP, Perl, Tcl/Tk e JavaScript e molti altri sono esempi concreti di interazione non vincolata alla piattaforma.