:: Enseignements :: Master :: M2 :: 2013-2014 :: Machine Virtuelle (et bazard autour ...) ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Lab 1 - AST walker |
Le but de ce premier lab est d'implanter un interpréteur pour la langage
Talk
en parcourant l'arbre de syntax abstrait (AST).
Pour préparer ce premier lab, deux exercice d'introduction vont vous permettre
de comprendre le langage
Talk qu'il faut implanter ainsi
pour la syntaxe des lambdas introduit dans la version 8 de Java.
La préparation du lab est à uploader sur la plateforme de elearning:
Lab 1.
Exercice 1 - Le langage Talk (Préparation)
Le but de ce premier exercice est de comprendre comment fonctionne le langage Talk.
Créer un fichier pour chaque exemple demandé, cela vous permettra d'avoir des tests
pour tester votre code que vous écrirez dans la suite de ce lab.
-
Ecrire un code permettant d'additionner les valeurs 2 et 3.
-
A quoi correspond l'opération '!' du language Talk ?
-
Ecrire un code permettant de declarer une variable 'a' initialisée avec la valeur du produit de 3 par 5
puis utiliser la valeur de la variable 'a' comme valeur de retour du script.
-
Ecrire une lambda qui prend une valeur en paramètre et renvoie la valeur de celle-ci.
Stocker la valeur correspondant à la lambda dans une variable 'identity' puis
appeler la lambda avec la valeur 42.
-
Déclarer une variable 'a' initilisée avec la valeur 12, créer un lambda que l'on stockera dans
une variable 'add' qui prend un paramètre 'x' et renvoie la somme entre la valeur de 'x' et
la valeur de 'a' (si vous préférer, la lambda à un paramètre normal 'x' et un paramètre lié
(bound) 'a'. Appeler la lambda avec la valeur 21.
Exercice 2 - Les lambdas de Java 8 (Préparation)
Un petit exercice pour comprendre comment marche les lambdas en Java.
Voilà une vidéo de la présentation que j'ai fait pour un Java User Group:
Les lambdas en Java
Comme cet exercice et les exercices suivants requiert Java 8, il vous faut utiliser le JDK 8 ainsi qu'un
eclipse compatible avec le jdk8, la page de
configuration d'Eclipse.
Et si vous voulez utiliser
un autre IDE.
-
On considère le suivant qui calcul le minimum des valeurs d'un tableau
public static int min(int[] values) {
if (values.length == 0) {
throw new IllegalArgumentException();
}
int min = values[0];
for(int i = 1; i < values.length; i++) {
min = Math.min(min, values[i]);
}
return min;
}
Ecrire le code permettant de calculer le maximum.
-
Bien sûr, faire du copier/coller n'est pas la bonne, idée, il vaut mieux
essayer de partager le code.
Transformer la méthode min en une méthode reduce qui prend
en second paramètre (en plus du tableau d'entier donc), une réference
sur une interface java.util.function.IntBinaryOperator et
remplacer l'appel à Math.min par l'appel à la méthode
de l'interface.
Puis créer un méthode min qui appel la méthode reduce
en envoyant en second paramètre une classe anonyme, le corps de la méthode
de la classe anonyme appelera Math.min.
Tutorial sur les classes anonymes
-
Transformer le code de la méthode min pour utiliser une lambda au lieu d'utiliser une classe anonyme.
Tutorial sur les lambdas
-
Finalement, il est plus simple ici d'utiliser une method reference qu'une lambda.
Faite la transformation qui s'impose.
Pour vous aidez, vous pouvez utiliser les slides du cours de L3:
function et lambdas.pdf
Exercice 3 - AST interpreter (Préparation)
Le but de cet exercice est d'écrire un interpreteur parcourant l'arbre
correspondant à un script du language
Talk et affichant sa valeur.
Archive au format ZIP contenant une base de code (le lexer, parseur et les classes définissant l'AST)
vm2014-lab1.zip
-
On cherche à comprendre ce que fait la méthode main
de la classe fr.umlv.talk.main.ASTInterpreterMain.
Quelle est la respondsabilité de la classe fr.umlv.talk.ast.ASTBuilder.
A quoi sert la méthode ASTBuilder.createScript ?
Que fait ligne à ligne la méthode main de la classe ASTInterpreterMain ?
-
Rappeler à quoi sert le Visitor Pattern.
Regarder la classe fr.umlv.talk.ast.Visitor et fr.umlv.talk.astinterp.ASTInterpreter
et indiquer les différences par rapport au Visitor Pattern classique.
-
On va maintenant ajouter du code dans la classe fr.umlv.talk.astinterp.ASTInterpreter
pour que l'interpretation du script Talk suivant affiche 3.
3
Que se passe t'il si l'on execute le main de la classe ASTInterpreterMain
sur le script ci-dessus ?
Quel code doit on écrire pour interpréter un block d'expression sachant qu'il faut
appeler le visiteur sur l'ensemble des expressions du bloc.
Quel code doit on écrire pour interpréter un litéral ?
Faire en sorte que le script ci-dessus s'exécute correctement.
-
Quelle valeur doit renvoyer l'exécution d'un script vide ?
Comment faire pour déclarer une telle valeur dans ASTInterpreter ?
Faire les changements qui s'imposent.
-
On cherche maintenant à interpréter un script permetant de déclarer des variables
et de les utiliser.
a = 3
a
Que doit afficher l'interpretation du script suivant ?
Que se passe t'il si on essaye d'exécuter l'interpreteur sur le script ?
-
Sachant que l'on doit enregistrer la valeur d'une variable pour pouvoir obtenir
la valeur d'une variable plus tard, on va utiiser la classe Env
et sa table de hachage.
Completer les méthodes lookup et register de la classe Env
puis compléter le visiteur.
-
Vérifier que les codes suivants ne sont pas valides.
définition d'une variable déjà définie
a = 3
a = 4
et utilisation de variable non définie.
a
-
Quelle est la méthode du visiteur qui permet d'interpreter le code suivant.
-3
Sachant que l'ensemble des opérations (unaire et binaire) du language Talk s'exécute
sur des entiers, faire en sorte que l'on puisse interpréter le code ci-dessus.
-
Faire en sorte que l'on puisse interpréter le code
+ 3
Faire de même avec l'opérateur '!' (attention à implanter correctement
son comportement).
-
Les ifs ou les switchs sur des types de choses sont
à bannir en programmation objet. Comment faire ici pour associer
l'opération à effectuer avec l'opérateur sans if ni switch ?
Implanter la solution retenue
-
Implanter les opérations binaires (+, -, *, /, %, ==, !=, < <=, > et >=).
-
On cherche maintenant à implanter la création de lambda, pour cela créer une classe
Function qui représentera à l'exécution une lambda.
Faire en sorte que l'on puisse représenter les lambdas suivantes
lambda1 = []
lambda2 = |x| [ x ]
lambda3 = |x, y| [ x + y ]
Ajouter un toString qui affiche les paramètres de la lambda, par exemple,
[x, y] Function@0x123456.
Ajouter ce qu'il faut au visiteur pour qui soit possible de créer une lambda.
-
Enfin, on veut maintenant être capable d'appeler une instance de Function
en lui passant des paramètres.
On donc cherche à ce que le code suivant fonctionne
f = |x| [ x + 1 ]
f(3)
L'appel de fonction peut se décomposer en deux parties, la première qui
consiste à calculer les arguments et vérifier que l'on appel bien
un object Function (donc le code 2() doit renvoyer une failure)
puis on doit exécuter le code de la lambda correspondant en ayant correctement
initialisé les paramètres avec les valeurs des arguments.
En terme de programmation, le calcul de la valeur des arguments se fera dans
le visiteur tandis que l'appel du code de la lambda se sera dans une méthode
de la classe Function.
Exercice 4 - Pour aller plus loin
Le langage
Talk ne supporte pas des fonctions nommées mais des lambdas (des fonctions anonymes)
mais la plupart des lambdas vont être initialisées et stockées dans une variable locale,
par exemple
identity = |x| [ x ]
Dans ces cas, il est possible d'utiliser le nom de la variable local comme nom de la lambda
pour founir plus d'information à l'utilisateur.
En terme d'implantation, l'idée est de propager le nom de la variable de gauche vers
l'expression de droite, si l'expression est une lambda, on peut stocker le nom
dans l'objet
Function correspondant, sinon on considèrera que la lambda
n'a pas de nom.
-
Ecrire le code qui permet de propager le nom d'une variable vers la lambda.
-
Vérifier que le nom foo est bien propagé dans ce cas
foo = ([])
-
Vérifier que la second lambda est bien nommée x.
bar = |x| [x]
bar([])
© Université de Marne-la-Vallée