:: Enseignements :: Master :: M2 :: 2013-2014 :: Machine Virtuelle (et bazard autour ...) ::
[LOGO]

Lab 2 - Stack interpreter


Le but de ce second lab est d'implanter un interpréteur à pile pour la langage Talk.
Une base de code est disponible: vm2014-lab2.zip
La préparation du lab (votre travail personnel) est à uploader sur la plateforme de elearning: Lab 2.

Exercice 1 - Stack interpreter (Préparation)

Le but de cet exercice est d'écrire un interpreteur à pile 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-lab2.zip

  1. On cherche à comprendre ce que fait la méthode main de la classe fr.umlv.talk.main.StackInterpreterMain.
    A quoi sert la classe StackDumper ?
    A quoi sert la classe Tracer ?
    A quoi sert la classe Rewriter ?
    A quoi servent les méthodes de la classe Rewriter.Env ?
    A quoi sert la classe StackInterpreter ?
  2. Ecrire dans le visiteur du Rewriter le code correspondant à la génération d'un block de code.
    Vérifier que le code est correctement généré pour les scripts
               2
             
    et
               2
               3
             
    en utilisant la classe Tracer.
  3. Vérifier que le l'interpreteur StackInterpreter exécute correctement le code.
  4. Vérifier que le rséultat de l'exécution d'un script vide est NIL.
  5. Modifier l'interpréteur pour pouvoir exécuter le script suivant.
              a = 3
              a
             
  6. Vérifier que l'exécution de
              a = b = 3
              a
             
    se passe corectement.
  7. Modifier l'interpreteur pour que le code suivant s'exécute correctement:
              -3
             

    Faire de même avec les opérations '!' et '+' (unitaire).
  8. Modifier l'interpréteur pour exécuteur les opérations +, -, *, / et %.
    Vérifier que les opérations -, / et % s'exécute dans le bon sens !
  9. Implanter les opérations de test dans l'interpreteur (==, !=, < <=, > et >=).
  10. Implanter l'exécution d'une lambda (APPLY) et vérifier avec les appels suivants
               res1 = []()
               res2 = |x| [ x ](7)
               res3 = |x, y| [ x + y ](2, 3)
             

    Note: vous devez aussi implanter RET (et attention à détecter si il s'agit du dernier RET).
    Vous pouvez vérifier que l'état de la pile est correct en utilisant la classe StackDumper.
  11. Vérifier que APPLY fonctionne aussi avec le code suivant
               a = |x, y| [ 1 + x * y ]
               a
             

Exercice 2 - Calculer la taille maximale de la pile (Préparation)

On souhaite modiier la classe Rewriter pour calculer la taille maximale de la pile.
Pour cela ajouter les champs et méthodes suivantes dans la classe Rewriter.Env.
    private int currentStack;
    private int maxStack;   
       
    public void push() {
      currentStack++;
      maxStack = Math.max(maxStack, currentStack);
    }
    public void pop(int stackSize) {
      currentStack -= stackSize;
      assert currentStack >= 0;
    }
    public int getMaxStack() {
      return maxStack;
    }
       

  1. Ajouter les appels à push et pop pour calculer la taille maximal de la pile pour chaque fonction.
  2. Utiliser la taille maximale calculée à la question précédente pour vérifier que la pile est suffisamment grande (attention il faut aussi la place pour les variables locales) lors d'un appel de fonction.
    Note: tester avec une toute petite pile.
  3. Au lieu de lever une Failure si la pile est pleine, on souhaite afficher un stack trace. En reprenant le code de StackDumper écrire une méthode dans l'interpreteur qui calcul le stack trace.
  4. On souhaite ajouter les numéros de ligne du script associée à chaque appel de fonction dans le stack trace. Pour cela, il faut associé un numéro de ligne à chaque instruction.
    Proposer un algorithme qui permet d'associer un numéro de ligne à chaque instruction sans stocker un numéro de ligne pour chaque instruction.
    Implanter l'algorithme.