Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- La leçon de programmation la plus importante
- ============================================
- Normalement, comme c'est la leçon de programmation la plus importante,
- elle aurait du déjà être enseignée avec les autres langages de
- programmation!
- Le principal problème dans le code que tu as écris, c'est le manque
- d'abstration.
- Par exemple, le fait d'utiliser GET partout. Cela implique un choix
- d'implantation trés spécifique pour la VM, à savoir qu'un VM est
- représentée par un symbole (pourquoi?) et ses attributs par des
- entrées dans la p-list du symbole (avec un accès linéaire O(n) sur les
- attributs, ce qui est coûteux, mais c'est accessoire).
- La conséquence, c'est que si on voulait changer l'implantation de la
- VM, il faudrait changer tout le code, remplacer tous ces appels à GET.
- Un autre inconvénient, ça n'aide pas à la compréhension de la
- signification du code. C'est particulièrement intriguant, dans
- l'utilisation de fonctions comme CADADR. On voit bien que on va
- naviguer dans un arbre de paires, mais quel rapport est-ce que ça a
- avec une machine virtuelle? (Avec GET, on voit bien qu'on va chercher
- une propriété dans une p-list, mais quel rapport est-ce que ça a avec
- une machine virtuelle? (C'est plus facile à deviner, mais c'est le
- même principe)).
- Pour résoudre ce problème, on peut utiliser une abstraction fonctionnelle.
- Il s'agit d'une fonction ou d'un groupe de fonction ayant un nom (et
- donc, une fonction) significative pour le domaine du problème.
- Ainsi, si on défini des fonctions comme:
- vm-memory
- vm-r0
- vm-r1
- vm-r2
- vm-r3
- vm-pc
- vm-fp
- vm-dpp
- etc, on voit bien que l'on a affaire à des composant d'une machine virtuelle.
- Même si tu choisis d'implanter la machine virtuelle avec un symbole et
- sa p-list, le fait d'introduire ces abstractions fonctionnelle vont
- rendre ton code bien plus limpide, et maintenable:
- (defun vm-memory (vm) (get vm :memtab))
- (defun vm-r0 (vm) (get vm :r0))
- …
- (defun vm-pc (vm) (get vm :pc))
- …
- Ainsi, quand on écrit:
- (defun memref (vm adr) (aref (vm-memtab vm) adr))
- (defun (setf memref) (val vm adr) (setf (aref (vm-memtab vm) adr) val))
- on voit tout de suite qu'on indexe (avec aref), a memtab de la vm.
- Si tu introduis l'abstraction fonctionnelle suivante pour les instructions:
- (defun operation (instruction) (car operation))
- (defun premier-operande (instruction) (cadr operation))
- (defun second-operande (instruction) (caddr operation))
- Alors une fonction comme:
- (defun sautp (inst)
- (member (operation inst) '(JMP JEQ JL JG JLE JGE JNE)))
- devient tout de suite plus claire.
- etc.
- Tel qu'il est, le code n'est pas clair; par exemple, on a du mal à
- comprendre quel est le format d'un programme assembleur
- source. D'après load-machine, on a une simple liste non structurée,
- mais comme on n'a pas d'abstraction fonctionnelle, on ne voit pas bien
- quelle syntaxe ASM doit avoir. Dans ce cas, tu aurais du le documenter!
- Mais mieux que documenter, c'est avoir un code limpide.
- Par exemple en écrivant l'abstraction fonctionnelle suivante:
- (premiere-instruction code) -> instruction
- (instructions-suivantes code) -> code-ou-nil
- (fin-du-code-p code-ou-nil) -> boolean
- (etiquette instruction) -> etiquette-ou-nil
- (operation instruction) -> operation
- (premier-operande instruction) -> operande
- (second-operande instruction) -> operande-ou-nil
- Avec de telles abstraction, on peut alors écrire de façon plus claire et lisible :
- (defun load-machine (vm asm)
- (loop
- :with etiqLoc := (make-hash-table :size (get vm :taille))
- :with etiqLocNR := (let ((table (make-hash-table :size (get vm :taille))))
- (setf (gethash 'nb table) 0)
- table)
- :for code := asm :then (instructions-suivantes code)
- :for instruction := (premiere-instruction asm)
- :do (case (operation instruction)
- ((@) (case-adr vm code instrution etiqLoc etiqLocNR))
- ((JSR) (case-saut vm code instrution))
- ((FEntry) (case-fonction vm code instrution))
- (otherwise (case-other vm code instrution etiqLoc etiqLocNR)))
- :until (fin-du-code-p code)))
- Mais surtout, si on veut changer le format de ASM, ou changer
- l'implantation de VM, on n'a plus besoin de modifier le programme! Le
- programme devient indépendant des choix d'implantation de ces modules.
- Il suffit de modifier l'implantation des abstractions fonctionnelles.
- Au lieu d'écire:
- (defun vm-memory (vm) (get vm :memtab))
- (defun vm-r0 (vm) (get vm :r0))
- …
- (defun vm-pc (vm) (get vm :pc))
- …
- on écrit:
- (defstruct vm
- memory
- r0 r1 r2 r3
- pc sp
- …)
- ou:
- (defstruct (vm (:type vector))
- memory
- r0 r1 r2 r3
- pc sp
- …)
- ou:
- (defclass vm ()
- ((memory :initarg :memory :accessor vm-memory)
- (r0 :initarg :r0 :initform 0 :accessor :vm-r0)
- …))
- ou n'importe quoi, qui défini ces fonctions, et on obtient
- automatiquement un programme qui fonctionne avec les nouvelles
- propriétés du module.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement