blob: a15742c2ed01f0ffaad137cf05d8c3e5c17d9530 [file] [log] [blame]
# pycrc -- parameterisable CRC calculation utility and C source code generator
#
# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
"""
This modules simplifies an expression.
import pycrc.expr as exp
my_expr = exp.Xor('var', exp.Parenthesis(exp.And('0x700', 4)))
print('"{}" -> "{}"'.format(my_expr, my_expr.simplify()))
"""
def _classify(val):
"""
Creates a Terminal object if the parameter is a string or an integer.
"""
if type(val) is int:
return Terminal(val)
if type(val) is str:
if val.isdigit():
return Terminal(int(val), val)
if val[:2].lower() == '0x':
return Terminal(int(val, 16), val)
return Terminal(val)
return val
class Expression(object):
"""
Base class for all expressions.
"""
def is_int(self, val = None):
return False
class Terminal(Expression):
"""
A terminal object.
"""
def __init__(self, val, pretty = None):
"""
Construct a Terminal.
The val variable is usually a string or an integer. Integers may also
be passed as strings. The pretty-printer will use the string when
formatting the expression.
"""
self.val = val
self.pretty = pretty
def __str__(self):
"""
Return the string expression of this object.
"""
if self.pretty is None:
return str(self.val)
return self.pretty
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
return self
def is_int(self, val = None):
"""
Return True if the value of this Terminal is an integer.
"""
if type(self.val) is int:
return val is None or self.val == val
return False
class FunctionCall(Expression):
"""
Represent a function call
"""
def __init__(self, name, args):
"""
Construct a function call object.
"""
self.name = _classify(name)
self.args = [_classify(arg) for arg in args]
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.name) + '(' + ', '.join([str(arg) for arg in self.args]) + ')'
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
args = [arg.simplify() for arg in self.args]
return FunctionCall(self.name, args)
class Parenthesis(Expression):
"""
Represent a pair of round brackets.
"""
def __init__(self, val):
"""
Construct a parenthesis object.
"""
self.val = _classify(val)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
val = self.val.simplify()
if type(val) is Terminal:
return val
return Parenthesis(val)
def __str__(self):
"""
Return the string expression of this object.
"""
return '(' + str(self.val) + ')'
class Add(Expression):
"""
Represent an addition of operands.
"""
def __init__(self, lhs, rhs):
"""
Construct an addition object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val + rhs.val)
if lhs.is_int(0):
return rhs
if rhs.is_int(0):
return lhs
return Add(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' + ' + str(self.rhs)
class Sub(Expression):
"""
Represent a subtraction of operands.
"""
def __init__(self, lhs, rhs):
"""
Construct subtraction object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val - rhs.val)
if lhs.is_int(0):
return rhs
if rhs.is_int(0):
return lhs
return Sub(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' - ' + str(self.rhs)
class Mul(Expression):
"""
Represent the multiplication of operands.
"""
def __init__(self, lhs, rhs):
"""
Construct a multiplication object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val * rhs.val)
if lhs.is_int(0) or rhs.is_int(0):
return Terminal(0)
if lhs.is_int(1):
return rhs
if rhs.is_int(1):
return lhs
return Mul(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' * ' + str(self.rhs)
class Shl(Expression):
"""
Shift left operation.
"""
def __init__(self, lhs, rhs):
"""
Construct a shift left object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val << rhs.val)
if lhs.is_int(0):
return Terminal(0)
if rhs.is_int(0):
return lhs
return Shl(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' << ' + str(self.rhs)
class Shr(Expression):
"""
Shift right operation.
"""
def __init__(self, lhs, rhs):
"""
Construct a shift right object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val >> rhs.val)
if lhs.is_int(0):
return Terminal(0)
if rhs.is_int(0):
return lhs
return Shr(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' >> ' + str(self.rhs)
class Or(Expression):
"""
Logical or operation.
"""
def __init__(self, lhs, rhs):
"""
Construct a logical and object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val | rhs.val)
if lhs.is_int(0):
return rhs
if rhs.is_int(0):
return lhs
return Or(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' | ' + str(self.rhs)
class And(Expression):
"""
Logical and operation.
"""
def __init__(self, lhs, rhs):
"""
Construct a logical and object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val & rhs.val)
if lhs.is_int(0) or rhs.is_int(0):
return Terminal(0)
return And(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' & ' + str(self.rhs)
class Xor(Expression):
"""
Logical xor operation.
"""
def __init__(self, lhs, rhs):
"""
Construct a logical xor object.
"""
self.lhs = _classify(lhs)
self.rhs = _classify(rhs)
def simplify(self):
"""
Return a simplified version of this sub-expression.
"""
lhs = self.lhs.simplify()
rhs = self.rhs.simplify()
if lhs.is_int() and rhs.is_int():
return Terminal(lhs.val ^ rhs.val)
if lhs.is_int(0):
return rhs
if rhs.is_int(0):
return lhs
return Xor(lhs, rhs)
def __str__(self):
"""
Return the string expression of this object.
"""
return str(self.lhs) + ' ^ ' + str(self.rhs)