Interpréteur basé sur la notation polonaise inverse - Geert

Transcription

Interpréteur basé sur la notation polonaise inverse - Geert
Interpréteur basé sur la notation polonaise inverse
Comment évaluer un langage à pile et comment l’optimiser ?
Geert-Jan Huizing
Avril 2016
1
Introduction
L’objectif de ce TIPE est de créer un langage informatique basé sur la notation polonaise inverse (NPI),
aussi appelée postfixe. L’idée est d’écrire les opérateurs de façon postfixe (1 2 +) au lieu d’infixe (1+2). Ainsi :
On remarque que l’absence de parenthèses rend la NPI plus compacte. De plus, les éléments sont organisés
dans l’ordre de lecture d’un ordinateur, et il est facile d’évaluer une telle expression au moyen d’un automate
à pile. Le langage Forth et certaines calculatrices HP utilisent donc cette notation.
On se propose d’implémenter en Python un interpréteur pour un langage basé sur la NPI. On se contentera
dans un premier temps d’évaluer des expressions simples du type 1 2 3 × + ou encore 3 4 / 6 + .
Puis on ajoutera progressivement des fonctionnalités nouvelles comme la gestion de flottants, de boucle
conditionnelles, de fonctions et d’autres opérateurs.
2
Structures de données
On utilisera des piles. Une pile est une suite d’éléments (ici des caractères) suivant le principe LIFO
(Last-In First-Out). Les opérations suivantes sont disponibles :
—
—
—
—
—
3
Créer une pile
Ajouter un élément
Lire le contenu du dernier élément
Enlever le dernier élément (on dira
Vérifier si la pile est vide
dépiler )
Une première version
Simplifions le problème au maximum : une seule ligne de calcul, des nombres entiers, et les seules opérations
élémentaires + − × / 1 . On suppose disposer de plus d’une pile P de tokens 2 telle que l’on dépile dans
l’ordre de saisie : ainsi, à l’expression 1 2 + correspond la pile d’éléments + 2 1 .
1. Les nombres étant entiers, la division est sous-entendue entière.
2. On appelle tokens des éléments lexicaux : ici, soit des nombres soit des opérateurs. A terme on ajoutera par exemple des
noms de fonctions (sin, cos, ...).
1
Algorithme
On crée une nouvelle pile, que l’on peuple de nombres sur lesquels on réalise les opérations.
— Créer une nouvelle pile Q
— Tant que P n’est pas vide
— Dépiler le dernier élément de P. Notons le E
— Si c’est un nombre, l’empiler dans Q
— Si c’est un opérateur
— Dépiler les deux derniers nombres de Q. Notons les A et B
— Empiler dans Q le résultat de l’opération entre A et B correspondant à l’opérateur E
— Renvoyer le dernier élément de Q
Remarque
1
1
1
3
2
4
2
4
4
3
Il faut veiller à ne pas dépiler sur une pile vide. Exemple :
+
2 + ∗
+ 4 ∗ 2 +
+ ∗
donne 1
donne 3
donne 6 ∗ 1 = 6
donne ( 7 ∗ 4 ) + 2 = 29
erreur
Pistes d’amélioration
Multiplicité des calculs A terme, le langage devra pouvoir effectuer plusieurs calculs, qui seront présentés
sous forme d’un fichier de plusieurs lignes (une ligne par calcul). On peut alors envisager le rappel d’un
résultat précédent ( Ans présent sur de nombreuses calculatrices).
Type de nombres Il devra supporter les flottants voire les complexes.
Boucles et fonctions Il convient d’ajouter les fonctions mathématiques de base (par exemple trigonométriques), et éventuellement la définition de fonctions personnalisées et l’usage de boucles conditionnelles.
Les conditions impliquent des opérateurs booléens et éventuellement un type booléen (on peut aussi agir sur
les nombres 0 et 1).
Opérateurs On peut ajouter un équivalent au symbole - unitaire (par exemple : 1 neg ⇐⇒ -1),
l’exponentiation, ainsi que des opérateurs de pile (par exemple, la duplication du dernier élément de la pile,
ou la permutation des deux derniers éléments). Il faut donc adapter l’algorithme pour que les opérateurs
unitaires ou sans arguments ne dépilent que le nombre de tokens nécessaires.
Optimisation Il faut prendre en compte deux types de complexité : en temps et en mémoire. L’idée est
de les limiter toutes deux et de vérifier expérimentalement que la complexité réelle correspond bien à la
complexité théorique. En effet, l’utilisation de certaines structures de données peut engendrer un surcoût
caché. L’ajout de nouvelles fonctionnalités mènera sans doute à des compromis. Leur analyse et la justification
de la solution conservée constituent une démarche de recherche scientifique et permet de complexifier le sujet
autant que nécessaire.
Sources
— Hamblin, C. L., 1962, Translation to and from Polish notation , The Computer Journal, 5 : 210-213
— Haran, B., [Computerphile], 2014, Reverse Polish Notation and The Stack - Computerphile , fichier
vidéo récupéré sur https://www.youtube.com/watch?v=7ha78yWRDlE
— Brodie, L., 2004, Thinking Forth 2