CentraleSupélec LMF, UMR CNRS 9021
Département informatique Laboratoire Méthodes Formelles
Bât Breguet, 3 rue Joliot-Curie Bât 650 Ada Lovelace, Université Paris Sud
91190 Gif-sur-Yvette, France Rue Noetzlin, 91190 Gif-sur-Yvette, France
Niklaus

Niklaus (nommé d'après Niklaus Wirth) est le langage utilisé pour illustrer le cours de traitement des langages.

Nous le reprenons comme langage d'application dans ce cours de sémantique.

Note : Le matériel présenté ici est largement adapté de Concrete Semantics de Tobias Nipkow, que je vous invite à visiter pour approfondir le sujet.

Transparents :

Fichiers Isabelle : NikausIsabelle.zip

Introduction

Transparents du cours (introduction)

Transparents du cours (sémantique de Niklaus)

Syntaxe concrète de Niklaus

La structure d'un programme Niklaus est la suivante :

Les variables de Niklaus sont du type entier. Les littéraux et les variables peuvent être combinés en expressions à l'aide des quatre opérateurs arithmétiques usuels (+, -, *, /) et des parenthèses.

Pour la condition des instructions de boucle et d'alternative, les expressions peuvent être comparées avec <, <=, =, <>, > et >=.

Les instructions de Niklaus sont :

lit un entier sur le flux d'entrée et l'affecte à la variable <var>.

écrit la valeur de la variable <var> sur le flux de sortie.

affecte la valeur de <expression> à la variable <var>.

exécute <instr1> si la <condition> est vraie, <instr2> sinon

exécute <instruction> si <condition> est vraie, et recommence. Ne fait rien si <condition> est fausse.

Les instructions peuvent être groupées en une instruction en les plaçant entre accolades.

Exemple :

Sémantique des expressions arithmétiques

Exercice

Définir une fonction simplify :: "expression => expression" qui simplifie une expression (somme avec 0, produit par 0 et par 1, opération sur des constantes), et prouver que cette simplification ne modifie pas la valeur d'une expression.

Sémantique des expressions booléennes

Syntaxe abstraite des instructions

On définit un type inductif instruction permettant de représenter la syntaxe abstraite des programmes Niklaus.

Le type state représente l'état de la machine d'exécution.

Sémantique opérationnelle naïve

Sémantique opérationnelle à grand pas

Transparents du cours

Sémantique dénotationnelle

Transparents du cours

Sémantique dénotationnelle naïve

Une première tentative de définition d'une fonction qui associe à chaque instruction la relation qu'elle établit entre les états de la machine d'exécution. Cette tentative échoue car la sémantique de la boucle while ne peut pas être définie de cette façon (on ne peut pas prouver sa terminaison).

Sémantique des définitions récursives

On illustre ici le problème du sens que l'on peut donner à une définition récursive à travers l'exemple de la factorielle et de la suite de Syracuse.

Définition d'une fonction récursive comme plus petit point fixe d'un foncteur

La définition usuelle de la factorielle {$\operatorname{fac} = \lambda n. \operatorname{if} n = 0 \operatorname{then} 1 \operatorname{else} n \operatorname{fac} (n-1)$} est récursive. Dans l'exemple ci-dessous, on donne un sens à cette définition en considérant une fonction comme une relation, c'est-à-dire un ensemble de paires d'éléments. À l'aide d'un foncteur {$\operatorname{Fac}$}, on construit une suite de fonctions partielles qui sont des approximations de plus en plus précises de {$\operatorname{fac}$}, et on définit {$\operatorname{fac}$} comme la limite de cette suite, qui est le plus petit point fixe de {$\operatorname{Fac}$}.

L'utilisation de relations entre entiers plutôt que de fonctions nous permet de travailler sur l'ensemble des relations entre entiers qui, muni de la relation d'inclusion, est un treillis complet (toute paire de relation admet une borne inférieure et une borne supérieure (respectivement l'intersection et l'union des relations), ce qui nous permet d'utiliser le théorème de Knaster-Tarski qui garantit que toute fonction croissante sur ce treillis admet un plus petit point fixe.

Sémantique dénotationnelle de Niklaus

Dans cette sémantique, la définition récursive de la boucle while telle que nous l'avions donnée pour la sémantique à grands pas, est traitée de manière similaire à la factorielle : la sémantique du while est définie comme le plus petit point fixe d'un foncteur.

Preuve de l'équivalence entre la sémantique à grand pas et la sémantique dénotationnelle

Nous avons deux définitions de la sémantique de Niklaus, une opérationnelle et une dénotationnelle. On montre ici que ces deux définitions sont équivalentes.

Sémantique axiomatique de Nikaus

Transparents du cours

Cette sémantique indique comment l'exécution d'une instruction affecte les prédicat valides sur l'état de la machine d'exécution. On exprime cela sous la forme de triplets de Hoare : {$\vDash \{\varphi\} P \{\psi\}$} indique que si la précondition {$\varphi$} est vraie dans un état, et que l'on exécute {$P$} dans cet état, alors la postcondition {$\psi$} est vraie dans l'état de la machine après exécution de {$P$}. Cette définition repose sur la sémantique à grands pas de Niklaus.

Nous allons définir la sémantique axiomatique de Niklaus comme un jeu de règles permettant de dériver des triplets de Hoare. On note {$\vdash \{\varphi\} P \{\psi\}$} le fait qu'un triplet puisse être dérivé selon ces règles :

Exemple de preuve utilisant la sémantique axiomatique

Grâce au jeu de règles de la sémantique axiomatique de Niklaus, on peut prouver la correction d'un programme Niklaus qui calcule le PGCD de deux entiers par soustractions successives :

Les définitions et les théorèmes utilisés dans cette démonstration sont donnés ci-dessous :

Preuve de la consistence et de la complétude des règles

La consistence des règles de dérivation est le fait que tout triplet dérivable est valide, c'est-à-dire que : {$$\vdash \{\varphi\} P \{\psi\} \implies \vDash \{\varphi\} P \{\psi\}$$}

La complétude des règles de dérivation est le fait que tout triplet valide peut-être dérivé des règles : {$$\vDash \{\varphi\} P \{\psi\} \implies \vdash \{\varphi\} P \{\psi\}$$}

La preuve de la complétude fait appel à la notion de plus faible précondition permettant de valider la postcondition après l'exécution d'une instruction :