Linguaggi per la rappresentazione di algoritmi
Transcript
Linguaggi per la rappresentazione di algoritmi
Sommario ! Linguaggi formali per la rappresentazione di algoritmi ! Linguaggi di programmazione: linguaggio macchina e linguaggi di alto livello ! Uno pseudo-linguaggio per la rappresentazione di algoritmi: sintassi e semantica Linguaggi per la rappresentazione di algoritmi Elementi di Informatica Docente: Giorgio Fumera ! Testi " Corso di Laurea in Edilizia Facoltà di Architettura A.A. 2009/2010 " di riferimento Sciuto et al., Introduzione ai sistemi informatici Ceri et al., Informatica: arte e mestiere 2 Linguaggi formali Sintassi e semantica: esempio Linguaggio naturale: sintassi " ! In riferimento a un dato esecutore, un linguaggio per la rappresentazione di algoritmi deve essere non ambiguo " ! Questa caratteristica è propria dei linguaggi formali, la cui sintassi e semantica sono rigorosamente definite " " “il cielo è azzurro”, “chi non studia non supera l'esame” sono frasi sintatticamente corrette in italiano “cielo il azzurro è”, “casa gatto giocare”, “anvy efyw jryc” sono frasi sintatticamente non corrette Semantica " sintassi: regole per definire le “frasi corrette” del linguaggio, cioè le frasi alle quali sia possibile attribuire un significato semantica: regole che definiscono il significato delle “frasi corrette” definisce il significato di frasi come “il cielo è azzurro”, “chi non studia non supera l'esame” Tuttavia il linguaggio naturale non è formale, poiché è ambiguo: il significato di una frase può dipendere dal contesto (es.: qual è il significato di “una vecchia porta la sbarra” ?) La sua sintassi e semantica sono troppo complesse per poter essere descritte in modo preciso e completo 3 4 Esempio di linguaggio formale Calcolatori, linguaggio macchina e programmi Il linguaggio della matematica ! I linguaggi per la rappresentazione di algoritmi devono essere formali L’esecutore di interesse nell’informatica è il calcolatore. Operazioni eseguibili: " semplici operazioni logico-aritmetiche su sequenze di bit (somma, confronto, ecc.: ALU) " trasferimento dati tra CUP e memoria o periferiche ! Per poter essere eseguiti da un calcolatore, gli algoritmi " devono essere espressi in un linguaggio formale come sequenze di istruzioni corrispondenti a tali operazioni " devono essere codificati in forma binaria ! Il linguaggio corrispondente è detto linguaggio macchina ! ! Algoritmi espressi in un linguaggio comprensibile da un calcolatore sono detti programmi 5 6 I linguaggi di alto livello Caratteristiche dei linguaggi di alto livello ! Per Sono più vicini al linguaggio naturale... un essere umano è difficile scrivere e leggere programmi in linguaggio macchina " " " le operazioni eseguibili sono troppo elementari: gli algoritmi devono essere espressi a un livello di dettaglio molto alto... ...e codificati in forma binaria " ! Gli algoritmi devono essere formulati da esseri umani, che usano con facilità il linguaggio naturale... ...ma devono essere espressi in linguaggio macchina per essere comprensibili dai calcolatori consentono di esprimere operazioni più complesse rispetto al linguaggio macchina, e più vicine a quelle usate dagli esseri umani: gli algoritmi vengono espressi a un livello di dettaglio inferiore esprimono le istruzioni con parole del linguaggio naturale, non codificate in forma binaria ...ma non sono comprensibili da un calcolatore... Sono però linguaggi formali, quindi possono essere tradotti in modo esatto in linguaggio macchina La stessa operazione di traduzione può essere descritta da un algoritmo, e quindi può essere eseguita automaticamente dagli stessi calcolatori! ! Un compromesso: linguaggi di alto livello per la rappresentazione di algoritmi 7 8 Tipologie di linguaggi di alto livello Alcuni dei principali linguaggi di alto livello Si distinguono principalmente per i tipi di algoritmi (calcoli numerici, elaborazione di dati simbolici, ecc.) e le strutture dati (vettori, liste, ecc.) che consentono di esprimere con maggiore semplicità Si parla di paradigmi di programmazione ! FORTRAN (imperativo): applicazioni scientifiche, calcoli numerici (funzionale): elaborazione simbolica, applicazioni di Intelligenza Artificiale ! COBOL (imperativo): gestione dati ! Pascal (imperativo): usato prevalentemente per scopi didattici ! C (imperativo), C++ (orientato agli oggetti): programmi di sistema, applicazioni scientifiche, calcoli numerici ! Java (orientato agli oggetti): applicazioni Internet (siti Web “dinamici”, ecc.) e per dispositivi mobili (telefoni cellulari, ecc.) ! Lisp – procedurali: modifica esplicita del contenuto delle celle di memoria, istruzioni di “salto”, ecc. – funzionali: applicazione di funzioni (in senso matematico) ad argomenti – dichiarativi: si esprime cosa si vuole ottenere, non come ottenerlo – orientati agli oggetti: i dati sono visti come oggetti caratterizzati dall'insieme di operazioni che possono essere svolte su di essi 9 10 Linguaggi interpretati e compilati Linguaggi interpretati e compilati Linguaggi compilati (C, C++, Java, ecc.) Linguaggi interpretati (BASIC, Lisp, ecc.) Per poter essere eseguito, un programma deve prima essere interamente tradotto in linguaggio macchina. La traduzione viene eseguita da un programma apposito detto compilatore. Nota: il compilatore è lo stesso per tutti i programmi! Compilatore Programma scritto in un linguaggio di alto livello (codice sorgente) 00100101 01010010 10100101 10010100 11110100 01100100 sono interattivi: ogni singola istruzione scritta dall'utente viene subito tradotta in linguaggio macchina da un programma detto interprete, ed eseguita linguaggio di alto livello linguaggio macchina istruzione 1 Interprete 00101101 Esecuzione istruzione 2 Interprete 10100101 Esecuzione istruzione 3 Interprete 11101010 Esecuzione Esecuzione Programma scritto in linguaggio macchina (codice oggetto) 11 ... 12 Pseudo-linguaggi Ambienti di programmazione ! Ogni linguaggio ha in genere un proprio ambiente di programmazione: un insieme di strumenti software che facilitano agli utenti le attività di sviluppo dei programmi " " " " ! Sono linguaggi per la descrizione di algoritmi simili a quelli di alto livello, ma non formalizzati rigorosamente, e ancora più vicini al linguaggio naturale ! Sono basati sulle principali strutture sintattiche e semantiche comuni alla maggior parte dei linguaggi di alto livello ! Sono usati per facilitare la formulazione di algoritmi: consentono di esprimerne le idee fondamentali senza vincolarsi ai dettagli di specifici linguaggi ! Non sono linguaggi di programmazione (non possono essere usati per scrivere programmi) scrittura del programma: editor di testi compilatore o traduttore individuazione e correzione degli errori: debugger librerie: insiemi di programmi che codificano algoritmi di utilità generale (funzioni matematiche, ecc.), e che possono essere inclusi nei programmi degli utenti 13 14 Obiettivo del corso Un modello astratto di esecutore ! Fornire ! Definiremo le basi per apprendere in futuro, anche autonomamente, un qualsiasi linguaggio di programmazione ! Per questo scopo, useremo uno pseudo-linguaggio che consentirà di imparare a esprimere algoritmi usando le principali strutture semantiche comuni alla maggior parte dei linguaggi di programmazione, senza entrare nei dettagli di linguaggi specifici il nostro pseudo-linguaggio in rapporto a un esecutore meccanico “astratto”: un calcolatore semplificato basato sull’architettura di Von Neumann ! Il nostro esecutore sarà composto da " " ! Lo pseudo-linguaggio che useremo è derivato dal linguaggio C, uno dei più diffusi linguaggi di alto livello " 15 una memoria suddivisa in celle, ciascuna delle quali – può contenere un singolo dato, di tre tipi diversi: un numero intero, un numero reale, un carattere – è identificata da un nome simbolico (non da un indirizzo numerico) che deve essere scelto da chi scrive l'algoritmo una perferica di ingresso e una di uscita (per es., una tastiera e un monitor) un'unità di elaborazione in grado di eseguire semplici operazioni logico-aritmetiche, modificare i valori delle celle di memoria, e inviare o ricevere dati dalle periferiche 16 Un modello astratto di esecutore Quali operazioni sa eseguire il nostro esecutore? Il nostro esecutore è in grado di eseguire solo cinque operazioni: 1) operazione di assegnamento 2) operazione di lettura 3) operazione di scrittura 4) esecuzione condizionale 5) iterazione x a alfa unità di elaborazione nomi simbolici delle celle di memoria (scelti da chi scrive un algoritmo) periferica di ingresso periferica di uscita ... ... memoria 17 18 Quali operazioni sa eseguire il nostro esecutore? Quali operazioni sa eseguire il nostro esecutore? 1) Operazione di assegnamento Consiste nella scrittura di un valore in una cella di memoria Il valore da assegnare può essere: " un numero " un carattere " il valore contenuto in un'altra cella di memoria " il risultato (un numero) di una qualsiasi espressione aritmetica costruita con cinque operatori (somma, sottrazione, moltiplicazione, divisione, resto della divisione tra interi), in cui gli operandi possono essere valori contenuti in celle di memoria Operazioni di lettura e scrittura Nota: scrivendo in una cella si cancella un eventuale valore scritto in precedenza 19 2) Lettura: consiste nell'acquisire (“leggere”) un valore (un numero o un carattere) dalla periferica di ingresso, e scriverlo in una cella di memoria 3) Scrittura: consiste nell'inviare alla periferica di uscita (“stampare”) un numero, un carattere, una sequenza di caratteri, il contenuto di una cella di memoria o il risultato di un'espressione aritmetica (definita come per l'operazione di assegnamento) Nota: ! tutti i dati di ingresso di un algoritmo devono essere acquisiti e memorizzati in celle di memoria attraverso operazioni di lettura ! tutti i risultati di un algoritmo devono essere inviati all'esterno del calcolatore attraverso operazioni di scrittura 20 Quali operazioni sa eseguire il nostro esecutore? 4) Esecuzione condizionale: consiste nell'eseguire una data sequenza di operazioni oppure un'altra, a seconda del verificarsi o meno di una condizione 5) Iterazione: consiste nel ripetere una data sequenza di operazioni, finché una data condizione è vera In entrambi i casi la condizione è definita come: " condizione semplice: confronto tra due valori (numeri o caratteri, il contenuto di celle di memoria, il risultato di espressioni aritmetiche definite come in precedenza) " condizione composta: più condizioni semplici combinate dalle congiunzioni “e”, “oppure”, “non” " operatori di confronto: “uguale” “diverso” “minore”, “minore o uguale”, “maggiore”, “maggiore o uguale” (nel caso in cui i valori da confrontare siano caratteri, si fa riferimento all'ordinamento alfabetico) Abbiamo definito quali operazioni possono essere eseguite dall'esecutore Ora vediamo esempi di algoritmi descritti usando queste operazioni In questi esempi useremo il linguaggio naturale: il nostro pseudo-linguaggio sarà descritto più avanti Nota: in questi esempi le celle di memoria verranno indicate con simboli scritti in neretto Per seguire cosa succede durante l'esecuzione dell'algoritmo è utile tenere traccia del valore memorizzato istante per istante nelle celle di memoria 21 22 Esempio Esempio Leggi un valore e scrivilo nella cella x Leggi un valore e scrivilo nella cella y Se il contenuto della cella x è maggiore del contenuto della cella y, allora stampa il valore della cella x, altrimenti stampa il valore della cella y Assegna 0 alla cella a Leggi un valore e scrivilo nella cella b Finché il contenuto di b è diverso da 0, ripeti le due istruzioni: Assegna alla cella a il risultato di a + b Leggi un valore e scrivilo nella cella b Stampa il valore di a Questo algoritmo è composto da tre operazioni: due di lettura e una condizionale (che contiene al suo interno due istruzioni di scrittura). Nell'algoritmo si usano due celle di memoria indicate con i nomi simbolici x e y Le prime due istruzioni chiedono all'esecutore di acquisire dalla periferica di ingresso due valori (si assume che si tratti di numeri) e di scriverli nelle celle x e y La terza fa sì che venga scritto nella periferica di uscita il più grande tra i due valori memorizzati nelle celle x e y 23 Questo algoritmo acquisisce dalla periferica di ingresso una sequenza di valori (si assume che siano numeri) che termina con il valore 0, ne calcola la somma e la invia alla periferica di uscita Note: " è presente un'iterazione (Finché...) che richiede di ripetere due istruzioni finché una condizione è vera; l'istruzione di scrittura successiva viene eseguita solo quando l'iterazione termina " ogni volta che viene eseguita l'istruzione di lettura, il valore letto viene memorizzato nella stessa cella (b), sostituendo il valore memorizzato in precedenza 24 Sintassi e semantica dello pseudo-linguaggio Note Ora definiamo la sintassi e la semantica del nostro pseudo-linguaggio: " sintassi: le regole per scrivere le istruzioni corrispondenti alle cinque operazioni eseguibili dall'esecutore " semantica: il significato delle istruzioni, cioè il modo in cui devono essere eseguite dall'esecutore (di fatto l'abbiamo già definita nella descrizione delle operazioni eseguibili) I nomi delle celle di memoria usati nei linguaggi di programmazione sono anche detti variabili, poiché il loro valore può essere modificato durante l’esecuzione di un algoritmo dalle istruzioni di assegnamento e di lettura I nomi delle variabili devono essere scelti da chi formula l’algoritmo (con la convenzione che uno stesso nome si riferirà sempre alla stessa cella) Associamo un'istruzione a ciascuna delle cinque operazioni eseguibili dall'esecutore: 1) istruzione di assegnamento 2) istruzione di lettura 3) istruzione di scrittura 4) istruzione condizionale 5) istruzione iterativa Non è necessario specificare a quale cella fisica corrisponda una data variabile: questo aspetto è interamente gestito dal compilatore o dall'interprete del linguaggio 25 26 Istruzione di assegnamento Istruzione di assegnamento Sintassi Semantica prima deve essere calcolato il valore di espressione poi tale valore deve essere memorizzato nella cella di memoria variabile variabile # espressione espressione può essere: " un numero, scritto come parte intera e parte frazionaria separate da una virgola (esempi: 3, -5, 3,14, ...) " un carattere, scritto tra apici per evitare ambiguità con i nomi delle variabili (esempi: 'a', 'W', '5', ...) " il contenuto di un'altra cella di memoria, indicata con il suo nome " il risultato (un numero) di una qualsiasi espressione aritmetica costruita con i cinque operatori di somma (+), sottrazione ($), moltiplicazione (*), divisione (/), resto della divisione tra interi (mod); gli operandi possono essere valori contenuti in celle di memoria, indicate con il loro nome Nota: il valore da memorizzare sostituisce un eventuale valore memorizzato in precedenza nella stessa variabile 27 28 Istruzione di assegnamento: esempi ! Istruzioni di lettura e scrittura m # 12 Sintassi e semantica assegna il valore 12 alla variabile m ! media # (x + y) / 2 " assegna a media la somma dei valori contenuti (nel momento in cui questa istruzione viene eseguita) nelle variabili x e y, divisa per 2 ! r # 5 mod 2 " assegna a r il resto della divisione intera tra 5 e 2 !n#n+1 espressione può essere: – un’espressione definita come per l’istruzione di assegnamento – una sequenza di caratteri indicata tra doppi apici (es. “ciao”) prima calcola la somma tra il valore contenuto in n e 1, poi assegna il risultato a n (il valore precedente di n viene sostituito dal nuovo valore) ! a # 1 / ((x + y) * (m – n)) ! read (variabile) acquisisce un valore dalla periferica di ingresso e lo memorizza nella cella variabile print (espressione) invia il valore di espressione alla periferica di uscita c # ‘F’ 29 30 Esempi Istruzione condizionale read (m) acquisisce un valore dalla periferica di ingresso e lo assegna alla variabile m ! print (5) invia il valore 5 alla periferica di uscita ! print (‘w’) invia il carattere w alla periferica di uscita ! print (“ciao”) invia la sequenza di caratteri ciao alla periferica di uscita ! print (x) invia alla periferica di uscita il valore contenuto nella variabile x ! print ((x+2)*z) invia alla periferica di uscita il valore dell’espressione (x+2)*z, calcolata in funzione dei valori contenuti nelle variabili x e z al momento dell’esecuzione di questa istruzione Sintassi if (condizione) { sequenza di istruzioni } oppure if (condizione) { sequenza di istruzioni 1 } else { sequenza di istruzioni 2 } " condizione è una espressione logica che può essere vera o falsa; le condizioni possono essere elementari o composte – condizione elementare: confronto tra i valori di due espressioni definite come per l’istruzione di assegnamento, per mezzo degli operatori =, %, <, !, ", > (se le espressioni sono caratteri alfabetici, entrambi minuscoli o maiuscoli, gli operatori si riferiscono all’ordinamento alfabetico) – condizione composta: combinazione di più condizioni elementari per mezzo degli operatori logici and, or e not " sequenza di istruzioni è una sequenza di una o più istruzioni qualsiasi 32 ! 31 Istruzione condizionale Esempi di espressioni logiche Condizioni elementari x = 3 è vera se il valore memorizzato nella variabile x è 3 a " b è vera se il valore memorizzato nella variabile a è maggiore di quello memorizzato nella variabile b (x + 2) * z < y è vera se il valore dell’espressione (x+2)*z è maggiore del valore di y b > ‘g’ è vera se il carattere memorizzato in b segue ‘g’ in ordine alfabetico Semantica: " " if (condizione) { sequenza di istruzioni } se condizione è vera esegui la sequenza di istruzioni, altrimenti non eseguire nessuna operazione if (condizione) { sequenza di istruzioni 1 } else { sequenza di istruzioni 2 } se condizione è vera esegui la sequenza di istruzioni 1, altrimenti esegui la sequenza di istruzioni 2 Condizioni composte (c1 and c2) è vera se sia c1 che c2 sono vere (c1 or c2) è vera se almeno una tra c1 e c2 è vera (not c) è vera se c è falsa Nota: c1, c2 e c possono essere sia condizioni elementari che composte Esempi: (x = 1) and (y > 0) (a = 1) or ((b + 2) * c > 0) not (c = ‘v’) ((x = 1) or (y > 0)) and (z = 0) 33 Esempi ! if Istruzione iterativa (x = 0) { y # 1 } ! Sintassi se il valore contenuto in x è 0, allora assegna a y il valore 1 ! if } while (condizione) do { sequenza di istruzioni } condizione e sequenza di istruzioni sono definite come per l’istruzione condizionale ((x = 1) and (y > 0)) { m#1 n#3 ! Semantica se il valore contenuto in x è 1 e quello contenuto in y è maggiore di 0, allora assegna a m il valore 1, e a n il valore 3 ! if 34 (z > 0) { y # 1 } else { y # 0 } se condizione è falsa, non eseguire nessuna operazione; se invece è vera, esegui la sequenza di istruzioni e alla fine valuta di nuovo condizione; se condizione è falsa, ... questo ciclo viene quindi ripetuto finché condizione è vera se il valore contenuto in z è maggiore di 0, assegna a y il valore 1, altrimenti assegna a y il valore 0 35 36 Esempi ! ! Osservazioni while (x > 0) do { print (x) x#x–1 } finché il valore di x è maggiore di 0: stampalo, calcola il valore dell'espressione x – 1, e memorizza il risultato in x (si ricordi che il valore precedente di x viene sostituito da quello nuovo). Si assume che alla variabile x sia già stato assegnato un valore while (y % z) do { y#z–x x#x*3 } finché il valore di y è diverso da quello di z: memorizza in y il valore di z – x, poi memorizza in x il valore di x*3 (si assume che alle variabili y e z sia già stato assegnato un valore) ! Qual è il potere espressivo del linguaggio di rappresentazione di algoritmi appena descritto? In altre parole: quali sono gli algoritmi che possono essere rappresentati usando questo linguaggio, e quelli che non possono essere rappresentati? !È stato dimostrato (teorema di Boehm-Jacopini) che un linguaggio dotato delle strutture semantiche corrispondenti alle istruzioni condizionale e iterativa consente di rappresentare qualsiasi algoritmo Per questo motivo queste due istruzioni sono comuni alla maggior parte dei linguaggi di alto livello 37 38 Rappresentazione ed esecuzione di algoritmi Dichiarazione delle variabili Nel notro pseudo-linguaggio (analogamente a tutti i linguaggi di programmazione) gli algoritmi saranno rappresentati come una sequenza ordinata di istruzioni, che saranno eseguite nell’ordine in cui sono elencate ! Tutti i dati di ingresso devono essere acquisiti dalla periferica di ingresso e memorizzati in variabili per poter essere successivamente elaborati ! Il risultato desiderato si ottiene “manipolando” i dati iniziali per mezzo delle istruzioni disponibili, memorizzando gli eventuali risultati intermedi in opportune variabili (spesso è necessario eseguire un'operazione sui risultati di altre operazioni) ! Tutti i risultati devono essere inviati alla periferica di uscita ! Per chiarezza, prima di riportare le istruzioni di un algoritmo si indicheranno in modo informale: ! ! " " i nomi di tutte le variabili usate nell’algoritmo il tipo di dati che esse conterranno (numeri interi, numeri reali o caratteri), con la convenzione che una variabile conterrà dati di un unico tipo durante l'esecuzione dell'algoritmo (come accade in molti linguaggi di programmazione reali) ! Nota: Nota: l’esecuzione di un algoritmo è un processo dinamico, il cui stato è caratterizzato in ogni istante dal valore di ciascuna variabile e dalla prossima istruzione da eseguire 39 nella maggior parte dei linguaggi di programmazione il nome e il tipo di tutte le variabili usate devono essere formalmente dichiarati all’inizio del programma 40 Esempi di algoritmi Esempio ! Come esempio, mostriamo di seguito la “traduzione” nello pseudolinguaggio appena definito degli algoritmi scritti in precedenza in linguaggio naturale (per chiarezza, si scriveranno in neretto i nomi simbolici usati per indicare le istruzioni e gli operatori logicoaritmetici: if, else, while-do, print, read, and, or, not, mod) ! Lo scopo di questi esempi è illustrare l’uso delle diverse istruzioni e il meccanismo di esecuzione degli algoritmi. A questo scopo si dovranno eseguire le istruzioni di ciascun algoritmo, con i seguenti accorgimenti: " i valori da acquisire per mezzo delle istruzioni di lettura (read) potranno essere scelti liberamente (nella realtà tali valori vengono forniti al calcolatore, per esempio da un utente per mezzo della tastiera) " per poter eseguire gli algoritmi è utile tener traccia (per esempio, per mezzo di una tabella) dei valori memorizzati istante per istante nelle celle di memoria 41 Esempio Assegna 0 alla cella a Leggi un valore e scrivilo nella cella b Finché il contenuto di b è diverso da 0, ripeti le due istruzioni: Assegna alla cella a il risultato di a + b Leggi un valore e scrivilo nella cella b Stampa il valore di a variabili: a e b memorizzano numeri reali a#0 read (b) while (b % 0) do { a#a+b read (b) } print (a) 43 In linguaggio naturale: Leggi un valore e scrivilo nella cella x Leggi un valore e scrivilo nella cella y Se il contenuto della cella x è maggiore del contenuto della cella y, allora stampa il valore della cella x, altrimenti stampa il valore della cella y Nello pseudo-linguaggio: variabili: x, y, z memorizzano numeri reali read (x) read (y) if (x > y) then { print (x) } else { print (y) } print (z) 42