15 febbraio 2017 - laboratorio
Linguaggi e Traduttori
Prof. Marco Gavanelli
15 febbraio 2017
Esercizio 1 (punti 14)
Diana vuole portare alla festa della scuola delle torte. La nonna le ha dato una ricetta e le ha spedito la lista degli ingredienti via email nel file di testo ricetta.txt. Gli ingredienti sono riportati uno per riga; per ciascun ingrediente, sono riportati:
- nome: stringa
- peso: (Int) quantità in grammi
Fortunatamente, Diana ha in casa tutti gli ingredienti; il suo modernissimo frigorifero le fornisce automaticamente l'elenco di tutti gli alimenti che contiene in un file di testo ingredienti.txt , in cui ciascun elemento è rappresentato come prima, cioè:
- nome: stringa
- peso: (Int) quantità in grammi
Si scriva un programma Haskell che visualizza quante torte riuscirà a fare Diana.
Ad esempio, se il file ricetta.txt contiene
| Zucchero | 300 |
| Burro | 100 |
| Farina | 350 |
ed il file ingredienti.txt contiene
| Burro | 500 |
| Farina | 1000 |
| Latte | 1000 |
| Zucchero | 700 |
il programma dovrà visualizzare che si riescono a fare 2 torte.
Diana desidera inoltre sapere quali ingredienti (e il relativo peso) dovrà acquistare per fare una torta in più; nell'esempio sopra, dovrà acquistare 200 grammi di Zucchero e 50 di Farina per poter fare 3 torte.
Si usino (e, possibilmente, definiscano) funzioni di ordine superiore per risolvere il problema. Nel voto finale è inclusa una valutazione basata sull'utilizzo di funzioni di ordine superiore, list comprehension, lazy evaluation.
Esercizio 2 (Punti 4)
Si scriva un programma Lex che, dato un file in linguaggio C, mostra solo le parti commentate fra /* e */ .
Si ricorda che un commento in linguaggio C inizia con /* , può contenere un testo qualsiasi (anche su più righe) ma che non contiene la sequenza */ e termina con */ .
Ad esempio, dato il programma
#include <stdio.h>
/* programma per stampare
Hello World!
*/
main()
{ printf("Hello world!\n");
}
il programma Lex dovrà stampare
/* programma per stampare Hello World! */
(il fatto che vengano visualizzati i simboli /* e */ è irrilevante).
Soluzione 1
data Ingrediente = Ingrediente{ nome :: String, peso :: Int } deriving Show;
converti :: [String] -> Ingrediente
converti [name,weight] = Ingrediente name (read weight)
lettura fileName = do
inpStr <- readFile fileName
return (map (converti.words) (lines inpStr))
ricerca xs y = (head (filter (((nome y)==).nome) xs))
rapportoRicerca xs y = div (peso (ricerca xs y)) (peso y)
minimo (x:xs) = foldl min x xs
rapporti ricetta ingrs =
map (rapportoRicerca ingrs) ricetta
join rs is = map (\r -> (r,(ricerca is r))) rs
diff x n = n*(peso (fst x)) - (peso (snd x))
mancanti rs is n =
let j = join rs is
in [Ingrediente ((nome.fst) x) (diff x n) | x <- j, (diff x n)>0]
main = do
ricetta <- lettura "ricetta.txt"
ingredienti <- lettura "ingredienti.txt"
let numTorte = minimo (rapporti ricetta ingredienti)
putStr "NumeroTorte = "
print numTorte
let listaSpesa = mancanti ricetta ingredienti (numTorte+1)
putStrLn "Lista della spesa = "
print listaSpesa
Soluzione 2
COMMENTTEXT ([^\*]|"*"[^/])*
COMMENT "/*"{COMMENTTEXT}"*/"
%%
{COMMENT} printf("%s",yytext);
. ;
\n ;
%%