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