Mots clés : analyse dynamique, analyse
statique, sémantique, interprétation abstraite, compilation
optimisante .
- Interprétation abstraite
- L'interprétation abstraite est un cadre permettant
de relier différentes interprétations sémantiques d'un
programme. Souvent, l'interprétation abstraite sert à
montrer la correction d'une analyse, présentée comme une
définition de la sémantique d'un langage sur un ensemble
de propriétés « abstraites » (par rapport à la
sémantique standard du langage).
- Itération de points fixes
- Le résultat d'une analyse est souvent donné comme
la solution d'une équation x =
f (x) où f est une fonction monotone sur un
ordre partiel. Le théorème de Knaster-Tarski indique un
algorithme pour trouver un tel point fixe en calculant la
limite de la suite itérative fn(
) où
désigne l'élément le plus petit
dans l'ordre partiel.
Résumé :
L'analyse de programmes désigne l'ensemble des
techniques qui permettent de déduire mécaniquement des
propriétés des programmes. Ses principaux domaines
d'application sont la compilation et l'aide à la mise au
point de programmes. Comme exemples d'analyses existantes,
nous pouvons citer l'analyse d'alias, le slicing,
les analyses de dépendances. Une analyse peut être
dynamique, elle porte alors sur une trace d'exécution
particulière, ou statique, et valable pour toute exécution
de programme. Dans les deux cas, sa correction doit être
assurée, ce qui signifie que les informations qu'elle
procure doivent être cohérentes avec la sémantique du
programme analysé.
L'analyse de programmes désigne l'ensemble des techniques
qui permettent de déduire mécaniquement des propriétés des
programmes. Ses principaux domaines d'application sont la
compilation et l'aide à la mise au point de programmes.
- Les analyses de flots de données qui permettent de
détecter notamment les variables inutiles ou les
expressions calculées à un point de programme donné.
- Les analyses d'alias qui produisent des informations
sur le partage entre variables dans les langages à
manipulation explicite de pointeurs.
- Les analyses de nécessité qui identifient les arguments
qui sont indispensables à l'évaluation d'une fonction.
- Les analyses de mode qui déterminent le degré
d'instanciation des variables dans les prédicats
logiques.
- Le filtrage de programmes ( slicing) qui
consiste à identifier les instructions d'un programme
nécessaires au calcul de variables données.
On distingue deux classes d'analyses : les analyses
dynamiques et les analyses statiques. L'analyse dynamique
déduit des propriétés d'un programme à partir d'une trace
d'exécution particulière [BGL93]. En revanche, l'analyse statique
[NNH99] permet d'établir des propriétés
satisfaites par un programme pour toutes ses exécutions.
L'information recherchée est en général incalculable ou d'une
complexité importante. Une analyse statique ne peut donc
calculer qu'une approximation de la solution idéale. En
conséquence, les résultats de l'analyse statique sont moins
précis mais plus généraux que ceux fournis par une analyse
dynamique.
La conception d'une analyse comprend deux phases : la
spécification et l'implantation. L'analyse doit être
spécifiée d'une manière qui permet de prouver sa
correction ; celle-ci garantit la cohérence du résultat
de l'analyse par rapport à la sémantique du langage (cf
module 3.1). La correction
et la précision des analyses ont été étudiées de manière
extensive dans le cadre de l'interprétation abstraite
[Cou97]. Le résultat de cette première phase de
conception d'analyse est souvent un système d'équations
récursives dont la solution décrit les propriétés
recherchées. On dispose d'algorithmes itératifs pour résoudre
ce système d'équations (« itérateurs de points
fixes »). On peut également s'appuyer sur des calculs
formels sur l'algèbre des propriétés étudiées (calcul
symbolique) afin d'améliorer l'efficacité de la
résolution.