from Pile import Pile_chaine as Pile from math import * from infixe import estUnNombre class Expression: def __init__(self, racine, gauche, droit): """initialisation d'un objet 'Expression'""" self.racine = racine self.gauche = gauche self.droit = droit def evalue(self): """renvoie la valeur de l'expression si 1 seul argument alors on prend le fils gauche""" #fonctions if self.racine == "sin": return sin(self.gauche.evalue()) if self.racine == "cos": return cos(self.gauche.evalue()) if self.racine == "tan": return tan(self.gauche.evalue()) if self.racine == "opp": return - self.gauche.evalue() if self.racine == "sqrt": return sqrt(self.gauche.evalue()) #operateurs if self.racine == "+": return self.gauche.evalue() + self.droit.evalue() if self.racine == "-": return self.gauche.evalue() - self.droit.evalue() if self.racine == "*": return self.gauche.evalue() * self.droit.evalue() if self.racine == "/": return self.gauche.evalue() / self.droit.evalue() if self.racine == "^": return self.gauche.evalue() ** self.droit.evalue() if "." in self.racine: return float(self.racine) return int(self.racine) def __str__(self): """affiche l'expression""" priorite = {"opp":1, "!":1, "^":2, "sin":3, "cos":3, "tan":3, "sqrt":3, "*":4, "/":4, "+":5, "-":5 } associativite = {"opp":"droit", "^":"droit", "*":"gauche", "/":"gauche", "+":"gauche", "-":"gauche" } pas_commutatif = ["^","/","-"] if self.racine in ["opp","!", "^", "*", "/", "+", "-"]: gauche = str(self.gauche) #definitivement à améliorer if self.droit == None: # racine est "-" (unaire) ou "opp" priorite_racine = priorite[self.racine] priorite_gauche = priorite.get(self.gauche.racine, -1) #test print(self.gauche.racine) #test if self.gauche.racine[0] == "-" or priorite_racine <= priorite_gauche: gauche = parentheses(gauche) return "-" + gauche droit = str(self.droit) priorite_racine = priorite[self.racine] priorite_gauche = priorite.get(self.gauche.racine, -1) priorite_droit = priorite.get(self.droit.racine, -1) if self.gauche.racine == "opp" or self.gauche.racine != "-" and self.gauche.racine[0] == "-": gauche = parentheses(gauche) if self.droit.racine == "opp" or self.droit.racine != "-" and self.droit.racine[0] == "-": droit = parentheses(droit) if priorite_racine < priorite_gauche: gauche = parentheses(gauche) if priorite_racine < priorite_droit: droit = parentheses(droit) if self.racine in pas_commutatif: if priorite_racine == priorite_droit and associativite[self.racine] == "gauche": droit = parentheses(droit) if priorite_racine == priorite_gauche and associativite[self.racine] == "droit": gauche = parentheses(gauche) return gauche + self.racine + droit if self.racine in ["sin","cos","tan","sqrt"]: return self.racine + "(" + str(self.gauche) + ")" return str(self.racine) def parentheses(txt): """ajoute des parentheses à txt""" return "(" + txt + ")" def npi2tree_original(liste_en_npi): """conversion d'une liste en NPI en un arbre""" pile_expr = Pile() for element in liste_en_npi: if element in ["+", "*","-","/", "^"]: fils_droit = pile_expr.depiler() fils_gauche = pile_expr.depiler() pile_expr.empiler(Expression(element, fils_gauche, fils_droit)) elif element in ["sin","cos","tan", "opp"]: pile_expr.empiler(Expression(element, pile_expr.depiler(),None)) else: pile_expr.empiler(Expression(element, None, None)) return pile_expr.sommet() #renommer la fonction !... def npi2tree(liste, etat_affichage): """conversion d'une liste en NPI ou NP en un arbre""" pile_expr = Pile() for element in liste: if element in ["+","-", "*","/", "^"]: fils_gauche = pile_expr.depiler() fils_droit = pile_expr.depiler() if etat_affichage == "post-expr" or etat_affichage == "inf": fils_gauche, fils_droit = fils_droit, fils_gauche pile_expr.empiler(Expression(element, fils_gauche, fils_droit)) elif element in ["sin","cos","tan", "opp", "sqrt"]: pile_expr.empiler(Expression(element, pile_expr.depiler(), None)) elif estUnNombre(element): pile_expr.empiler(Expression(element, None, None)) else: #à compléter raise ValueError("Fonction inconnue","n'est pas une fonction connue, ou il manque des espaces.", element) print("Taille de pile_expr à la fin de la boucle : " , pile_expr.taille()) if pile_expr.taille() == 2: raise SyntaxError(("Il manque un opérateur. L'étoile ( « ★ » ) indique la position de l'opérateur manquant dans l'expression.", pile_expr)) if pile_expr.taille() > 2: raise SyntaxError(("Il manque " + str(pile_expr.taille() - 1) + " opérateurs. L'étoile ( « ★ » ) indique la position des opérateurs manquants dans l'expression.", pile_expr)) return pile_expr.sommet() def fonctionsAvecArgument(lst_expr): #la clarifier un peu, peut-être ? """vérifie que les fonctions aient des arguments, mêmes incorrects ex : `sin ) 2 +` est OK.Plus tard l'expression sera vérifiée par d'autres fonctions qui verront les erreurs (parenthèses..) Le but est d'éviter que les expression comme `2 sin` soit vues justes par shunting-yard""" fonctions = ["sin","cos","tan", "sqrt"] lst_expr_stripped = list(filter(lambda x: x != "+" and x != "-", lst_expr)) if lst_expr_stripped[-1] in fonctions: return False #si à droite, pas un nombre ou une parenthèse fermante fx_a_gauche = False for terme in lst_expr_stripped: if fx_a_gauche == True: if terme in [")", "*", "/"]: return False if terme in fonctions: fx_a_gauche = True #return not in fonctions def inserer_dans_liste(element, lst, indice): """insère l'item `element` dans la liste `lst` à l'indice `indice`""" return