[image]https://leganerd.com/wp-content/uploads/LEGANERD_040578.png[/image]
[image]https://leganerd.com/wp-content/uploads/LEGANERD_041060.png[/image]
Prima le basi (gli “ingredienti”), poi la compilazione (la “cottura”, in cui accennare cosa può andar storto) e per ultimo il debugging, che presuppone aver individuato una sorta di indizi sugli errori commessi (“rifare la torta, migliorandola”).
Con questa citazione di [url=https://leganerd.com/people/ragnoboy/]Ragnoboy[/url] (sia [del]benedetto[/del] [del]maledetto[/del] circondato da poppe), inizia il [b]quarto articolo[/b] della vostra preferita, sempreverde, incommensurabile, fantasmagorica, ineccepibile, incredibile, erotica, […], machecatzovelodicoafarev2.0 rubrica [b]Programmazione: Parliamone[/b].
Per i fessi o gli sfigatelli che si sono persi le [url=https://leganerd.com/tag/propa/]precedenti puntate[/url], il [i]consiglio[/i] è quello di andare a mangiare sapone e olio di ricino leggendo il libretto di istruzioni della Lega al contrario; fatto quello avrete la possibilità di affacciare le vostre menti nel lurido sciogliersi di informazioni dello scorso articolo che è [b]F O N D A M E N T A L E[/b] per evitare che scriviate immondizia nei commenti.
Nelle ultime settimane abbiamo parlato di come i linguaggi di programmazione si siano evoluti nel tempo fino a formare quell’ [i]environment[/i] che tutti i programmatori amano ed odiano allo stesso tempo. Se vi ricordate, i primi linguaggi erano semplicemente una sorta di linguaggio molto [b]simile[/b] a quello utilizzato direttamente dai calcolatori, scritto all’interno delle macchine dalle dolci manine di goliardici e panzuti ingegneri. Esso veniva poi eseguito durante la stessa lettura in quanto decisamente similare al linguaggio [b]binario[/b] e, quindi, immediatamente traducibile nelle istruzioni che l’hardware poteva eseguire. Poche storie: era un mondo duro e i programmatori morivano di onanismo mentale [i]quarantadue[/i] ore su ventiquattro.
Per questo, un bel giorno, nel lontano [del]Giurassico[/del] 1957, dopo decenni passati a cercare una soluzione per tutti quei fazzoletti sprecati in nome della scienza, il primo linguaggio di programmazione compilato venne alla luce ed il mondo cambiò. Non fate i pidocchiosi ed andate a leggervi il secondo articolo di [tag]ProPa[/tag]. [b]NAU![/b]
Ma in cosa consiste un [b]compilatore[/b], vi starete chiedendo. Beh, innanzitutto, non è un affare che ammucchia delle porte seriali cercando di superare Rocco in quanto ad “altezza” raggiunta. Non è neanche un tizio che riempie le scartoffie del lavoro al posto vostro.
Forse è [i]42[/i], ma manca una decina di milioni di anni per scoprirlo.
Un compilatore, [b]in soldoni[/b], è quel programma che traduce del codice scritto in un linguaggio ad alto livello in un qualcosa che il processore è in grado di leggere, cercando di essere il più fedele possibile. Ha il compito di rispettare la volontà del programmatore senza intervenire sul codice e per questo non è il miglior amico del [i]debugger[/i] (prossimamente su LN). E’ uno strumento importantissimo per il programmatore e spesso la [b]velocità[/b] di esecuzione del programma è direttamente proporzionale alla sua [b]qualità[/b] (pensate che con l’ultimo aggiornamento di gcc, il più famoso compilatore quasi-universale open source, le prestazioni di molti software sono aumentate addirittura del 20%). Il suo scopo ultimo è quello di creare un [b]eseguibile[/b] che la macchina è in grado di leggere appieno.
Non sono però tutte rose e fiori. Come succedeva per i linguaggi simil-macchina, i compilatori sono legati a doppio filo coi linguaggi [b]target[/b], quelli che le specifiche architetture del processori sono in grado di leggere. Fortunatamente, ad oggi molti linguaggi di programmazione (ma non tutti) utilizzano dei programmi che permettono una lettura cross-platform a discapito però di un’eventuale riduzione della velocità di esecuzione. Uno di questi linguaggi è per esempio il [b]Java[/b], che utilizza la[i] Java Virtual Machine[/i].
Questo fantastico strumento lavora [b]semplicisticamente[/b] in tre fasi:
– La fase di [b]front end[/b] dove avviene il controllo del testo dal punto di vista [b]grammaticale[/b] e [b]sintattico[/b]. Il codice, infatti, per essere compilato, non deve avere tutti quegli errori che andrebbero a [b]bloccare[/b] le fasi successive di compilazione. Non sono quindi ammesse variabili dichiarate malamente, oggetti lasciati a metà, punteggiatura mancante e tutto quello che non è descritto dal programma o dal linguaggio di programmazione. Diciamo che questa fase può essere considerata come il muro di fuoco composto da GrammarNazi che tutti gli autori di LegaNerd devono superare quando decidono di suicidarsi scrivere un articolo. In questa fase, se il compilatore trova errori di sorta, viene generato un file di [b]log[/b] contenente tutti gli [b]eventuali[/b] errori. Eventuali perché non tutto ciò che il software vi scrive è essenzialmente giusto; infatti, molto spesso, basta una sola parentesi dimenticata per creare il caos, morte e distruzione nel developer di turno [i][True Story – Se il vostro programma, scritto in C, supera le 5k righe, sperate di non lasciare mai una parentesi scoperta tutta sola soletta: ve ne potreste pentire amaramente][/i]. Dicevamo, se il compilatore trova errori in questa fase, tutto si stoppa e la traduzione [b]non va avanti[/b].
SE invece tutto fila liscio, solitamente viene creato un file contenente una traduzione intermedia che va direttamente a finire in pasto al secondo livello del compilatore che procede quindi con la fase di middle end [NdA: Fantasia portami via].
– La fase di [b]middle end[/b] dove avviene il lavoro di ottimizzazione. Il codice viene [b]smaltito[/b] di tutto quello che [b]non è necessario[/b] e le ridondanze o le ripetizioni vengono eliminate. Per chi conosce come funziona una compressione di un file, diciamo che questa è la fase dove il codice viene compresso. E’ probabilmente la parte più importante di tutto il processo ed è quella che determinerà la qualità del codice tradotto e quindi la sua velocità di esecuzione. Questa fase è molto spesso una branca dell’ultima poiché non tutti i compilatori hanno predefinitamente il compito di ottimizzare il codice. Anche qua viene creato un altro codice sorgente intermedio che passa alla fase finale, quella di back end.
– La fase di [b]back end[/b] dove avviene il passaggio dal codice intermedio al[b] linguaggio target[/b], generalmente un linguaggio [b]macchina o assembly[/b]. Questa fase è particolare poiché si basa sull’architettura della macchina target – il computer che dovrà eseguire il programma – e quindi cambia in base ad essa. Generalmente viene eseguita una seconda ottimizzazione e vengono decisi come il programma utilizzerà le risorse di sistema in modo più o meno intelligente. Il prodotto finale è il famoso eseguibile [b].exe[/b] [del]per i portatori di handicap[/del] per chi usa windows. Da notare che, in assenza di un [i]DEcompilatore[/i], è [b]impossibile[/b] risalire al codice originale di alto livello e, per tanto, è necessario uno studio di [i]reverse engineering[/i] per poter sapere in che modo il programmatore ha ragionato.
Come potete notare, il processo di compilazione non è affatto semplice e molto spesso è anche [b]incredibilmente lungo[/b]. Chi usa il computer ad un livello già più avanzato avrà potuto sperimentare i brividi durante le compilazioni di durata giornaliera. Vi capisco, mi dispiace molto per voi.
Nonostante comunque tutte le preoccupazioni che il compilatore si prende per assicurare che non possano crearsi bachi, [b]shit happens[/b]: tutti i programmi avranno dei bug anche solo minimi che non sono dipendenti da un errore grammaticale o sintattico ma bensì da un errore logico (come magari dimenticarsi che l’area del quadrato non è lato alla seconda ma la somma dei lati moltiplicata per due… [b]ehi… aspettate un momento![/b]). Del resto, non siamo [ancora] macchine ed è perfettamente normale sbagliare.
Se avete letto gli scorsi articoli, ed a questo punto l’avete fatto, vi starete chiedendo sicuramente un’altra cosa: perché non hai ancora nominato quella brutta parola quale è l'[i]interprete[/i]? [b]DON’T PANIC![/b] Ci stavo appunto arrivando.
All’interno della categoria dei compilatori, tanti anni fa, c’è stata diciamo una deviazione voluta da alcuni [i]ingegneri[/i] – Sempre loro, maledetti! – del modo di scrivere linguaggi ad alto livello. Utilizzati per determinate applicazioni, vennero creati dei linguaggi che non avevano bisogno di un compilatore per essere trasformati in linguaggio macchina, ma che necessitavano invece di un [b]Interprete[/b]. Questo tipo di programma, e quindi anche il linguaggio che è collegato ad esso, differisce da un compilatore poiché ha la funzione di tradurre il codice [b]contemporaneamente alla lettura[/b] dello stesso. E’ quindi possibile avere dei vantaggi non facilmente applicabili nei linguaggi compilati come l[i]’indipendenza dall’architettura e dalla piattaforma, la riflessione (l’auto-modifica da parte del programma al suo stesso codice sorgente), la tipizzazione dinamica[/i] e molto altro ancora. Questo tipo di programmazione è l’ideale per il web poiché consente di creare linguaggi di [b]scripting[/b] facilmente utilizzabile all’interno dei contesti informatici.
Se però avete letto attentamente, avrete notato che non ho detto che i linguaggi compilati siano inferiori a quelli interpretati. I linguaggi interpretati, data la loro natura “live”, sono molto più lenti e non potranno [i]mai[/i] essere utilizzati in contesti di basso livello come driver, kernel e così via.
Tuttavia, è bene dire che esistono compilatori per [b]PHP[/b] e [b]Python[/b] come esistono anche interpreti per [b]C[/b], quindi è prettamente impossibile standardizzare questo tipo di classificazione; inoltre, ci sono dei linguaggi come il [b]Java[/b] che sono difficili da catalogare, poiché, prendendo sempre questo come esempio, esso è interpretato sulla carta ma, quando viene eseguito, diventa a tutti gli effetti linguaggio macchina tramite il suo specifico layer. Ci sono addirittura linguaggi come il [b]Lisp[/b] che utilizzano entrambe le tecniche contemporaneamente!
Lentamente, queste differenze andranno ad assottigliarsi sempre di più grazie all’aumento delle velocità e tutto probabilmente diventerà interpretato se non direttamente nativo. Non ci resta quindi che aspettare o attivarci per rendere il più presto possibile[i] presente[/i] questo [b]futuro[/b].
Link di approfondimento
-[url=http://it.wikipedia.org/wiki/Compilatore]Compilatore[/url]
-[url=http://it.wikipedia.org/wiki/Interprete_(informatica)]Interprete[/url]
-[url=http://it.wikipedia.org/wiki/Java_Virtual_Machine]Java Virtual Machine[/url]
-[url=https://leganerd.com/2011/05/09/propa-basi-ed-acidi-dei-linguaggi-di-programmazione/]ProPa: Basi ed Acidi dei linguaggi di programmazione[/url]
-[url=https://leganerd.com/2011/05/02/storia-dei-linguaggi-di-programmazione/]ProPa: Storia dei linguaggi di programmazione[/url]
[more]Mi dispiace di essermi fatto attendere. Purtroppo gli esami sono una brutta bestia ed un articolo del genere me lo devo preparare a modo. Come avete notato, ora molti termini stanno diventando in inglese ed io non posso farci nulla. Sappiate che se volete conoscere la programmazione, l’inglese ne è un fondamentale tanto quanto la matematica.
Prossimo articolo, per la gioia di @zed, deeeeeebugging![/more]