diff --git a/expression.py b/expression.py index b70ceac..d949223 100644 --- a/expression.py +++ b/expression.py @@ -1 +1,51 @@ -from lexer import Token +import re + +class Token: + NUMBER = 0 + OPERATOR = 1 + PARENTHESE = 2 + FUNCTION = 3 + + @staticmethod + def isNumber(n): + return re.match(r'\d+', str(n)) is not None + + @staticmethod + def getPrecedence(tok): + if tok == "(" or tok == "": + return 4 + elif tok == "*" or tok == "/": + return 3 + elif tok == "+" or tok == "-": + return 2 + + + def __init__(self, type, val): + self.type = type + self.val = val + +class Expression: + + def __init__(self, val=None, gauche=None, droite=None): + if Token.isNumber(val) and (gauche != None or droite != None): + raise AttributeError("gauche et droite ne peuvent pas exister si val est un nombre") + self.val = val + self.gauche = gauche + self.droite = droite + + def evalue(self): + if self.val == "+": + return self.gauche.evalue() + self.droite.evalue() + elif self.val == "-": + return self.gauche.evalue() - self.droite.evalue() + elif self.val == "*": + return self.gauche.evalue() * self.droite.evalue() + elif self.val == "/": + return self.gauche.evalue() / self.droite.evalue() + else: + return float(self.val) + + def __str__(self): + if Token.isNumber(self.val): + return str(self.val) + return "(" + str(self.gauche.__str__()) + str(self.val) + str(self.droite.__str__()) + ")" \ No newline at end of file diff --git a/infixe.py b/infixe.py index 4a06ed6..83005cf 100644 --- a/infixe.py +++ b/infixe.py @@ -29,7 +29,7 @@ class Token: PARENTHESE_OUVERTE = "(" PARENTHESE_FERME = ")" - NUMBER = re.compile(r'\d+') + NUMBER = re.compile(r'(?:\d+)?.\d+') @staticmethod def isNumber(n): @@ -59,7 +59,6 @@ def arbre(tokens): #-> Expression waiting_before_exp = None waiting_for_after_exp = None - ##Brackets loop i = 0 while i < len(tokens): if tokens[i] == "(": @@ -83,7 +82,7 @@ def arbre(tokens): #-> Expression else: waiting_before_exp = exp - elif tokens[i] == "*": + elif tokens[i] == "*" or tokens[i] == "+": exp = Expression("*") if Token.isNumber(tokens[i-1]): exp.gauche = tokens[i-1] @@ -102,49 +101,13 @@ def arbre(tokens): #-> Expression exp.gauche = waiting_before_exp waiting_for_after_exp = exp else: - raise Exception() - - elif tokens[i] == "+": - exp = Expression("+") - if Token.isNumber(tokens[i-1]): - exp.gauche = tokens[i-1] - if Token.isNumber(tokens[i+1]): - exp.droite = tokens[i+1] - if Token.isNumber(tokens[i-1]) and Token.isNumber(tokens[i+1]): - return exp - - if tokens[i-1] == ")": - exp.gauche = waiting_before_exp - waiting_before_exp = None - elif tokens[i+1] == "(": - waiting_for_after_exp = exp - print(exp) - elif tokens[i-1] == " ": - exp.gauche = waiting_before_exp - waiting_for_after_exp = exp - else: - raise Exception() - + raise Exception() i += 1 - ##Multiplication loop - #i = 0 - #while i != len(tokens): - # if tokens[i] == "*": - # print("at") - # return Expression("*", tokens[i-1], tokens[i+1]) - # i += 1 - ##Addition loop - #i = 0 - #while i != len(tokens): - # if tokens[i] == "+": - # return Expression("+", tokens[i-1], tokens[i+1]) - # i += 1 - return waiting_for_after_exp if __name__ == "__main__": - print(arbre(tokenize("(2*8)*4+(7*4)*7"))) + print(arbre(tokenize("(2*8)+(4+7)"))) diff --git a/lib/File.py b/lib/File.py new file mode 100644 index 0000000..64919e6 --- /dev/null +++ b/lib/File.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +class File_lst: + """Implémentation d'une file par une liste.""" + def __init__(self): + """Crée une file vide.""" + self.__file = [] + + def est_vide(self): + """Indique si la file est vide.""" + return self.__file == [] + + def enfiler(self, valeur): + """Enfile l'élément valeur.""" + self.__file.append(valeur) + + def defiler(self): + """Défile la tête de la file et la renvoie.""" + return self.__file.pop(0) + + def taille(self): + """Renvoie la taille de la file.""" + return len(self.__file) + + def tete(self): + """Renvoie la tête de la file (sans la défiler).""" + return self.__file[0] + + def __str__(self): + s = "tete->" + for val in self.__file: + s += str(val) + "->" + return s + "queue" + + +class Maillon: + """Un maillon d'une liste doublement chaînée.""" + def __init__(self, precedent, valeur, suivant): + self.valeur = valeur + self.precedent = precedent + self.suivant = suivant + + def __str__(self): + return str(self.valeur) + + +class File_chaine: + """Implémentation d'une file par une liste doublement chaînée.""" + def __init__(self): + """Crée une file vide.""" + self.__debut = self.__fin = None + self.__taille = 0 + + def est_vide(self): + """Indique si la file est vide.""" + return self.__taille == 0 + + def enfiler(self, valeur): + """Enfile l'élément valeur.""" + maillon = Maillon(self.__fin, valeur, None) + if self.est_vide(): + self.__debut = self.__fin = maillon + else: + self.__fin.suivant = maillon + self.__fin = maillon + self.__taille += 1 + + def defiler(self): + """Défile la tête de la file et la renvoie.""" + if self.est_vide(): + raise IndexError("Impossible de défiler une file vide.") + valeur = self.__debut.valeur + self.__taille -= 1 + if self.est_vide(): + self.__debut = self.__fin = None + else: + self.__debut = self.__debut.suivant + self.__debut.precedent = None + return valeur + + def taille(self): + """Renvoie la taille de la file.""" + return self.__taille + + def tete(self): + """Renvoie la tête de la file (sans la défiler).""" + if self.est_vide(): + raise IndexError("Une file vide n'a pas de tête.") + return self.__debut.valeur + + def __str__(self): + s = "tete->" + maillon = self.__debut + while maillon is not None: + s += str(maillon) + "->" + maillon = maillon.suivant + return s + "queue" + + +if __name__ == "__main__": + f = File_lst() + print(f.est_vide()) + f.enfiler('A') + f.enfiler('B') + f.enfiler('C') + print(f.est_vide()) + print(f.tete()) + print(f) + print(f.taille()) + print(f.defiler()) + print(f.defiler()) + print(f.defiler()) + print(f.est_vide()) diff --git a/lib/Pile.py b/lib/Pile.py new file mode 100644 index 0000000..3fe61cf --- /dev/null +++ b/lib/Pile.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from lib.listeChaine import ListeChaine + +class Pile_lst: + """Implémentation d'une pile par une liste.""" + def __init__(self): + """Crée une pile vide.""" + self.__pile = [] + + def est_vide(self): + """Indique si la pile est vide.""" + return self.__pile == [] + + def empiler(self, valeur): + """Empile la valeur.""" + self.__pile.append(valeur) + + def depiler(self): + """Dépile le sommet de la pile et le renvoie.""" + return self.__pile.pop() + + def taille(self): + """Renvoie la taille de la pile.""" + return len(self.__pile) + + def sommet(self): + """Renvoie le sommet de la pile (sans le dépiler).""" + return self.__pile[-1] + + def __str__(self): + s = "|" + for val in self.__pile: + s = str(val) + "->" + s + return s + + +class Pile_chaine: + """Implémentation d'une pile par une liste chaînée.""" + def __init__(self): + """Crée une pile vide.""" + self.__pile = ListeChaine() + self.__taille = 0 + + def est_vide(self): + """Indique si la pile est vide.""" + return self.__taille == 0 + + def empiler(self, valeur): + """Empile la valeur.""" + self.__pile.ajoute(valeur) + self.__taille += 1 + + def depiler(self): + """Dépile le sommet de la pile et le renvoie.""" + if self.est_vide(): + raise IndexError("Impossible de dépiler une pile vide.") + valeur = self.__pile.tete() + self.__pile = self.__pile.queue() + self.__taille -= 1 + return valeur + + def taille(self): + """Renvoie la taille de la pile.""" + return self.__taille + + def sommet(self): + """Renvoie le sommet de la pile (sans le dépiler).""" + if self.est_vide(): + raise IndexError("Une pile vide n'a pas de sommet.") + return self.__pile.tete() + + def __str__(self): + return str(self.__pile) + "->|" + + +if __name__ == "__main__": + p = Pile_lst() + print(p.est_vide()) + p.empiler('A') + p.empiler('B') + p.empiler('C') + print(p.est_vide()) + print(p.sommet()) + print(p) + print(p.taille()) + print(p.depiler()) + print(p.depiler()) + print(p.depiler()) + print(p.est_vide()) diff --git a/lib/listeChaine.py b/lib/listeChaine.py new file mode 100644 index 0000000..5c491ef --- /dev/null +++ b/lib/listeChaine.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Tue Sep 22 20:44:35 2020 + +@author: manu +""" + + +class Maillon: + """Un maillon d'une liste chaînée.""" + def __init__(self, valeur, suivant): + self.valeur = valeur + self.suivant = suivant + + def __str__(self): + """Renvoie une chane de caractères représentant le maillon.""" + return str(self.valeur) + + +class ListeChaine: + """Une liste chaînée.""" + def __init__(self, tete=None): + """Crée une liste vide, ou une liste dont la tete (un maillon) + est donnée.""" + self.__tete = tete + + def est_vide(self): + """Indique si la liste est vide.""" + return self.__tete is None + + def tete(self): + """Renvoie la valeur du premier élément de la liste.""" + if self.est_vide(): + raise IndexError("La liste vide n'a pas de tête") + return self.__tete.valeur + + def queue(self): + """Renvoie la queue de la liste.""" + if self.est_vide(): + raise IndexError("La liste vide n'a pas de queue") + return ListeChaine(self.__tete.suivant) + + def ajoute(self, valeur): + """ajoute `valeur` en tête de la liste.""" + self.__tete = Maillon(valeur, self.__tete) + + def __str__(self): + """Renvoie une chaîne de caractères représentant la liste.""" + maillon = self.__tete + s = '' + while maillon is not None: + s = s + str(maillon.valeur) + maillon = maillon.suivant + if maillon is not None: + s += '->' + return s + + def __len__(self): + """Renvoie la longueur de la liste.""" + maillon = self.__tete + long = 0 + while maillon is not None: + long = long + 1 + maillon = maillon.suivant + return long + + def __getitem__(self, n): + """Renvoie l'élément d'indice n de la liste.""" + maillon = self.__tete + i = 0 + while i < n and maillon is not None: + i = i + 1 + maillon = maillon.suivant + if maillon is None or n < 0: + raise IndexError("Indice non valide") + return maillon.valeur + + def __add__(self, other): + """Renvoie la liste correspondant à la concaténation des 2 listes.""" + if self.est_vide(): + return other + v = self.tete() + q = self.queue() + return ListeChaine(Maillon(v, (q + other).__tete)) + + def reverse(self): + """Renvoie une liste correspondant à la liste renversée.""" + res = ListeChaine() + maillon = self.__tete + while maillon is not None: + res.ajoute(maillon.valeur) + maillon = maillon.suivant + return res + + +if __name__ == "__main__": + lst = ListeChaine() + print(lst.est_vide()) + lst.ajoute(306) + lst.ajoute(42) + lst.ajoute(205) + print(lst) + print(lst.est_vide()) + print(lst[0]) + print(lst[1]) + print(len(lst)) + lst2 = ListeChaine() + lst2.ajoute(18) + lst2.ajoute(45) + print(lst + lst2) diff --git a/main.py b/main.py index e69de29..60ac061 100644 --- a/main.py +++ b/main.py @@ -0,0 +1,4 @@ +from reader import * + +cal = input("Entrez votre calcul en NPI : ") +print(npi2tree(tokenize(cal)).evalue()) \ No newline at end of file diff --git a/reader.py b/reader.py new file mode 100644 index 0000000..916922b --- /dev/null +++ b/reader.py @@ -0,0 +1,79 @@ +from expression import Token, Expression +from lib.Pile import Pile_chaine as Pile +from lib.File import File_chaine as File + +def tokenize(text): + buffer = "" + tokens = [] + for char in text: + #NUMBER + if Token.isNumber(char) or char == ".": + buffer += char + else: + #PUSH + if buffer != "": + print("a") + tokens.append(Token(Token.NUMBER, buffer)) + buffer = "" + #SINGLE CHAR + if char != " ": + if char == "(" or char == ")": + tokens.append(Token(Token.PARENTHESE, char)) + else: + tokens.append(Token(Token.OPERATOR, char)) + if buffer != "": + tokens.append(Token(Token.NUMBER, buffer)) + for token in tokens: + print(token.type, ":", token.val) + return tokens + +def shutting_yard(tokens): + output = File() + opertator = Pile() + for token in tokens: + if token.type == Token.NUMBER: + output.enfiler(token) + elif token.type == Token.FUNCTION: + opertator.empiler(token) + elif token.type == Token.OPERATOR: + if not opertator.est_vide(): + o2 = opertator.sommet() + a = o2 != "(" + print(o2.val) + b = Token.getPrecedence(o2.val) > Token.getPrecedence(token.val) + c = Token.getPrecedence(token.val) == Token.getPrecedence(o2.val) + + while a and (b or (c)): #and d)) + output.enfiler(opertator.depiler()) + opertator.empiler(token) + elif token.val == "(": + opertator.empiler(token) + elif token.val == ")": + while opertator.sommet() != "(": + assert not opertator.est_vide() + output.enfiler(opertator.depiler()) + assert opertator.sommet() == "(" + opertator.depiler() + if opertator.sommet().type == Token.FUNCTION: + output.enfiler(opertator.depiler()) + + while not opertator.est_vide(): + assert opertator.sommet != "(" + output.enfiler(opertator.depiler()) + + return output + + +def npi2tree(tokens): + pile = Pile() + for token in tokens: + if token in ["+", "-", "*", "/"]: + exp = Expression(token, pile.depiler(), pile.depiler()) + pile.empiler(exp) + else: + pile.empiler(Expression(token)) + return pile.depiler() + +if __name__ == "__main__": + print(shutting_yard(tokenize("2+44(4+21)"))) + #print(npi2tree(tokenize("6 4 3 + *"))) \ No newline at end of file