Il file Imp-Operazionale.ml contiene la sintassi di un semplice linguaggio imperativo (con assegnamento, condizionale e while) e la sua semantica operazionale. Per controllare che non ci siano problemi, lanciare l'interprete "ocaml" nella directory dove si trova il file e - copiare tutto il contenuto del file Imp-Operazionale.ml e battere ";; ", oppure - scrivere #use "Imp-Operazionale.ml";; L'interprete non deve segnalare errori e dovrebbe stampare i tipi delle funzioni definite nel file. Esercizio 1 =========== Estendere sintassi e semantica del linguaggio con un nuovo comando, il "blocco" 'Block(decl, com list)'. Un blocco comprende una lista di "dichiarazioni" 'decl' e una lista di comandi 'com list'. Una "dichiarazione" e' una coppia di tipo 'ide * exp'. L'esecuzione di un blocco 'Block(decl, com list)' in un ambiente 'env' e con memoria 'st' consiste in 1) valutare la lista di dichiarazioni, ottenendo ambiente 'env1' e memoria 'st1' 2) valutare la lista di comandi nell'ambiente e memoria risultanti Requisiti: estendere il tipo 'com' con il nuovo costrutto e la funzione 'semc' con una clausola per valutarne la semantica. Nel file Esempi.ml ci sono due esempi di definizione di blocco e di corrispondente esecuzione che dovrebbero poter funzionare in una implementazione corretta. Suggerimenti: introdurre tipi di dati e funzioni ausiliarie a piacere. Sfruttare le funzioni 'semcl' e 'semdv' gia' definite nel file per le due parti del blocco. Esercizio 2 =========== Estendere sintassi e semantica del linguaggio precedente con procedure senza parametri e non ricorsive, e loro chiamata. In una dichiarazione, un identificatore puo' essere legato a una procedura, che ha sintassi SimpleProc(block). La procedura puo' essere invocata con un nuovo comando CallSimple(exp). Se "P" e' legata nell'ambiente a SimpleProc(block), l'invocazione di CallSimple(Den "P") eseguira' 'block' con scoping statico. Nel file "Esempi.ml" ci sono due esempi di definizione di procedura e di corrispondente esecuzione che dovrebbero poter funzionare in una implementazione corretta. Esercizio 3 =========== Estendere il linguaggio dell'esercizio precedente con procedure con parametri e varie modalita' di passaggio, cioe' per nome, per riferimento e per valore. Si aggiunga il nuovo tipo: type param = (* parametro formale e suo tipo *) | Const of ide | Ref of ide | Value of ide Si estenda il tipo 'exp' con la clausola: | Proc of param list * block e il tipo 'com' con il comando | Call of exp * exp list dove 'exp' e' l'astrazione procedurale e 'exp list' la lista di parametri attuali. La semantica di Call deve gestire correttamente il passaggio dei parametri modificando ambiente e memoria di conseguenza. In particolare, se il parametro e' di tipo: Const("x"), allora "x" viene legata nell'ambiente al valore del parametro attuale Ref("x"), allora "x" viene legata nell'ambiente alla locazione associata al parametro attuale Value("x"), allora "x" viene legata nell'ambiente a una nuova variabile che viene inizializzata con il valore del parametro attuale. ============================