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