Utilisation de la syntaxe markdown... en cours.
This commit is contained in:
parent
0765b73512
commit
702fb1bf3f
|
@ -1,33 +1,45 @@
|
|||
Choses à ne pas oublier à dire lors de la soutenance (keywords: compilation lafourcade um2 m1)
|
||||
|
||||
= lisp2li =
|
||||
On a choisi de ne pas utiliser le li du prof, mais au contraire d'utiliser du LISP simplifié qui est donc exécutable donc on a pu faire des
|
||||
tests unitaires pour voir si la transformation préservait le sens du programme.
|
||||
Tests unitaires
|
||||
===============
|
||||
|
||||
= tests unitaires =
|
||||
'test de régression': on a pu modifier des morceaux de code qui avait déjà les tests et voir que ça tournait toujours (après modifs)
|
||||
framework extensible : possibilité d'ajouter de nouveaux types de tests (ex. deftest-error, deftest-equiv)
|
||||
séparation des tests en modules / sous-modules, possibilité de lancer des tests de certains (sous-)modules seulement.
|
||||
contabilisation du nombre de tests, d'erreurs, etc.
|
||||
* «tests de régression» : on a pu modifier des morceaux de code qui avait déjà les tests et voir que ça tournait toujours (après modifs)
|
||||
* framework extensible : possibilité d'ajouter de nouveaux types de tests (ex. `deftest-error`, `deftest-equiv`)
|
||||
* séparation des tests en modules / sous-modules, possibilité de lancer des tests de certains (sous-)modules seulement.
|
||||
* Statistiques : contabilisation du nombre de tests, d'erreurs, etc.
|
||||
|
||||
mini-meval
|
||||
==========
|
||||
|
||||
= mini-meval =
|
||||
C'est un méta-évaluateur 'naïf' mais qui supporte pratiquement tout LISP sauf CLOS (Common Lisp Object System)
|
||||
|
||||
= syntaxe supportée =
|
||||
* Le 'eval-when'
|
||||
* Les 'tagbody' et 'go', les 'throw' et 'catch', les 'block' et 'return' et 'return-from' et le 'unwind-protect'
|
||||
* Les 'let', 'let*', 'flet', 'labels', 'macrolet',
|
||||
* Les 'macro'
|
||||
* Les 'lambda' avec capture de variables
|
||||
* Dans la 'lambda-list': '&optional', '&rest', '&key', '&allow-other-keys', '&aux', mais pas les '&body'
|
||||
* Plus progn, if, #', quote, etc.
|
||||
Syntaxe supportée par mini-meval et le simplificateur
|
||||
=====================================================
|
||||
|
||||
= squash-lisp =
|
||||
* Le `eval-when`
|
||||
* Les `tagbody` et `go`, les `throw` et `catch`, les `block` et `return` et `return-from` et le `unwind-protect`
|
||||
* Les `let`, `let*`, `flet`, `labels`, `macrolet`,
|
||||
* Les `macro`
|
||||
* Les `lambda` avec capture de variables
|
||||
* Dans la `lambda-list`: `&optional`, `&rest`, `&key`, `&allow-other-keys`, `&aux`, mais pas les `&body`
|
||||
* Plus `progn`, `if`, `#'`, `quote`, etc.
|
||||
|
||||
lisp2li
|
||||
=======
|
||||
|
||||
On a choisi de ne pas utiliser le li du prof, mais au contraire d'utiliser du LISP (très) simplifié qui est donc exécutable ce qui nous a permis de faire des tests unitaires pour voir si la transformation préservait le sens du programme.
|
||||
|
||||
Cette transformation est assurée par la fonction squash-lisp :
|
||||
|
||||
squash-lisp
|
||||
===========
|
||||
* En 3 passes :
|
||||
* Passe 1 :
|
||||
* macro-expansion (on utilise mini-meval) et eval-when
|
||||
* macro-expansion (on utilise `mini-meval`) et `eval-when`
|
||||
* simplification globale de la syntaxe :
|
||||
* (let (a (b 2) c) (list a b c)) -> (let ((a nil) (b 2) (c nil)) (list a b c))
|
||||
*
|
||||
(let (a (b 2) c) (list a b c))
|
||||
-> (let ((a nil) (b 2) (c nil)) (list a b c))
|
||||
* unification de la syntaxe des let, let*, flet, labels.
|
||||
* tous les appels de fonction sont transformés en funcall.
|
||||
* ré-écriture des tagbody/go, throw/catch, block/return(-from) en termes de unwind/unwind-protect, jump/jump-label + variations.
|
||||
|
@ -41,13 +53,14 @@ C'est un méta-évaluateur 'naïf' mais qui supporte pratiquement tout LISP sauf
|
|||
(let ((a nil) (b 2)) (list a b)) -> (simple-let (a b) (setq a nil) (setq b 2) (list a b))
|
||||
* simplification de la lambda-list (élimination de &optional &rest &key &allow-other-keys &aux)
|
||||
* suppression des paramètres de la lambda :
|
||||
(lambda (x y) (+ x y)) -> (simple-lambda (simple-let (x y) (setq x (get-param 0)) (setq y (get-param 1)) (+ x y)))
|
||||
(lambda (x y) (+ x y)) -> (simple-lambda (simple-let (x y) (setq x (get-param 0)) (setq y (get-param 1)) (+ x y)))
|
||||
* Passe 3
|
||||
* On lorsqu'une variable à l'intérieur d'un lambda référence une déclaration à l'extérieur du lambda, on la marque comme étant capturée.
|
||||
* On fusionne tous les let d'une lambda en les remontant dans un let à la racine de la lamdba.
|
||||
* On sort toutes les lambdas (fonctions anonymes), on les nomme avec un symbole unique, et on les met au top-level.
|
||||
|
||||
= match =
|
||||
match
|
||||
=====
|
||||
* on a fait une fonction de pattern matching qui utilise une syntaxe proche de expressions régulières pour reconnaître des expressions LISP
|
||||
qui ont une certaine forme / motif . On peut 'capturer' des portions de ce motif dans des variables qui sont accessibles dans le corps des
|
||||
match.
|
||||
|
@ -59,12 +72,14 @@ C'est un méta-évaluateur 'naïf' mais qui supporte pratiquement tout LISP sauf
|
|||
* Pas d'optimisation à la compilation de quelle fonction match : la syntaxe de match est assez lourde, et vu qu'on ne match pas sur la forme
|
||||
de l'appel de fonction, mais sur les valeurs passées en paramètre, l'optimisation n'est pas faisable 90% du temps.
|
||||
|
||||
= compilation =
|
||||
compilation
|
||||
===========
|
||||
* On compile vers de l'assembleur assez proche de l'x86. On avait déjà un système d'exploitation assez simple qui tournait de manière
|
||||
autonome sur un PC. On a donc stotché ensemble une REPL compilée et le SE de manière à avoir une REPL autonome qui ne dépend de rien.
|
||||
le système d'exploitation sous-jacent fournit juste de quoi faire des entrées-sorties.
|
||||
|
||||
= garbage collector =
|
||||
garbage collector
|
||||
=================
|
||||
* gestion du tas
|
||||
* on a un gc très simpliste qui copie les données d'une zone de la mémoire vers une autre et vice versa à chaque fois qu'elle est pleine. La
|
||||
raison est que les autres gc nécessite une occupation variable de la mémoire pour l'exécution du gc qui peut être aussi grosse que la
|
||||
|
|
Loading…
Reference in New Issue
Block a user