Scaricare la presentazione
1
Fondamenti di Informatica
Programmi e Linguaggi di Programmazione Prof. Michele Amoretti Fondamenti di Informatica a.a. 2007/2008
2
Sommario Definizione di programma
Modalità di esecuzione: compilazione VS interpretazione Linguaggi di programmazione Linguaggi a basso livello Linguaggi ad alto livello Programmazione strutturata Programmazione procedurale Programmazione a oggetti
3
Definizione di programma
Se per risolvere un certo problema esiste un algoritmo, cioè un procedimento infallibile, che può essere descritto in modo non ambiguo fino ai dettagli, e conduce sempre all'obiettivo desiderato in un tempo finito allora esistono le condizioni per affidare questo compito a un computer, semplicemente descrivendo l'algoritmo in questione in un programma scritto in un opportuno linguaggio comprensibile alla macchina. La descrizione di un algoritmo per la soluzione di un problema P in un linguaggio di programmazione L, e cioè un programma in L, è costituito da una sequenza finita di istruzioni in L la cui esecuzione da parte del calcolatore porta (o dovrebbe portare) alla risoluzione di P.
4
Struttura di un programma
Il codice sorgente (= testo) di un programma è tipicamente formato da: Una parte di dichiarazioni, che ha lo scopo di dichiarare tutte le variabili utilizzate dal programma, con il loro tipo, che specifica l’insieme dei valori che le variabili possono assumere e le operazioni che su di esse possono essere esguite. Una parte di istruzioni, che descrive l’implementazione dell’algoritmo risolutivo utilizzato. Es. in Java int a,b,t; // dichiarazione di 3 variabili di tipo int (4 byte) a = 10; // istruzioni di assegnamento b = 5;
5
Modalità di esecuzione: compilazione VS interpretazione
La compilazione di un programma consiste nell’analisi delle istruzioni del codice sorgente (CS) da parte di un programma traduttore, il compilatore, al fine di generare l’equivalente (ottimizzato) programma in codice binario, detto programma oggetto (PO). La successiva fase di “linking” con altri programmi oggetto (es. librerie di funzioni) produce il programma eseguibile dalla macchina hardware. L’esecuzione di quest’ultimo necessita il caricamento dello stesso in memoria. CS PO LIB EXE Compilatore Editor Linker Loader Programma in memoria
6
Modalità di esecuzione: compilazione VS interpretazione
L’interpretazione di un programma consiste nell’analisi e immediata esecuzione delle sue istruzioni, una alla volta in modo sequenziale, da parte di un programma apposito, l’interprete. Rispetto al compilatore, l’interprete genera codice macchina molto meno ottimizzato, perché non ha una visione globale del programma. Vengono compilati la maggior parte dei linguaggi di programmazione “convenzionali”, come ad esempio l’assembly, il Pascal, il C e il C++. Vengono interpretati, invece, i linguaggi “non convenzionali”, quali il Prolog e il LISP. Anche il linguaggio macchina, in un certo senso, è interpretato (dall’hardware del sistema di elaborazione). Esistono poi tecniche miste, per cui il programma sorgente viene tradotto in un linguaggio intermedio che viene poi interpretato. E’ il caso di Java.
7
Linguaggi di programmazione
Un linguaggio di programmazione è un formalismo per scrivere programmi per calcolatori. Come tutti i linguaggi è definito da una grammatica, cioè una raccolta di regole che definiscono il lessico (vocabolario del linguaggio) la morfologia (classificazione degli elementi lessicali) la sintassi (struttura delle istruzioni) la semantica (significato delle istruzioni) del linguaggio. Essendo i linguaggi di programmazione molto semplici e le istruzioni inequivocabili, dato che devono essere eseguite da una macchina, non si parla di pragmatica (influenza del contesto sull’interpretazione dei significati).
8
Linguaggi di programmazione
Dal punto di vista lessicale, i linguaggi di programmazione presentano tipicamente un insieme di “parole riservate”, che non possono essere utilizzate dal programmatore come nomi di variabili, perché hanno uno scopo ben preciso (stabilito dalla morfologia del linguaggio). Tutte le combinizioni di caratteri (consentiti) che non sono parole riservate, possono essere usate come nomi di variabili. Es. in Java non posso chiamare una variabile “for” perché quell’elemento lessicale è una parola riservata che definisce un comando ben preciso (iterazione)
9
Linguaggi di programmazione
Dal punto di vista morfologico, i linguaggi di programmazione usano tre categorie di parole: le variabili gli operatori i comandi che unite fra di loro secondo certe regole sintattiche formano le istruzioni.
10
Linguaggi di programmazione
La sintassi di un linguaggio di programmazione stabilisce le sequenze accettabili delle parole del linguaggio. La notazione più ampiamente utilizzata per rappresentare la sintassi di un linguaggio di programmazione è detta BNF (Backus-Naur Form), dal nome dei suoi progettisti John Backus e Peter Naur. Generica regola BNF: lato sinistro ::= definizione Dove il lato sinistro è il nome di una singola categoria grammaticale. Es. <intero con segno> ::= <segno> <numero> <segno> ::= +|-|Λ <numero> ::= <cifra>|<cifra><numero> <cifra> ::= 0|1|2|3|4|5|6|7|8|9
11
Linguaggi di programmazione
Le regole semantiche di un linguaggio sono quelle per cui, ad esempio, la frase “i gatti abbaiano” viene considerata sbagliata, anche se lessicalmente e sintatticamente corretta. Quali sono le istruzioni semanticamente errate nei linguaggi di programmazione? Es. char a; float b; int somma; somma = a + b; // sto sommando variabili di tipo diverso e pretendo // di ottenere un risultato di tipo ancora diverso
12
Linguaggi di programmazione
Attenzione! La semantica di un linguaggio di programmazione è facilmente formalizzabile (anche se spesso ci si limita alle spiegazioni in linguaggio naturale). E’ difficile invece formalizzare la semantica di un programma (= il significato delle operazioni svolte dal programma). La macchina non capisce il senso dei programmi, si limita ad eseguire istruzioni che gli vengono presentate (dopo compilazione o interpretazione) in forma di sequenze di bit. Se la macchina capisse il senso di quello che deve fare, potrebbe ad esempio cercare di ottimizzare un programma da sola, o magari cercare in Internet un programma analogo ma che ha prestazioni migliori!
13
Linguaggi a basso livello
Sono strettamente dipendenti da una specifica macchina hardware (in particolare dalla CPU). Il più “semplice” in termini di sintassi è il linguaggio macchina, le cui istruzioni sono scritte direttamente in notazione binaria (sequenze di 0 e 1) e sono quindi molto lontane dal linguaggio naturale e molto complesse da utilizzare per il programmatore. Le istruzioni in linguaggio macchina sono lette ed eseguite (“interpretate”) direttamente dalla macchina hardware. Generalmente per ogni linguaggio macchina esiste anche una versione simbolica, detta linguaggio assembly. I comandi sono espressi da codici mnemonici (= facili da ricordare). E’ più immediato da utilizzare del linguaggio macchina, ma il codice sorgente risulta comunque complesso e non è portabile tra famiglie di processori diverse.
14
Linguaggi a basso livello
Tra le istruzioni in linguaggio assembly e quelle in linguaggio macchina c’è un mapping 1-a-1. Il compilatore che traduce da assembly a linguaggio macchina è detto assembler. Es. Istruzione in linguaggio Assembly 8086: MOV AH, 11 Istruzione in linguaggio macchina: i primi 4 bit rappresentano l’Operation Code, che identifica il tipo di istruzione; il bit W vale 1 se l’operando è su 16 bit, 0 se è su 8 bit: nel caso in esame W = 0; i 3 bit Reg indicano il registro destinazione, secondo la tabella indicata: nel caso in esame Reg = 100; gli 8 bit di dato contengono l’operando: nel caso in esame 11(10) = (2).
15
Linguaggi ad alto livello
Nascondono, in modo più o meno completo, le caratteristiche proprie delle diverse macchine hardware ed offrono al programmatore una sintassi molto più vicina al linguaggio naturale rispetto ai linguaggi a basso livello. Consentono di descrivere il problema in modo intuitivo ed espressivo. Permettono di trattare con facilità: formule matematiche operazioni di I/O strutture dati complesse Mettono a disposizione strutture dati e costrutti logici (ad es. per il controllo del flusso). Il codice sorgente risulta più leggibile e documentabile.
16
Linguaggi ad alto livello
Hanno caratteristiche diverse: offrono forme espressive appropriate per alcuni problemi specifici. Es. FORTRAN (problemi scientifici) COBOL (problemi commerciali) BASIC, Pascal (problemi generici non troppo complessi) C, C++ (controllo di dispositivi elettronici, automazione) Java, C# (GUI, applicazioni distribuite) LISP (intelligenza artificiale) PROLOG (dimostrazione automatica di teoremi) I linguaggi più diffusi hanno il compilatore per quasi tutti i sistemi operativi e calcolatori presenti sul mercato.
17
Linguaggi ad alto livello
Linguaggi imperativi Sono linguaggi convenzionali, basati sulla nozione di istruzione di macchina e di memorizzazione di valori in celle di memoria (quindi “vedono” il calcolatore come da modello di Von Neumann). Es. BASIC, FORTRAN, C, JAVA, ecc. Linguaggi funzionali Sono linguaggi non convenzionali, basati sul concetto di funzione. Le funzioni vengono definite anche in modo ricorsivo, e utilizzando costrutti per il controllo di flusso. Es. LISP Linguaggi dichiarativi basati sulla logica Sono linguaggi non convenzionali, basati sui concetti di asserzione condizionata e interrogazione. Es. PROLOG
18
Programmazione strutturata
Le idee chiave della programmazione strutturata si possono ricondurre alla critica della struttura di controllo del salto incondizionato (o GOTO, "vai a"), che rappresentava, negli anni '60, lo strumento fondamentale per la scrittura di programmi complessi. In un celebre articolo del 1968, “Goto statement considered harmful”, Edsger Dijkstra discusse approfonditamente gli effetti deleteri del goto sulla qualità del software, e in particolare sulla sua leggibilità e modificabilità (il cosiddetto problema dello spaghetti code).
19
Programmazione strutturata
Un'altra celebre pubblicazione che risultò fondamentale all'affermarsi della programmazione strutturata fu “Flow Diagrams, Turing Machines, and Languages with Only Two Formation Rules”, in cui Corrado Böhm e Giuseppe Jacopini dimostrarono il loro celebre teorema. Teorema di Jacopini-Bohm Qualsiasi programma scritto usando il GOTO può essere riscritto senza, a patto di avere a disposizione altri tre tipi di strutture di controllo: sequenza, alternativa e iterazione.
20
Programmazione strutturata
Sequenza:
21
Programmazione strutturata
Alternativa:
22
Programmazione strutturata
Iterazione:
23
Programmazione strutturata
Il seguente programma è un esempio banale di spaghetti code in BASIC, che stampa su schermo la sequenza di numeri da 1 a 10 e il loro quadrato. 10 DIM i 20 i = 0 30 i = i + 1 40 IF i <> 10 then GOTO 70 50 PRINT "Programma terminato." 60 END 70 PRINT i & " al quadrato = " & i * i 80 GOTO 30 Si noti come le istruzioni di GOTO introducano una dipendenza dai numeri di riga del programma, e come il flusso di esecuzione salti in maniera impredicibile da una zona all'altra.
24
Programmazione strutturata
Ecco un esempio di codice equivalente scritto con uno stile di programmazione strutturato: DIM i FOR i = 1 to 10 PRINT i & " al quadrato = " & i*i NEXT PRINT "Programma terminato." Il costrutto “for” evita di dover usare il GOTO.
25
Programmazione strutturata
In C il GOTO si può usare (purtroppo!): // ciclo che stampa gli interi da 10 a 1 int n=10; loop: cout << n << ", "; n--; if (n>0) goto loop; Usando però il costrutto sintattico iterativo “for”: for (int n=10; n>0; n--) il codice è molto più sintetico e leggibile!
26
Programmazione strutturata
In Java l’istruzione GOTO esiste come “parola riservata” del linguaggio, ma non è più implementata perché considerata strumento di cattiva programmazione. Ci sono comunque dei meccanismi (assolutamente “legali”) che producono l’effetto del GOTO, ad esempio: l’istruzione break Es. for (i = 0; i < arrayOfInts.length; i++) { if (arrayOfInts[i] == searchFor) break; } l’istruzione continue Es. for (int i = 0; i < max; i++) { if (searchMe.charAt(i) != 'p') continue; numPs++;
27
Programmazione procedurale
Nella programmazione procedurale si adotta la metodologia di suddivisione del problema in sottoproblemi detta “divide et impera”. Dividendo un problema in porzioni più piccole è possibile governare la complessità che altrimenti ci sovrasterebbe se si guardasse il problema nella sua interezza. Adottando questa tecnica, il codice del programma risulta diviso in moduli, detti sottoprogrammi o anche procedure o funzioni, ciascuno dei quali svolge una precisa porzione del compito complessivo. nome + tipo dei parametri signature della procedura Vantaggi: - maggiore leggibilità dei programmi - possibilità di riuso del codice.
28
Programmazione procedurale
In genere c’è una procedura principale (main) che ha il compito di invocare ciascun sottoprogramma ogni volta che si deve affrontare il compito cui questo è proposto. Es. in linguaggio C #include <stdio.h> int main() { printf("Hello world\n"); return 0; }
29
Programmazione orientata agli oggetti (OOP)
E’ un paradigma di programmazione in cui: un'unica entità (detta classe) raggruppa i dati (detti attributi) le procedure (dette metodi) che operano sui dati. Una classe definisce un tipo complesso. Una variabile il cui tipo è definito da una classe è detta istanza della classe, o più brevemente oggetto. E’ l’evoluzione della programmazione procedurale. La modularità di un programma viene realizzata progettando e realizzando il codice sotto forma di classi che interagiscono tra di loro. Il programma ideale, realizzato applicando i criteri dell'OOP, è completamente costituito da oggetti che interagiscono gli uni con gli altri.
30
Oggetti Sono astrazioni che descrivono • oggetti fisici,
• concetti astratti che fanno parte del problema (o della soluzione). Caratterizzati da • uno stato, • un insieme di servizi che offrono agli altri oggetti. I valori degli attributi determinano lo stato. I metodi (che non sono solo di tipo get e set!) rappresentano i servizi offerti. Es. un telefono cellulare • stato: carica della batteria, potenza del segnale, … • servizi: chiama un numero, rispondi alla chiamata, …
31
Oggetti Es. in linguaggio Java attributi (variabili di stato)
public class CellularPhone { private int field = 0; private int battery = 0; public void answer() { … } public void call(String number) { public class Caller { public static void main(String args[]) { CellularPhone cellPhone = new CellularPhone(); cellPhone.call(“ ”); attributi (variabili di stato) metodi (servizi offerti) classe principale: solo lei contiene il metodo main() oggetto di tipo CellularPhone
32
Storia dell’OOP - 1967: Simula (1967)
- anni '70: Smalltalk e varie estensioni del Lisp - anni '80: C++, Objective C, Object Pascal, ecc. - anni '90: Eiffel, Java Oggi i linguaggi più usati sono quelli che supportano anche ma non solo il paradigma di programmazione orientata agli oggetti, come C++, Java, Delphi, Python, C#, Visual Basic .NET. Un linguaggio di programmazione per poter essere definito ad oggetti deve possedere le tre proprietà seguenti: Incapsulamento Ereditarietà Polimorfismo
33
Incapsulamento L'incapsulamento è la proprietà per cui un oggetto contiene ("incapsula") al suo interno gli attributi (dati) e i metodi (procedure) che accedono ai dati stessi. Gestito in maniera intelligente, l'incapsulamento permette di vedere l'oggetto come una black-box, cioè una scatola nera di cui, attraverso l‘interfaccia sappiamo cosa fa e come interagisce con l'esterno ma non come lo fa. E’ buona pratica definire tutti gli attributi come private; quelli che si vogliono esporre vengono resi accessibili solo attraverso metodi public di tipo get e set.
34
Ereditarietà Meccanismo molto importante che permette di derivare nuove classi a partire da classi già definite. Le classi derivate possono aggiungere nuovi membri rispetto alla superclasse, oppure modificare il comportamento dei metodi della superclasse (ridefinendone il codice).
35
Ereditarietà Se un oggetto di una sottoclasse può essere utilizzato al posto di un'istanza della superclasse, il tipo della classe derivata è detto sottotipo (in questo caso l’operazione di subclassing corrisponde a quella di subtyping). Una sottoclasse che voglia definire un sottotipo può ridefinire (= implementare diversamente) i metodi della superclasse (vedi Polimorfismo), ma non può eliminarli sintatticamente nè modificare le loro signature. In alcuni linguaggi una sottoclasse può eliminare o cambiare le proprietà di accesso ad un metodo della superclasse, il che fa sì che l'operazione di subclassing non sia corrispondente a quella di subtyping.
36
Polimorfismo E’ il meccanismo per cui classi derivate possono implementare in modo differente i metodi e le proprietà delle proprie superclassi, rendendo possibile che gli oggetti appartenenti a delle sottoclassi di una stessa classe rispondano diversamente alle stesse istruzioni. Es. In una gerarchia in cui le classi Cane e Gatto discendono dalla super-classe Animale potremmo avere il metodo cosaMangia() che restituisce la stringa "osso" se eseguito sulla classe Cane e "pesce" se eseguito sulla classe Gatto. Buona regola di programmazione: quando una classe derivata ridefinisce un metodo, il nuovo metodo deve avere la stessa semantica di quello ridefinito, dal punto di vista degli utenti della classe.
37
Polimorfismo Il polimorfismo è particolarmente utile quando la versione del metodo da eseguire viene scelta sulla base del tipo di oggetto effettivamente assegnato a una variabile a runtime (invece che al momento della compilazione). Questa funzionalità è detta binding dinamico (o late-binding). In Java: - interface (definisce solo le signature dei metodi pubblici; non ha costruttore; non può essere istanziata perché i metodi non sono implementati) - class (definisce e implementa metodi pubblici e privati) Una class puà implementare diverse interface, ma estendere una sola classe. Una interface può estendere una sola interface. Una classe o singoli metodi possono essere dichiarati abstract per obbligare i programmatori a ridefinirli nelle classi derivate.
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.