Probleme – Une grammaire pour la logique propositionnelle
Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 30 — Grammaires non contextuelles
Énoncé
Le programme demande de « montrer comment définir … une formule de la logique propositionnelle par une grammaire ».
- Écrire une grammaire non ambiguë pour les formules sur , avec , , et par priorités décroissantes, l'implication étant associative à droite.
- Écrire l'analyseur qui construit le type inductif du chapitre chap:logique.
- Décider si une formule est une tautologie.
Corrigé
1. La grammaire. On note par {}, par &, par | et par >. Un niveau par priorité, du moins prioritaire au plus prioritaire. On écrit les règles une par ligne et l'on sépare les variantes par le mot « ou » : la barre verticale appartient ici à l'alphabet, elle ne peut donc plus servir de notation pour l'alternance.
I --> D > I ou D (implication, recursive a DROITE)
D --> D | C ou C (disjonction, recursive a gauche)
C --> C & N ou N (conjonction, recursive a gauche)
N --> N ou A (negation, prefixe)
A --> ( I ) ou p ou q ou r ou 0 ou 1
L'implication est le seul niveau récursif à droite, et ce n'est pas un détail de présentation : c'est ainsi que se lit . Les deux autres binaires sont récursifs à gauche, donc traduits par des boucles.
2. L'analyseur. Le type est celui du chapitre chap:logique ; la grammaire en est la syntaxe concrète.
type formule =
| Vrai | Faux
| Var of char
| Non of formule
| Et of formule * formule
| Ou of formule * formule
| Implique of formule * formule
let analyser texte =
let n = String.length texte in
let pos = ref 0 in
let regarde () = if !pos < n then Some texte.[!pos] else None in
let lire c =
if !pos < n && texte.[!pos] = c then incr pos
else raise (Echec (Printf.sprintf "attendu %c en position %d" c !pos))
in
let rec i () = (* implication : recursive a DROITE *)
let g = d () in
match regarde () with
| Some '>' -> lire '>'; Implique (g, i ())
| _ -> g
and d () = (* disjonction : a gauche, donc BOUCLE *)
let acc = ref (c ()) in
while regarde () = Some '|' do lire '|'; acc := Ou (!acc, c ()) done;
!acc
and c () = (* conjonction : a gauche, donc BOUCLE *)
let acc = ref (nn ()) in
while regarde () = Some '&' do lire '&'; acc := Et (!acc, nn ()) done;
!acc
and nn () =
match regarde () with
| Some ' ' -> lire ' '; Non (nn ())
| _ -> atome ()
and atome () =
match regarde () with
| Some '(' -> lire '('; let x = i () in lire ')'; x
| Some '0' -> lire '0'; Faux
| Some '1' -> lire '1'; Vrai
| Some ch when ch >= 'p' && ch <= 'r' -> incr pos; Var ch
| Some ch -> raise (Echec (Printf.sprintf "symbole inattendu %c en %d" ch !pos))
| None -> raise (Echec "formule attendue, fin du texte")
in
let x = i () in
if !pos <> n then raise (Echec (Printf.sprintf "reste a lire en %d" !pos));
x
Noter que nn s'appelle elle-même pour la négation préfixe : c'est une récursivité à droite, elle consomme le {} avant de s'appeler, donc elle termine.
3. Décider une tautologie. On évalue sous les valuations et l'on regarde si la réponse est toujours vraie. Les tables de vérité mesurées, les huit valuations étant rangées dans l'ordre binaire de , de à :
| Texte | Arbre construit | Table de vérité |
|---|---|---|
| `p>q>r` | `(p>(q>r))` | `11111101` |
| `(p>q)>r` | `((p>q)>r)` | `01011101` |
| `p|q&r` | `(p|(q&r))` | `00011111` |
| `(p|q)&r` | `((p|q)&r)` | `00010101` |
| ` {`(p&q)} | ` {`(p&q)} | `11111100` |
| ` {`p| {}q} | `( {`p| {}q)} | `11111100` |
| `(p>q)&(q>r)>(p>r)` | `(((p>q)&(q>r))>(p>r))` | `11111111` |
Trois lectures de ce tableau :
- les priorités sont bien celles annoncées :
p|q&ret(p|q)&rn'ont pas la même table ; sans les niveaux de la grammaire, on ne pourrait pas les distinguer ; - l'associativité de l'implication compte :
p>q>ret(p>q)>rdiffèrent ; - les lois de De Morgan se lisent :
{(p&q)} et{p| {}q} ont la même table. Le programme le confirme aussi pour{(p|q)} et{p& {}q}, et pourp>qet{p|q}.
Le dernier essai, , a une table constante à : c'est le syllogisme, et c'est bien une tautologie — mesuré, pas supposé.
Ce que le problème apporte. Le chapitre chap:logique manipule des formules ; le chapitre chap:deduction les démontre. Ni l'un ni l'autre ne dit d'où vient l'objet. Il vient d'ici : un texte, une grammaire, un analyseur, un arbre. Le passage de la syntaxe concrète — une chaîne de caractères — à la syntaxe abstraite — une valeur du type inductif — est le seul endroit du livre où l'on voit une formule naître.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.