2013-08-09 09:35:14 +00:00
#!/usr/bin/env python
# encoding: utf-8
class Expression ( object ) :
""" A calculus expression. Today it can andle only expression with numbers later it will be able to manipulate unknown """
2013-08-09 11:08:24 +00:00
priority = { " * " : 3 , " / " : 3 , " + " : 2 , " - " : 2 , " ( " : 1 }
2013-08-09 09:35:14 +00:00
def __init__ ( self , exp ) :
""" Initiate the expression.
: param exp : the expression . It can be a string or a list of tokens . It can be infix or postfix expression
"""
2013-08-09 10:03:32 +00:00
self . _tokens = { }
self . _strings = { }
if type ( exp ) == list :
fix = self . get_fix ( exp )
self . _tokens [ fix ] = exp
elif type ( exp ) == str :
tokens = self . parseExp ( exp )
fix = self . get_fix ( tokens )
self . _tokens [ fix ] = tokens
self . _strings [ fix ] = exp
else :
raise ValueError ( " The expression needs to be a string or a list of token " )
2013-08-09 09:35:14 +00:00
# ---------------------
# String parsing
# @classmethod ????
def parseExp ( self , exp ) :
""" Parse the expression, ie tranform a string into a list of tokens
2013-08-09 10:03:32 +00:00
: param exp : The expression ( a string )
2013-08-09 09:35:14 +00:00
: returns : list of token
"""
2013-08-09 10:03:32 +00:00
return exp . split ( " " )
2013-08-09 09:35:14 +00:00
# ---------------------
# "fix" recognition
2013-08-09 10:03:32 +00:00
def get_fix ( self , tokens ) :
2013-08-09 09:35:14 +00:00
""" Give the " fix " of an expression
infix - > A + B
prefix - > + A B
postfix - > A B +
2013-08-09 10:03:32 +00:00
: param exp : the expression ( list of token )
2013-08-09 09:35:14 +00:00
: returns : the " fix " ( infix , postfix , prefix )
"""
2013-08-09 10:03:32 +00:00
if tokens [ 0 ] in " +-*/ " :
return " prefix "
elif token [ 0 ] not in " +-*/ " ans token [ 1 ] not in " +-*/ " :
return " postfix "
else :
return " infix "
# ----------------------
# Expressions - tokens getters
def tokens ( self , fix = " infix " ) :
""" Get the list of tokens with the wanted fix
: param fix : the fix wanted ( infix default )
: returns : list of tokens
"""
2013-08-09 11:08:24 +00:00
# Si ce fix n'a pas encore été enregistré
2013-08-09 10:03:32 +00:00
if fix not in self . _tokens :
2013-08-09 11:08:24 +00:00
# Il peut venir de la version string
if fix in self . _string :
self . _tokens [ fix ] = self . parseExp ( self . _string [ fix ] )
# Sinon il faut le calculer à partir d'une autre forme
else :
fix_transfo = " to " + fix . capitalize ( )
getattr ( self , fix_transfo ) ( )
2013-08-09 10:03:32 +00:00
return self . _tokens [ fix ]
##### On en est là,il faudra faire attention à bien vérifier ce que les "to..." enregistre (string ou tokens)
def string ( self , fix = " infix " ) :
""" Get the string with the wanted fix
: param fix : the fix wanted ( infix default )
: returns : the string representing the expression
"""
2013-08-09 11:08:24 +00:00
# Si ce fix n'a pas encore été enregistré
if fix not in self . _string :
# Il peut venir de la version string
if fix in self . _tokens :
self . _string [ fix ] = self . parseExp ( self . _string [ fix ] )
# Sinon il faut le calculer à partir d'une autre forme
else :
fix_transfo = " to " + fix . capitalize ( )
getattr ( self , fix_transfo ) ( )
return self . _string [ fix ]
2013-08-09 09:35:14 +00:00
# ----------------------
# "fix" tranformations
def toPostfix ( self ) :
2013-08-09 11:08:24 +00:00
""" Transorm the expression into postfix form using the infix form """
2013-08-09 09:35:14 +00:00
pass
def toInfix ( self ) :
2013-08-09 11:08:24 +00:00
""" Tranform the expression into infix form using postfix form """
2013-08-09 09:35:14 +00:00
pass
# ---------------------
# Tools for placing parenthesis in infix notation
def needPar ( operande , operator , posi = " after " ) :
""" Says whether or not the operande needs parenthesis
: param operande : the operande
: param operator : the operator
: param posi : " after " ( default ) if the operande will be after the operator , " before " othewise
: returns : bollean
"""
2013-08-09 11:08:24 +00:00
if isNumber ( operande ) and " - " in operande :
return 1
elif not isNumber ( operande ) :
# Si c'est une grande expression ou un chiffre négatif
stand_alone = get_main_op ( operande )
# Si la priorité de l'operande est plus faible que celle de l'opérateur
minor_priority = self . priority [ get_main_op ( operande ) ] < self . priority [ operator ]
# Si l'opérateur est -/ pour after ou juste / pour before
special = ( operator in " -/ " and posi == " after " ) or ( operator in " / " and posi == " before " )
return stand_alone and ( minor_priority or special )
else :
return 0
2013-08-09 09:35:14 +00:00
2013-08-09 11:08:24 +00:00
# J'aime pas bien cette endroit faudrait que ce soit une méthode qui s'applique uniquement à l'expression en question (self) pas à n'importe quel string, ça serait plus propre.
2013-08-09 09:35:14 +00:00
def get_main_op ( exp ) :
""" Gives the main operation of the expression
: param exp : the expression
: returns : the main operation ( + , - , * or / ) or 0 if the expression is only one element
"""
2013-08-09 11:08:24 +00:00
parStack = Stack ( )
tokenList = exp . split ( " " )
if len ( tokenList ) == 1 :
# Si l'expression n'est qu'un élément
return 0
main_op = [ ]
for token in tokenList :
if token == " ( " :
parStack . push ( token )
elif token == " ) " :
parStack . pop ( )
elif token in " +-*/ " and parStack . isEmpty ( ) :
main_op . append ( token )
return min ( main_op , key = lambda s : priority [ s ] )
2013-08-09 09:35:14 +00:00
# ---------------------
# Computing the expression
def compute ( self ) :
""" Recursive method for computing as a student the expression
: returns : list of steps needed to reach the result
"""
pass
def doMath ( op , op1 , op2 ) :
""" Compute " op1 op op2 "
: param op : operator
: param op1 : first operande
: param op2 : second operande
: returns : string representing the result
"""
return str ( eval ( op1 + op + op2 ) )
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del