Il software: dall’algoritmo al linguaggio macchina Raffaella Brighi, a.a. 2006/07 Lezione II – 23 aprile 2007 Corso di Informatica A.A. 2006-07 CdL Operatore Giuridico d’Impresa. Linguaggi di programmazione Un programma è la rappresentazione formale (codifica) di un algoritmo progettata per essere eseguita da un computer. I linguaggi di codifica, che possono avere diversi livelli di astrazione, vanno dal linguaggio macchina ai cosiddetti linguaggi di programmazione di alto livello. Linguaggio macchina Linguaggio assembler Linguaggi ad alto livello 1 Il linguaggio macchina In un calcolatore i dati e le istruzioni di programma sono codificate in forma binaria, cioè come sequenza di 0 e di 1. Un calcolatore può trattare diversi tipi di dati: numeri, testi, immagini, ecc. I dati sono espressi in formato binario (ad esempio i numeri naturali da 0 a 255 sono rappresentati in otto bit, i caratteri sono tradotti in numeri seguendo una codifica, ad es. ASCII o Unicode, e poi rappresentanti in forma binaria) Anche le istruzioni sono codificate come sequenza di bit e sono composte da un campo codice operativo, che indica l’operazione da compiere (es. somma, confronto, ecc.) e da un campo operando che indica gli indirizzi dove recuperare i dati su cui operare e dove copiare i risultati. L’insieme delle istruzioni accettate dal sistema di elaborazione e il loro sistema di codifica è chiamato linguaggio macchina. Ogni CPU (esecutore delle istruzioni del programma) è caratterizzata funzionalmente dal suo linguaggio macchina, cioè dall’insieme delle istruzioni che è in grado di eseguire e dalle modalità di rappresentazione degli operandi. È impossibile far eseguire un programma scritto per una Sun workstation con il processore Sparc ad un PC IBM con un processore Intel. Qualunque algoritmo può essere scritto direttamente in linguaggio macchina. 2 Linguaggi assembler L’assembler è una abbreviazione simbolica del linguaggio macchina: consente di esprimere gli algoritmi con una codifica simbolica anziché binaria. Ogni simbolo corrisponde ad una istruzione in codice binario. La macchina traduce i simboli nella corrispondente forma binaria. Le primitive del linguaggio assembly sono però le stesse del linguaggio macchina corrispondente: i programmi sono ancora intrinsecamente legati all’architettura della macchina per cui sono scritti. Il programmatore è ancora obbligato a ragionare secondo i passi incrementali del linguaggio macchina (linguaggio di basso livello). Linguaggi ad alto livello Consentono di descrivere i problemi ad un livello di astrazione di poco inferiore a quello degli algoritmi, quindi vicino al problema da risolvere piuttosto che all’architettura della macchina. Sono dotati di un insieme di primitive di alto livello (ognuna delle quali corrisponde ad una sequenza di operazioni elementari) che consentono di trattare oggetti complessi senza preoccuparsi dei dettagli. Un programma (compilatore/interprete) traduce il codice scritto con questi linguaggi in codice macchina. Java, C++, Visual Basic, Pascal, ecc sono linguaggi ad alto livello 3 Caratteristiche generali di un linguaggio di programmazione Ogni linguaggio di programmazione è caratterizzato da: Vocabolario insieme di parole chiave e simboli ammessi per comporre le istruzioni (identificatori) Sintassi che specifica le regole di composizione delle istruzioni (es. per Java un identificatore non puo’ iniziare con una cifra, le parentesi graffe racchiudono classi e metodi). Semantica che specifica il significato delle istruzioni; definisce quello che accade quando l’istruzione viene eseguita (non ambiguità) Vocabolario, sintassi e semantica sono definite a priori, in modo univoco, per ogni linguaggio di programmazione. Hallo World! public class HalloWorld { public static void main(String[] args) { System.out.println("Ciao mondo!!"); } } Questo programma stampa in output (sulla console) la scritta “ciao mondo”. public class static void main sono identificatori del linguaggio di programmazione: vocabolario la posizione delle parantesi graffe segue regole sintattiche l’istruzione System.out.println significa (semantica) “scrivi in output” 4 Dal file sorgente al programma eseguibile (codice oggetto) Il programma nella sua forma originale, cioè cosi come scritto dal programmatore, si dice “ codice sorgente”. Per scrivere il codice sorgente occorre un editor. Il codice sorgente per poter essere eseguito deve essere tradotto in linguaggio macchina. Esistono due categorie di software per tradurre il codice sorgente: COMPILATORI INTEPRETI Compilatori e interpreti sono programmi. Per ogni architettura si può progettare il compilatore/interprete per il linguaggio L dopodichè la macchina potrà eseguire qualsiasi programma scritto in linguaggio L Programma sorgente (S) COMPILATORE Programma oggetto (O) 5 Il compilatore Il compilatore è un programma, che traduce un programma sorgente (S) scritto in un linguaggio L in un nuovo programma, detto programma oggetto (O), equivalente a S. Nei compilatori tradizionali il linguaggio oggetto è il linguaggio macchina. Un programma detto linker collega tutti i moduli oggetto (un programma può essere composto da più moduli) creati dal compilatore e genera il programma eseguibile. Il programma così generato potrà essere eseguito in qualsiasi momento. Il processo di traduzione avviene una sola volta. La traduzione e l’esecuzione si realizzano in momenti diversi. L’interprete L’ interprete è un programma (I) che esegue un programma (P) scritto in un linguaggio ad alto livello (L), traducendo un’istruzione alla volta in linguaggio macchina. L’interprete preleva un’istruzione del programma P, la decodifica, la traduce in linguaggio macchina e la manda in esecuzione, quindi passa all’istruzione successiva di P (questo significa che un’istruzione racchiusa in un ciclo viene tradotta per ogni iterazione del ciclo). I programmi interpretati sono tradotti ed eseguiti nello stesso momento. 6 Vantaggi/svantaggi: Compilazione: La traduzione viene effettuata una sola volta, questo porta migliori prestazioni in esecuzione. Il programma compilato è più veloce del programma interpretato. Lo spazio di memoria occupato da un programma compilato è minore. Un programma compilato può essere eseguito autonomamente, senza la presenza del compilatore, mentre un programma interpretato richiede l’esecuzione contemporanea del programma interprete Interpretazione: è possibile modificare il programma interpretato ed eseguirlo immediatamente, così da verificare l’effetto delle modifiche apportate, mentre la modifica del programma compilato richiede la correzione del programma sorgente e una nuova compilazione. Esempio di creazione, compilazione ed esecuzione di un programma Java 7 Processo di traduzione ed esecuzione del codice Java Java combina l’uso di un compilatore e di un interprete Il compilatore genera un bytecode (linguaggio a basso livello) Java indipendente dalla piattaforma hw. L’interprete Java legge il bytecode e lo traduce e lo esegue in una specifica macchina. Si ha bisogno di un interprete del bytecode Java per ogni processore. Editor codice sorgente compilatore file bytecode macchina virtuale programma in esecuzione librerie 8 Tipi di errori Nella stesura di un programma si presentano tre categorie di errori: Errori in compilazione: sono errori sintattici o assegnazioni di tipi di dato incompatibili. Questi errori vengono evidenziati dal traduttore durante la fase di compilazione/interpretazione. Se le istruzioni non sono corrette il programma non può essere tradotto. Errori in fase di esecuzione del programma: comportano la terminazione anomala del programma. Ad esempio divisione per zero. Errori logici: il programma viene compilato ed eseguito senza problemi ma perviene a risultati sbagliati. Significa che vi è un errore nella progettazione dell’algoritmo. inizio modifica programma compila programma errore di compilazione? si si no collauda programma errore di esecuzione? no fine 9 Classificazione dei linguaggi Paradigma imperativo (o procedurale): la programmazione è una sequenza di comandi (istruzioni) che esprime un algoritmo. Passo passo si definiscono le variazioni degli stati possibili del sistema (assegnazioni di variabili, salti di istruzione, cicli ecc.) Paradigma dichiarativo: il programma descrive il problema specifico non come risolverlo; alla base ci sono algoritmi molto generali che risolvono classi di problemi. Un esempio è il Prolog, che si basa sulla logica del primo ordine per risolvere i problemi Paradigma funzionale: concepisce il processo di sviluppo dei programmi come connessioni di ‘scatole nere’ predefinite (chiamate funzioni, secondo la notazione matematica), ognuna delle quali accetta un valore in ingresso e produce un valore in uscita. Esempio di questa generazione di linguaggi è il LISP (anni ’60). Paradigma ad oggetti: si basa sulla definizione di unità di programmazione attive, chiamate classi di oggetti, caratterizzate da proprietà (dati) e metodi, cioè operazioni che la classe può compiere (è il comportamento dell’oggetto della classe). L’assembler e i linguaggi imperativi (fortran, basic, c) sono astrazioni rispetto al linguaggio macchina ma costringono a pensare ancora in termini di struttura del computer (spazio delle soluzioni) anziché di struttura del problema (spazio dei problemi). L’approccio OO (object oriented) consente di descrivere il problema nei suoi propri termini. Il programmatore può rappresentare elementi nello spazio dei problemi. Il programma si adatta al gergo del problema. Ogni oggetto assomiglia ad un piccolo computer: ha uno stato e possiede operazioni che gli si può chiedere di eseguire. Esempio sono le icone di un’interfaccia grafica, esse possono essere rappresentate come oggetti che comprendono le procedure con le quali l’oggetto risponde a varie operazioni (es. clic del mouse, ecc.). 10 Distribuzione del software Un programma può essere distribuito in due diverse modalità: codice chiuso - fornendo il solo codice oggetto, vale a dire il codice direttamente eseguibile dall’elaboratore codice aperto - fornendo all’utilizzatore anche il codice sorgente La modalità di distribuzione (codice aperto/chiuso) non implica la commercializzazione/non commercializzazione e la tutela della proprietà del sw. Reverse engineering: (decompilare un programma) vuol dire ripercorrere a ritroso le fasi attraverso le quali viene creato il software, partendo dal codice oggetto sino ad arrivare al sorgente e, quindi, ai principi logico matematici alla base di ogni programma. L’open source (software aperto) Definizione: applicazioni informatiche che rendono disponibile il codice sorgente perché possa essere liberamente studiato, copiato, modificato e ridistribuito. Open source non è sinonimo di gratuito. L’idea di fondo è che quando un utente è entrato in possesso di una copia di un programma libero ha il diritto di utilizzarlo secondo quanto previsto dalla licenze (tipicamente può modificarlo, copiarlo, installarlo, ridistribuirlo) Esistono diverse forme di licenze e modelli per consentirne la commercializzazione. Vantaggi in termini di: contenimento dei prezzi trasparenza e sicurezza non dipendenza da un unico fornitore elevata riusabilità accessibilità per le piccole realtà di sviluppo (www.opensourece.org) 11 La direttiva 19 dicembre 2003 del MIT La direttiva del 19 dicembre 2003 del Ministro per l’Innovazione e le Tecnologie pubblicata sulla G.U. n. 31 del 7 febbraio 2004, in materia di sviluppo ed utilizzo dei programmi informatici da parte delle PA, sostiene la possibilità di acquisizione ed utilizzo di programmi informatici "open source” nella PA. Punti fondamentali: la trasferibilità ad altre amministrazioni delle soluzioni acquisite; l’interoperabilità e la cooperazione applicativa tra le amministrazioni; la non dipendenza da un unico fornitore o da un’unica tecnologia proprietaria; la disponibilità del codice sorgente per ispezione e tracciabilità; l’esportabilità di dati e documenti in più formati, di cui almeno uno di tipo aperto I programmi e dati I programmi eseguono istruzioni sui dati. I dati costituiscono l’ingresso (input) e l’uscita (output) dei processi di elaborazione. L’attività di raccolta, organizzazione e conservazione dei dati costituiscono uno dei principali compiti dei sistemi informatici (elenchi di utenti telefonici, elenchi di iscritti ad una facoltà, i saldi dei conto correnti bancari, ecc.) I sistemi informatici garantiscono la conservazione dei dati, l’aggiornamento, la trasmissione. In molte applicazioni i dati sono più stabili rispetto ai programmi utilizzati per elaborarli. Spesso le procedure vengono modificate, i dati invece sono ereditati (con opportune conversioni). I dati sono una risorsa da sfruttare e proteggere. 12 I dati possono essere: memorizzati nella memoria centrale e quindi “volatili”. Tali dati sono utilizzati durante l’esecuzione del programma. memorizzati nelle memorie di massa (cd-rom, floppy, hard-disk, nastri, ec..), cioè archiviati. In questo caso i dati si dicono persistenti. Ogni tipo di dato ha una propria rappresentazione in memoria, in forma codificata e organizzata in modo compatibile con la tecnologia utilizzata. I linguaggi di programmazione ad alto livello consentono di trattare i dati in modo astratto, prescindendo cioè da come sono rappresentati nella macchina. Riferimenti normativi Legge 22 aprile 1941 n. 633 – Protezione del diritto d’autore e di altri diritti connessi al suo esercizio. Direttiva del 18 dicembre 2003 del Ministro per l’Innovazione e le Tecnologie pubblicata sulla G.U. n. 31 del 7 febbraio 2004 DIRETTIVA 2003/98/CE DEL PARLAMENTO EUROPEO E DEL CONSIGLIO del 17 novembre 2003 relativa al riutilizzo dell'informazione del settore pubblico DECRETO LEGISLATIVO: Attuazione della direttiva 2003/98/CE relativa al riutilizzo di documenti nel settore pubblico. 28 ottobre 2005 Decreto Legislativo del 7 marzo 2005, n.82 Codice dell'amministrazione digitale( G.U. n. 112 del 16-5-2005 Suppl. Ordinario n. 93) 13