Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 1
Vers des analyseurs syntaxiques efficaces et bien typ ´es
Franc¸ois Pottier et Yann R ´egis-Gianas
4 janvier 2005
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 2
Introduction
Un automate
Implantation en ML
Au-del `a de ML
Conclusion
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 3
En bref
Le propos de cet expos ´e est d’illustrer le slogan informel selon lequel un syst`eme de types expressif permet de garantir la sˆuret ´e de programmes complexes.
La classe de programmes consid ´er ´ee sera celle des analyseurs syntaxiques LR et le syst`eme de types une extension de ML.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 4
Les analyseurs LR
On aime sp ´ecifier un analyseur syntaxique sous forme d’une
grammaire non contextuelle, typiquement au format BNF, d ´ecor ´ee par des actions s ´emantiques.
On aime implanter un analyseur syntaxique sous forme d’un automate d ´eterministe `a pile (DPDA).
Les grammaires LR sont celles pour lesquelles une telle implantation est possible.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 5
Les g ´en ´erateurs d’analyseurs LR
Il existe des outils pour engendrer, `a partir d’une grammaire LR, un programme qui simule l’ex ´ecution de l’automate correspondant.
Peut-on garantir la sˆuret ´e des programmes ainsi engendr ´es sans devoir exiger une confiance en la correction de l’outil ?
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 6
Introduction
Un automate
Implantation en ML
Au-del `a de ML
Conclusion
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 7
Une grammaire simple
Voici une grammaire LR tr`es simple, tir ´ee du « Dragon Book: » (1) E{x}+T{y} → E{x+y}
(2) T{x} → E{x}
(3) T{x}*F{y} → T{x×y}
(4) F{x} → T{x}
(5) (E{x}) → F{x}
(6) int{x} → F{x}
Les terminaux ou lex`emes sont +, *, (, ) et int. Les non-terminaux sont E, T et F. Les quatre premiers n’ont pas de valeur s ´emantique ; les quatre derniers ont une valeur s ´emantique enti`ere.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 8
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
Voici un automate `a pile qui reconnaˆıt cette grammaire.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 9
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S1
´Etat Pile
Entr ´ee Prochaine action
shift S4
( int ) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 10
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S4
´Etat Pile
Entr ´ee Prochaine action
S1 ( shift S10
int ) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 11
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S10
´Etat Pile
Entr ´ee Prochaine action
S1 ( S4 int reduce int→F, goto F ) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 12
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
´Etat Pile
Entr ´ee Prochaine action
S1 ( S4 F goto F
) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 13
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S5
´Etat Pile
Entr ´ee Prochaine action
S1 ( S4 F reduce F→T, goto T ) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 14
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S6
´Etat Pile
Entr ´ee Prochaine action
S1 ( S4 T reduce T →E, goto E ) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 15
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S11
´Etat Pile
Entr ´ee Prochaine action
S1 ( S4 E shift S12
) $
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 16
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S12
´Etat Pile
Entr ´ee Prochaine action
S1 ( S4 E S11 ) reduce (E)→F, goto F
$
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 17
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S5
´Etat Pile
Entr ´ee Prochaine action
S1 F reduce F→T, goto T
$
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 18
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S6
´Etat Pile
Entr ´ee Prochaine action
S1 T reduce T →E, goto E
$
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 19
S12 ...
S11 ...
)
S3 ...
+
S10 ...
<)> F:Int.
...
S9 ...
S8 ...
Int F
S4 ...
(
S7 ...
*
S6 ...
*
S5 ...
E
Int T
F (
Int T
F ( S2
... +
S1 ...
Int T
F
(
E
S2
´Etat Pile
Entr ´ee Prochaine action
S1 E accept
$
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 20
Introduction
Un automate
Implantation en ML
Au-del `a de ML
Conclusion
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 21
Que produisent les outils existants ?
Yacc, Bison, etc. produisent des programmes C, donc sans garantie de sˆuret ´e. Ils utilisent une union pour repr ´esenter les valeurs s ´emantiques.
ML-Yacc ou Happy produisent des programmes ML ou Haskell, donc typ ´es. N ´eanmoins, le typage n’empˆeche pas la lev ´ee d’une exception pendant l’ex ´ecution, en cas d’ ´echec d’un filtrage.
A quoi ressemble le code produit par ces derniers ?`
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 22
Interface avec l’analyseur lexical
Les lex`emes sont constitu ´es d’une ´etiquette et ´eventuellement d’une valeur s ´emantique:
type token = KPlus | KStar | KLeft | KRight | KEnd | KInt of int L’analyseur lexical fournit deux fonctions pour consulter et jeter le lex`eme courant:
val peek : unit → token val discard : unit → unit
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 23
Structures de donn ´ees
Le type des ´etats se d ´efinit ais ´ement:
type state = S0 | S1 | . . . | S11
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 24
Structures de donn ´ees (suite)
La pile est form ´ee de paires d’un ´etat et d’une valeur s ´emantique dont le type d ´epend du non-terminal auquel elle est associ ´ee. Il s’agit donc d’une liste chaˆın ´ee de cellules ´etiquet ´ees.
type stack =
| SEmpty
| SPlus of stack × state
| SStar of stack × state
| SLeft of stack × state
| SRight of stack × state
| SEnd of stack × state
| SInt of stack × state × int
| SE of stack × state × int
| ST of stack × state × int
| SF of stack × state × int
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 25
Implantation (structure g ´en ´erale)
L’automate est implant ´e par une fonction run qui, ´etant donn ´es l’ ´etat, la pile et (implicitement) le flot de lex`emes courants, produit la valeur s ´emantique correspondant au mot complet ou bien ´echoue.
let rec run (s : state) (stack : stack) : int = match s, peek() with
| . . . (∗ transitions shift ou reduce ∗)
| , →
raise SyntaxError
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 26
Implantation (d ´ecalage)
Une transition shift empile ´etat courant et valeur s ´emantique associ ´ee au lex`eme courant, consomme ce dernier, et modifie l’ ´etat courant:
let rec run (s : state) (stack : stack) : int = match s, peek() with
| . . .
| S9, KStar → (∗ shift S7 ∗) discard ();
run S7 (SStar (stack, S9))
| . . .
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 27
Implantation (r ´eduction)
Une transition reduce d ´epile un certain nombre de valeurs s ´emantiques, les exploite pour en calculer une nouvelle, et empile celle-ci.
let rec run (s : state) (stack : stack) : int = match s, peek() with
| . . .
| S9, KPlus → (∗ reduce E{x}+T{y} →E{x+y} ∗) let ST (SPlus (SE (stack, s , x ), ), , y) = stack in let stack = SE (stack, s, x + y) in
gotoE s stack (∗ goto E ∗)
| . . .
On observe ici un filtrage non exhaustif.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 28
Implantation (fin)
Une transition goto se base sur l’ ´etat extrait de la pile pendant la r ´eduction pour d ´eterminer le prochain ´etat courant.
and gotoE (s : state) : stack → int = match s with
| S0 → run S1
| S4 → run S8
On observe un nouveau filtrage non exhaustif.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 29
En r ´esum ´e
Ce programme est consid ´er ´e par le compilateur ML comme bien typ ´e.
N ´eanmoins, celui-ci affiche des avertissements pour filtrage non exhaustif, ce qui signifie que l’absence d’ ´echec `a l’ex ´ecution n’est pas garantie.
Le probl`eme est de r ´e ´ecrire le programme de fac¸on `a n’effectuer que des filtrages exhaustifs. En supprimant les tests dynamiques
redondants, on obtiendra une garantie de sˆuret ´e et une meilleure efficacit ´e.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 30
Introduction
Un automate
Implantation en ML
Au-del `a de ML
Conclusion
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 31
Pourquoi ces tests sont-ils redondants ?
Les tests dynamiques effectu ´es lors de la transition reduce
pr ´ec ´edente sont redondants parce que, lorsque l’automate est dans l’ ´etat S9, la pile est n ´ecessairement de la forme
. . . ? E ? + ? T
Les tests dynamiques effectu ´es lors de la transition goto E
pr ´ec ´edente sont redondants parce que, lorsque l’automate est dans l’ ´etat S9, la pile est n ´ecessairement de la forme
. . . (S0|S4) ? ? ? ? ?
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 32
L’invariant (fragment)
En fait, on peut d ´emontrer que, lorsque l’automate est dans l’ ´etat S9, la pile est n ´ecessairement de la forme
. . . (S0|S4) E (S1|S8) + S6 T
Plus g ´en ´eralement, la connaissance de l’ ´etat courant d ´etermine celle d’un suffixe de la pile...
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 33
L’invariant complet
Pile ´Etat
S0
S0 E S1
. . . (S0|S4) T S2
. . . (S0|S4|S6) F S3
. . . (S0|S4|S6|S7) ( S4
. . . (S0|S4|S6|S7) int S5
. . . (S0|S4) E (S1|S8) + S6
. . . (S0|S4|S6) T (S2|S9) * S7 . . . (S0|S4|S6|S7) ( S4 E S8
. . . (S0|S4) E (S1|S8) + S6 T S9 . . . (S0|S4|S6) T (S2|S9) * S7 F S10 . . . (S0|S4|S6|S7) ( S4 E S8 ) S11
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 34
Vers un typage plus fin
On d ´emontre manuellement sans difficult ´e, par induction structurelle sur une ex ´ecution de l’automate, la correction de l’invariant.
Pour que le compilateur puisse exploiter cet invariant, il faut qu’on le lui fournisse explicitement, et qu’il le v ´erifie m ´ecaniquement.
Le langage de programmation doit ˆetre dot ´e d’un syst`eme de types suffisamment expressif pour permettre le codage de l’invariant.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 35
L’id ´ee
Il faut expliquer au compilateur qu’il y a corr ´elation entre ´etat courant et structure de la pile.
Pour cela, nous param ´etrons le type state par une variable de types α. L’id ´ee est que si l’ ´etat courant admet le type αstate, alors la pile courante est de type α.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 36
Structure des piles
Le type stack disparaˆıt. La structure des piles sera d ´efinie `a l’aide d’une famille de types param ´etr ´es d ´efinis de fac¸on mutuellement ind ´ependante:
type empty = SEmpty
type α cellPlus = SPlus of α×αstate type α cellStar = SStar of α×αstate type α cellLeft = SLeft of α×αstate type α cellRight = SRight of α×αstate type α cellInt = SInt of α×αstate type α cellE = SE of α×αstate×int type α cellT = ST of α×αstate×int type α cellF = SF of α×αstate×int (Comparer `a la d ´efinition originale.)
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 37
Codage de l’invariant (fragment)
Le fait, lorsque l’automate est dans l’ ´etat S9, la pile est n ´ecessairement de la forme
. . . ? E ? + ? T,
sera cod ´e en attribuant `a la constante S9 le type
∀α.αcellE cellPlus cellTstate
et de mˆeme pour les autres ´etats.
Une telle d ´eclaration est impossible en ML! Le type state sera un type de donn ´ees alg ´ebrique g ´en ´eralis ´e ou gard ´e (GADT).
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 38
Structure des ´etats
type state : ∗ → ∗ where
| S0 : empty state
| S1 : empty cellE state
| S2 : ∀α.αcellT state
| S3 : ∀α.αcellF state
| S4 : ∀α.αcellLeft state
| S5 : ∀α.αcellInt state
| S6 : ∀α.αcellE cellPlus state
| S7 : ∀α.αcellT cellStar state
| S8 : ∀α.αcellLeft cellE state
| S9 : ∀α.αcellE cellPlus cellT state
| S10 : ∀α.αcellT cellStar cellF state
| S11 : ∀α.αcellLeft cellE cellRight state
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 39
Implantation (structure g ´en ´erale)
Le type de la fonction run est modifi ´e: elle accepte un ´etat arbitraire et une pile dont la structure est coh ´erente vis- `a-vis de cet ´etat.
let rec run : ∀α.αstate→α→int = fun s stack →
match s, peek() with
| . . .
| , →
raise SyntaxError (Comparer au type original.)
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 40
Implantation (d ´ecalage)
Le code d’une transition shift est inchang ´e, mais la v ´erification de types devient plus subtile.
let rec run : ∀α.αstate→α→int = fun s stack →
match s, peek() with
| S9, KStar →
(∗ SStar (stack, S9) a le type αcellStar ∗) (∗ run S7 a le type ∀γ.γcellT cellStar→int ∗) (∗ Or α=βcellE cellPlus cellT, pour β inconnu ∗)
(∗ Donc αcellStar=γ cellT cellStar, pour γ=βcellE cellPlus ∗) discard ();
run S7 (SStar (stack, S9)) (Consulter la d ´efinition du type des ´etats.)
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 41
Implantation (r ´eduction)
Le code d’une transition reduce est ´egalement inchang ´e, mais le filtrage est maintenant exhaustif.
let rec run : ∀α.αstate→α→int = fun s stack →
match s, peek() with
| S9, KPlus →
(∗ α=βcellE cellPlus cellT, pour β inconnu ∗) (∗ Donc stack:βcellE cellPlus cellT ∗)
let ST (SPlus (SE (stack, s , x ), ), , y) = stack in (∗ stack:β, s:βstate, x:int, y:int ∗)
let stack = SE (stack, s, x + y) in (∗ stack:βcellE ∗)
gotoE s stack
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 42
Implantation (fin)
Le type attribu ´e `a gotoE indique qu’au sommet de pile doit se trouver une cellule associ ´ee au non-terminal E et que le reste de la pile doit ˆetre coh ´erent avec l’ ´etat s.
and gotoE : ∀α.αstate→αcellE→int = fun s →
match s with
| S0 → run S1
| S4 →
(∗ run S8 a le type βcellLeft cellE→int, pour tout β ∗) (∗ Or α=βcellLeft, pour β inconnu ∗)
run S8
(Ce filtrage reste non exhaustif.)
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 43
En r ´esum ´e
Nous avons cod ´e une partie de l’invariant dans les d ´eclarations de types de donn ´ees et dans les types attribu ´es aux fonctions run et goto. On pourrait coder l’int ´egralit ´e de l’invariant.
Alors, la v ´erification des types contient la d ´emonstration de l’invariant.
Le filtrage fournit localement de nouvelles hypoth`eses, que l’on peut exploiter pour ´etablir une ´egalit ´e entre types.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 44
Introduction
Un automate
Implantation en ML
Au-del `a de ML
Conclusion
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 45
R ´esultats
Nous avons obtenu une garantie de sˆuret ´e `a propos de l’analyseur syntaxique engendr ´e, sans devoir exiger une confiance en la correction du g ´en ´erateur.
L’outil qui produit l’automate connaˆıt l’invariant, ou croit le connaˆıtre, et engendre sans difficult ´e les d ´eclarations de types appropri ´ees.
Si l’outil produit un programme incorrect, celui-ci sera rejet ´e par le compilateur.
Il reste n ´ecessaire d’avoir confiance en la correction du compilateur,
`a moins d’employer un compilateur certifiant.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 46
Mieux prouver nos programmes
Nous avons exploit ´e un syst`eme de types tr`es expressif pour prouver la sˆuret ´e d’un programme.
Des assistants `a la preuve, comme Coq, permettent cela depuis longtemps. Ici, cependant, nous sommes rest ´es dans le cadre d’un langage de programmation dot ´e, en particulier, d’un m ´ecanisme d’inf ´erence de types puissant et d’un sch ´ema de compilation tr`es efficace.
R ´eduire le foss ´e entre programmation et preuve reste l’objet de recherches actives.
Introduction Un automate Implantation en ML Au-del `a de ML Conclusion 47
R ´ef ´erences
Transparents de cet expos ´e, version pr ´eliminaire de l’article, prototype du v ´erificateur de types et prototype du g ´en ´erateur d’analyseurs syntaxiques sont disponibles en ligne:
http: // cristal. inria. fr/ ~fpottier/
http: // cristal. inria. fr/ ~regisgia/