blob: a15742c2ed01f0ffaad137cf05d8c3e5c17d9530 [file] [log] [blame]
Brian Silverman84b22232019-01-25 20:29:29 -08001# pycrc -- parameterisable CRC calculation utility and C source code generator
2#
3# Copyright (c) 2017 Thomas Pircher <tehpeh-web@tty1.net>
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to
7# deal in the Software without restriction, including without limitation the
8# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9# sell copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21# IN THE SOFTWARE.
22
23
24"""
25This modules simplifies an expression.
26
27 import pycrc.expr as exp
28
29 my_expr = exp.Xor('var', exp.Parenthesis(exp.And('0x700', 4)))
30 print('"{}" -> "{}"'.format(my_expr, my_expr.simplify()))
31"""
32
33
34def _classify(val):
35 """
36 Creates a Terminal object if the parameter is a string or an integer.
37 """
38 if type(val) is int:
39 return Terminal(val)
40 if type(val) is str:
41 if val.isdigit():
42 return Terminal(int(val), val)
43 if val[:2].lower() == '0x':
44 return Terminal(int(val, 16), val)
45 return Terminal(val)
46 return val
47
48
49class Expression(object):
50 """
51 Base class for all expressions.
52 """
53 def is_int(self, val = None):
54 return False
55
56
57class Terminal(Expression):
58 """
59 A terminal object.
60 """
61 def __init__(self, val, pretty = None):
62 """
63 Construct a Terminal.
64 The val variable is usually a string or an integer. Integers may also
65 be passed as strings. The pretty-printer will use the string when
66 formatting the expression.
67 """
68 self.val = val
69 self.pretty = pretty
70
71 def __str__(self):
72 """
73 Return the string expression of this object.
74 """
75 if self.pretty is None:
76 return str(self.val)
77 return self.pretty
78
79 def simplify(self):
80 """
81 Return a simplified version of this sub-expression.
82 """
83 return self
84
85 def is_int(self, val = None):
86 """
87 Return True if the value of this Terminal is an integer.
88 """
89 if type(self.val) is int:
90 return val is None or self.val == val
91 return False
92
93
94class FunctionCall(Expression):
95 """
96 Represent a function call
97 """
98 def __init__(self, name, args):
99 """
100 Construct a function call object.
101 """
102 self.name = _classify(name)
103 self.args = [_classify(arg) for arg in args]
104
105 def __str__(self):
106 """
107 Return the string expression of this object.
108 """
109 return str(self.name) + '(' + ', '.join([str(arg) for arg in self.args]) + ')'
110
111 def simplify(self):
112 """
113 Return a simplified version of this sub-expression.
114 """
115 args = [arg.simplify() for arg in self.args]
116 return FunctionCall(self.name, args)
117
118
119class Parenthesis(Expression):
120 """
121 Represent a pair of round brackets.
122 """
123 def __init__(self, val):
124 """
125 Construct a parenthesis object.
126 """
127 self.val = _classify(val)
128
129 def simplify(self):
130 """
131 Return a simplified version of this sub-expression.
132 """
133 val = self.val.simplify()
134 if type(val) is Terminal:
135 return val
136 return Parenthesis(val)
137
138 def __str__(self):
139 """
140 Return the string expression of this object.
141 """
142 return '(' + str(self.val) + ')'
143
144
145class Add(Expression):
146 """
147 Represent an addition of operands.
148 """
149 def __init__(self, lhs, rhs):
150 """
151 Construct an addition object.
152 """
153 self.lhs = _classify(lhs)
154 self.rhs = _classify(rhs)
155
156 def simplify(self):
157 """
158 Return a simplified version of this sub-expression.
159 """
160 lhs = self.lhs.simplify()
161 rhs = self.rhs.simplify()
162 if lhs.is_int() and rhs.is_int():
163 return Terminal(lhs.val + rhs.val)
164 if lhs.is_int(0):
165 return rhs
166 if rhs.is_int(0):
167 return lhs
168 return Add(lhs, rhs)
169
170 def __str__(self):
171 """
172 Return the string expression of this object.
173 """
174 return str(self.lhs) + ' + ' + str(self.rhs)
175
176
177class Sub(Expression):
178 """
179 Represent a subtraction of operands.
180 """
181 def __init__(self, lhs, rhs):
182 """
183 Construct subtraction object.
184 """
185 self.lhs = _classify(lhs)
186 self.rhs = _classify(rhs)
187
188 def simplify(self):
189 """
190 Return a simplified version of this sub-expression.
191 """
192 lhs = self.lhs.simplify()
193 rhs = self.rhs.simplify()
194 if lhs.is_int() and rhs.is_int():
195 return Terminal(lhs.val - rhs.val)
196 if lhs.is_int(0):
197 return rhs
198 if rhs.is_int(0):
199 return lhs
200 return Sub(lhs, rhs)
201
202 def __str__(self):
203 """
204 Return the string expression of this object.
205 """
206 return str(self.lhs) + ' - ' + str(self.rhs)
207
208
209class Mul(Expression):
210 """
211 Represent the multiplication of operands.
212 """
213 def __init__(self, lhs, rhs):
214 """
215 Construct a multiplication object.
216 """
217 self.lhs = _classify(lhs)
218 self.rhs = _classify(rhs)
219
220 def simplify(self):
221 """
222 Return a simplified version of this sub-expression.
223 """
224 lhs = self.lhs.simplify()
225 rhs = self.rhs.simplify()
226 if lhs.is_int() and rhs.is_int():
227 return Terminal(lhs.val * rhs.val)
228 if lhs.is_int(0) or rhs.is_int(0):
229 return Terminal(0)
230 if lhs.is_int(1):
231 return rhs
232 if rhs.is_int(1):
233 return lhs
234 return Mul(lhs, rhs)
235
236 def __str__(self):
237 """
238 Return the string expression of this object.
239 """
240 return str(self.lhs) + ' * ' + str(self.rhs)
241
242
243class Shl(Expression):
244 """
245 Shift left operation.
246 """
247 def __init__(self, lhs, rhs):
248 """
249 Construct a shift left object.
250 """
251 self.lhs = _classify(lhs)
252 self.rhs = _classify(rhs)
253
254 def simplify(self):
255 """
256 Return a simplified version of this sub-expression.
257 """
258 lhs = self.lhs.simplify()
259 rhs = self.rhs.simplify()
260 if lhs.is_int() and rhs.is_int():
261 return Terminal(lhs.val << rhs.val)
262 if lhs.is_int(0):
263 return Terminal(0)
264 if rhs.is_int(0):
265 return lhs
266 return Shl(lhs, rhs)
267
268 def __str__(self):
269 """
270 Return the string expression of this object.
271 """
272 return str(self.lhs) + ' << ' + str(self.rhs)
273
274
275class Shr(Expression):
276 """
277 Shift right operation.
278 """
279 def __init__(self, lhs, rhs):
280 """
281 Construct a shift right object.
282 """
283 self.lhs = _classify(lhs)
284 self.rhs = _classify(rhs)
285
286 def simplify(self):
287 """
288 Return a simplified version of this sub-expression.
289 """
290 lhs = self.lhs.simplify()
291 rhs = self.rhs.simplify()
292 if lhs.is_int() and rhs.is_int():
293 return Terminal(lhs.val >> rhs.val)
294 if lhs.is_int(0):
295 return Terminal(0)
296 if rhs.is_int(0):
297 return lhs
298 return Shr(lhs, rhs)
299
300 def __str__(self):
301 """
302 Return the string expression of this object.
303 """
304 return str(self.lhs) + ' >> ' + str(self.rhs)
305
306
307class Or(Expression):
308 """
309 Logical or operation.
310 """
311 def __init__(self, lhs, rhs):
312 """
313 Construct a logical and object.
314 """
315 self.lhs = _classify(lhs)
316 self.rhs = _classify(rhs)
317
318 def simplify(self):
319 """
320 Return a simplified version of this sub-expression.
321 """
322 lhs = self.lhs.simplify()
323 rhs = self.rhs.simplify()
324 if lhs.is_int() and rhs.is_int():
325 return Terminal(lhs.val | rhs.val)
326 if lhs.is_int(0):
327 return rhs
328 if rhs.is_int(0):
329 return lhs
330 return Or(lhs, rhs)
331
332 def __str__(self):
333 """
334 Return the string expression of this object.
335 """
336 return str(self.lhs) + ' | ' + str(self.rhs)
337
338
339class And(Expression):
340 """
341 Logical and operation.
342 """
343 def __init__(self, lhs, rhs):
344 """
345 Construct a logical and object.
346 """
347 self.lhs = _classify(lhs)
348 self.rhs = _classify(rhs)
349
350 def simplify(self):
351 """
352 Return a simplified version of this sub-expression.
353 """
354 lhs = self.lhs.simplify()
355 rhs = self.rhs.simplify()
356 if lhs.is_int() and rhs.is_int():
357 return Terminal(lhs.val & rhs.val)
358 if lhs.is_int(0) or rhs.is_int(0):
359 return Terminal(0)
360 return And(lhs, rhs)
361
362 def __str__(self):
363 """
364 Return the string expression of this object.
365 """
366 return str(self.lhs) + ' & ' + str(self.rhs)
367
368
369class Xor(Expression):
370 """
371 Logical xor operation.
372 """
373 def __init__(self, lhs, rhs):
374 """
375 Construct a logical xor object.
376 """
377 self.lhs = _classify(lhs)
378 self.rhs = _classify(rhs)
379
380 def simplify(self):
381 """
382 Return a simplified version of this sub-expression.
383 """
384 lhs = self.lhs.simplify()
385 rhs = self.rhs.simplify()
386 if lhs.is_int() and rhs.is_int():
387 return Terminal(lhs.val ^ rhs.val)
388 if lhs.is_int(0):
389 return rhs
390 if rhs.is_int(0):
391 return lhs
392 return Xor(lhs, rhs)
393
394 def __str__(self):
395 """
396 Return the string expression of this object.
397 """
398 return str(self.lhs) + ' ^ ' + str(self.rhs)