Le procédé de décompilation des arbres syntaxiques – l'évaluation d'un texte – et la langage – Lisp – suggèrent l'introduction d'une nouvelle forme de décompilation : l'exécution du programme.
On reprend ici l'exemple du langage (§ 1) et celui des fonctions (§ 2) en vue d'une interprétation effective du programme en cours d'édition.
1. L'exécution
précisions de l'exemple
Si l'on souhaite réaliser une exécution symbolique du programme, il faut davantage préciser l'exemple. Cela touche deux points :
type-int et type-real), qui présentent maintenant les deux propriétés :nom : le nom du type,conv : le schéma de conversion d'une chaîne de caractères (formellement nommée STG) en une valeur du type ;TYP) est défini par référence à un texte de type – type-int ou type-real ; les "valeurs immédiates" "0" ou "1.0" sont définies comme la conversion d'une chaîne de caractères en une valeur du type (utilisation de la propriété conv du type).Les points précédents ne font que mieux préciser la définition du langage et son utilisation. La seule véritable modification intervient dans l'introduction d'un nouveau champ à la déclaration d'une variable : le champ VAL, dont la représentation a une valeur indéfinie ; il est utilisé à l'exécution pour stocker la valeur de la variable.
Figure 1.a : grammaire [ << masquer ]
(def type-int
((def nom () ("integer"))
(def conv () ((STG)))))
(def type-real
((def nom () ("real"))
(def conv () ((STG)))))
(def pgme ()
((PGME-DECLA)
(PGME-INSTR)))
(def pgme-decla ()
((lst-init ((DECLA*))
("VAR " (rep (DECLA) (lst (DECLA)))))))
(def pgme-instr ()
((lst-init ((INSTR*))
((INSTR)))))
(def decla ()
((NOM((VAR))) ":" (TYP((VAR))) "^M"))
(def affect ()
((VAR) ":=" (EXP) "^M"))
(def affiche ()
("write(" (EXP) ")" "^M"))
(def cond ()
("if " (EXP-COND) "^M"
(THEN-CLAUSE)
(ELSE-CLAUSE)
"endif" "^M"))
(def exp-egal ()
((EXP1) "=" (EXP2)))
(def exp-diff ()
((EXP1) "<>" (EXP2)))
(def then-clause ()
("then" "^M"
(lst-init ((INSTR*))
(" " (rep (INSTR) (lst (INSTR)))))))
(def else-clause ()
("else" "^M"
(lst-init ((INSTR*))
(" " (rep (INSTR) (lst (INSTR)))))))
(def var
((def lect () ((NOM)))
(def ecr () ((NOM)))
(def init () ((INIT)))))
Figure 1.b : arbre syntaxique [ << masquer ]
(def VAR-x
((def NOM () ("x"))
(def TYP () ((type-int)))
(def INIT ((type-int))
((conv
((def STG () ("0"))))))
(def VAL () ((lsp *))
(var)))
(def VAR-y
((def NOM () ("y"))
(def TYP () ((type-real)))
(def INIT ((type-real))
((conv
((def STG () ("1.0"))))))
(def VAL () ((lsp *))
(var)))
(def PGME
((def PGME-DECLA
((def DECLA*
(lst-env
((def DECLA
((def VAR ((VAR-x))))
((decla))))
(def DECLA
((def VAR ((VAR-y))))
((decla)))))))
((pgme-decla)))
(def PGME-INSTR
((def INSTR*
(lst-env
((def INSTR
((def VAR ((VAR-x)) ((ecr)))
(def EXP ((VAR-x)) ((init))))
((affect))))
(def INSTR
((def VAR ((VAR-y)) ((ecr)))
(def EXP ((VAR-y)) ((init))))
((affect))))
(def INSTR
((def EXP-COND
((def EXP1 ((VAR-x)) ((lect)))
(def EXP2 ((VAR-y)) ((lect))))
((exp-egal)))
(def THEN-CLAUSE
((def INSTR*
(lst-env
((def INSTR
((def EXP () ("'Ok'")))
((affiche)))))))
((then-clause)))
(def ELSE-CLAUSE
((def INSTR*
(lst-env
((def INSTR
((def VAR ((VAR-x)) ((ecr)))
(def EXP ((VAR-y)) ((lect))))
((affect))))
(def INSTR
((def EXP () ("'Erreur'")))
((affiche)))))))
((else-clause))))
((cond))))
(def INSTR
((def EXP () ("'fin'")))
((affiche)))))))
((pgme-instr))))
((pgme)))
les nouveaux termes du langage
Pour éviter des insertions fréquentes de code Lisp par l'entremise de l'opérateur lsp, on introduit trois nouveaux opérateurs : exec, clean et funclean. Pour alléger encore un peu plus la syntaxe, et illustrer la possibilité de définition d'un phylum, on introduit un nouveau phylum : EXEC.
syntaxe
EXEC ::= exec clean funclean
exec -> SEX*
clean -> NOM ENV REP
funclean -> NOM ENV REP
phylum EXEC
C'est le phylum des exécutions, fils du phylum des représentations REP : là où est attendue une représentation on pourra trouver un opérateur d'exécution – et non réciproquement.
opérateur exec
exec est à EXEC ce que lsp est à LSP : l'évaluation de l'opérateur correspond à l'évaluation séquentielle des S-expressions qui le composent (c'est "progn" en Lisp).
opérateur clean
clean correspond à l'utilisation "propre" use : son évaluation est élaborée de manière identique à celle de use, mais la valeur retournée est "nettoyée" des préfixes de représentation rep.
Par exemple :
- use NOM retourne (rep (rep "nom-x"))
- clean NOM retourne "nom-x"
opérateur funclean
funclean est l'application :
REPNOM dans l'environnement local ENV.On peut donc écrire ceci :
(funclean NOM ENV REP) ≡ (funcall (clean NOM ENV) REP)
L'argument REP est évalué en dehors de la lambda-expression. A l'application de la lambda-expression il est construit une "sorte" de fermeture lexicale grâce à l'environnement ENV.
Pour que l'évaluation fournisse un résultat correct, il faut bien sûr que l'utilisation du texte NOM retourne une lambda-expression : ceci n'est pas testé à l'évaluation.
On redéfinit les opérateurs du langage en modifiant leur valeur de représentation. Celle-ci retourne maintenant un résultat qui appartient au « monde Lisp » (en particulier conv-int et conv-real sont les conversions lexicales de chaînes de caractères en entiers et réels respectivement).
Figure 2 : grammaire d'exécution [ << masquer ]
(def type-int
((def nom () ("integer"))
(def conv ()
(exec
(conv-int (clean STG))))))
(def type-real
((def nom () ("real"))
(def conv ()
(exec
(conv-real (clean STG))))))
(def pgme ()
((PGME-DECLA)
(PGME-INSTR)))
(def pgme-decla ())
(def pgme-instr ()
((lst-init ((INSTR*))
((INSTR)))))
(def decla ())
(def affect ()
(funclean VAR () ((clean EXP))))
(def affiche ()
(exec
(print (clean EXP))))
(def cond ()
(exec
(if (clean EXP-COND) (use THEN-CLAUSE) (use ELSE-CLAUSE))))
(def exp-egal ()
(exec
(= (clean EXP1) (clean EXP2))))
(def exp-diff ()
(exec
(<> (clean EXP1) (clean EXP2))))
(def then-clause ()
((lst-init ((INSTR*))
((INSTR)))))
(def else-clause ()
((lst-init ((INSTR*))
((INSTR)))))
(def var
((def lect ()
(exec
(setq aux (recht 'VAL))
(setq aux (cdr (nth <fct> (repq (cdr aux)))))
(car aux)))
(def ecr ()
(exec
'(lambda (x)
(setq aux (recht 'VAL))
(setq aux (cdr (nth <fct> (repq (cdr aux)))))
(rplaca aux x))))
(def init ()
((clean INIT)))))
La "décompilation" du programme dans cette grammaire fournit le résultat de son évaluation symbolique. Ici, il s'affiche :
'Erreur'
'fin'