231 self.preferred_base = None |
231 self.preferred_base = None |
232 |
232 |
233 def set_preferred_base (self, x): |
233 def set_preferred_base (self, x): |
234 self.preferred_base = x |
234 self.preferred_base = x |
235 |
235 |
236 def trim_spaces (self, expr): |
236 def trim_spaces (self): |
237 return re.sub ('\s+', '', expr.strip()) |
237 self.expr = re.sub ('\s+', '', self.expr.strip()) |
238 |
238 |
239 def parse_attributes (self, expr): |
239 def parse_attributes (self): |
240 if expr[0] != '<': |
240 if self.expr[0] != '<': |
241 return expr |
241 return |
242 |
242 |
243 i = 1 |
243 i = 1 |
244 while expr[i] != '>': |
244 while self.expr[i] != '>': |
245 if expr[i] == '|': |
245 if self.expr[i] == '|': |
246 i += 1 |
246 i += 1 |
247 |
247 |
248 for name in AttributeNames: |
248 for name in AttributeNames: |
249 if expr[i:i + len(name)] == name: |
249 if self.expr[i:i + len(name)] == name: |
250 Attributes[name] (self) |
250 Attributes[name] (self) |
251 i += len(name) |
251 i += len(name) |
252 |
252 |
253 if expr[i] == '>': |
253 if self.expr[i] == '>': |
254 break |
254 break |
255 |
255 |
256 if expr[i] != '|': |
256 if self.expr[i] != '|': |
257 raise ValueError ('malformed attributes') |
257 raise ValueError ('malformed attributes') |
258 break |
258 break |
259 else: |
259 else: |
260 raise ValueError ('bad attributes: %s' % expr[i:]) |
260 raise ValueError ('bad attributes: %s' % self.expr[i:]) |
261 |
261 |
262 return expr[i + 1:] |
262 return self.expr[i + 1:] |
263 |
263 |
264 def parse_number (self, expr): |
264 def parse_number (self): |
265 """Tries to parse a number from the expression. Returns (value, length) on success.""" |
265 """Tries to parse a number from the expression. Returns value on success.""" |
266 i = 0 |
266 i = 0 |
267 value = None |
267 value = None |
268 base = 10 |
268 base = 10 |
269 |
269 |
270 # Possibly it's hexadecimal |
270 # Possibly it's hexadecimal |
271 if expr[0:2].lower() == '0x': |
271 if self.expr[0:2].lower() == '0x': |
272 base = 0x10 |
272 base = 0x10 |
273 digits = string.hexdigits |
273 digits = string.hexdigits |
274 digitname = 'hexit' |
274 digitname = 'hexit' |
275 i = 2 |
275 i = 2 |
276 elif expr[0:2].lower() == '0b': |
276 elif self.expr[0:2].lower() == '0b': |
277 base = 0b10 |
277 base = 0b10 |
278 digits = ['0', '1'] |
278 digits = ['0', '1'] |
279 digitname = 'bit' |
279 digitname = 'bit' |
280 i = 2 |
280 i = 2 |
281 |
281 |
282 if base != 10: |
282 if base != 10: |
283 if not self.preferred_base: |
283 if not self.preferred_base: |
284 self.preferred_base = base |
284 self.preferred_base = base |
285 |
285 |
286 # Skip leading zeroes |
286 # Skip leading zeroes |
287 while i < len (expr) and expr[i] == '0': |
287 while i < len (self.expr) and self.expr[i] == '0': |
288 i += 1 |
288 i += 1 |
289 |
289 |
290 startingIndex = i |
290 startingIndex = i |
291 while i < len (expr) and expr[i] in digits: |
291 while i < len (self.expr) and self.expr[i] in digits: |
292 i += 1 |
292 i += 1 |
293 |
293 |
294 if i < len(expr) and expr[i] == '.': |
294 if i < len(self.expr) and self.expr[i] == '.': |
295 raise ValueError ('non-decimal floating point numbers are not supported') |
295 raise ValueError ('non-decimal floating point numbers are not supported') |
296 |
296 |
297 if i == startingIndex: |
297 if i == startingIndex: |
298 if i < len (expr): |
298 if i < len (self.expr): |
299 raise ValueError ('not a valid %s "%s" in %s' % (digitname, expr[i], expr[0:i+1])) |
299 raise ValueError ('not a valid %s "%s" in %s' % (digitname, self.expr[i], self.expr[0:i+1])) |
300 else: |
300 else: |
301 raise ValueError ('end of expression encountered while parsing ' |
301 raise ValueError ('end of expression encountered while parsing ' |
302 'base-%d literal' % base) |
302 'base-%d literal' % base) |
303 |
303 |
304 return (complex (int (expr[startingIndex:i], base), 0), i) |
304 return (complex (int (self.expr[startingIndex:i], base), 0), i) |
305 |
305 |
306 if expr[0] == 'i': |
306 if self.expr[0] == 'i': |
307 # Special case, we just have 'i' -- need special handling here because otherwise this would |
307 # Special case, we just have 'i' -- need special handling here because otherwise this would |
308 # call float('') in the complex number routine, which throws an error. |
308 # call float('') in the complex number routine, which throws an error. |
309 # TODO: maybe 'i' can be a symbol instead? |
309 # TODO: maybe 'i' can be a symbol instead? |
310 return (1j, 1) |
310 self.expr = self.expr[1:] |
|
311 return 1j |
311 |
312 |
312 # Try parse increasingly long substrings until we are unable to create a float or complex number |
313 # Try parse increasingly long substrings until we are unable to create a float or complex number |
313 # from it. |
314 # from it. |
314 try: |
315 try: |
315 while i < len (expr): |
316 while i < len (self.expr): |
316 if expr[i] == 'i': |
317 if self.expr[i] == 'i': |
317 value = complex (0.0, float (expr[:i])) |
318 value = complex (0.0, float (self.expr[:i])) |
318 else: |
319 else: |
319 value = complex (float (expr [:i + 1]), 0.0) |
320 value = complex (float (self.expr [:i + 1]), 0.0) |
320 i += 1 |
321 i += 1 |
321 |
322 |
322 return (value, i) |
323 self.expr = self.expr[i:] |
|
324 return value |
323 except ValueError: |
325 except ValueError: |
324 if i != 0: |
326 if i != 0: |
325 # Got a number (the error happened when we tried to parse past the number) |
327 # Got a number (the error happened when we tried to parse past the number) |
326 return (value, i) |
328 self.expr = self.expr[i:] |
|
329 return value |
327 else: |
330 else: |
328 # The error happened on the first character. So this is not a number. |
331 # The error happened on the first character. So this is not a number. |
329 return None |
332 return None |
330 |
333 |
331 def parse_symbol (self, expr): |
334 def parse_symbol (self): |
332 for sym in Symbols: |
335 for sym in Symbols: |
333 if expr[:len (sym)] == sym: |
336 if self.expr[:len (sym)] == sym: |
|
337 self.expr = self.expr[len (sym):] |
334 return sym |
338 return sym |
335 |
339 |
336 return None |
340 return None |
337 |
341 |
338 def tokenize (self, expr): |
342 def tokenize (self): |
339 i=0 |
343 self.tokens = [] |
340 tokens = [] |
344 |
341 |
345 while self.expr: |
342 while i < len(expr): |
346 sym = self.parse_symbol() |
343 sym = self.parse_symbol (expr[i:]) |
|
344 |
347 |
345 if sym: |
348 if sym: |
346 symtype = SymbolTypes[sym] |
349 symtype = SymbolTypes[sym] |
347 if symtype == SymbolType.CONSTANT: |
350 if symtype == SymbolType.CONSTANT: |
348 tokens.append (Constants[sym]) |
351 self.tokens.append (Constants[sym]) |
349 else: |
352 else: |
350 tokens.append (sym) |
353 self.tokens.append (sym) |
351 |
|
352 i += len(sym) |
|
353 continue |
354 continue |
354 |
355 |
355 result = self.parse_number (expr[i:]) |
356 result = self.parse_number() |
356 if result: |
357 if result: |
357 num, length = result |
358 self.tokens.append (result) |
358 tokens.append (num) |
|
359 i += length |
|
360 continue |
359 continue |
361 |
360 |
362 raise ValueError ("""bad expression, couldn't parse: %s""" % expr[i:]) |
361 raise ValueError ("""bad expression, couldn't parse: %s""" % self.expr[i:]) |
363 |
362 |
364 return tokens |
363 def process_parens (self): |
365 |
364 """Processes parentheses of self.tokens into sublists in-place. |
366 def process_parens (self, expr): |
|
367 """Processes parentheses of expr into sublists in-place. |
|
368 [1.0, '*', '(', 3.5, '+', 1j, ')'] |
365 [1.0, '*', '(', 3.5, '+', 1j, ')'] |
369 -> [1.0, '*', [3.5, '+', 1j]]""" |
366 -> [1.0, '*', [3.5, '+', 1j]]""" |
370 if '(' not in expr and ')' not in expr: |
367 if '(' not in self.tokens and ')' not in self.tokens: |
371 return |
368 return |
372 |
369 |
373 try: |
370 try: |
374 parenStart = rindex (expr, '(') |
371 parenStart = rindex (self.tokens, '(') |
375 parenEnd = expr.index (')', parenStart) |
372 parenEnd = self.tokens.index (')', parenStart) |
376 except ValueError: |
373 except ValueError: |
377 raise ValueError ("""mismatched parentheses in expression: %s""" % expr) |
374 raise ValueError ("""mismatched parentheses in expression: %s""" % self.tokens) |
378 |
375 |
379 subexpr = expr[parenStart + 1:parenEnd] |
376 subexpr = self.tokens[parenStart + 1:parenEnd] |
380 del expr[parenStart + 1:parenEnd + 1] |
377 del self.tokens[parenStart + 1:parenEnd + 1] |
381 expr[parenStart] = subexpr |
378 self.tokens[parenStart] = subexpr |
382 self.process_parens (expr) |
379 self.process_parens (self.tokens) |
383 |
380 |
384 def process_functions (self, expr): |
381 def process_functions (self): |
385 """Processes functions in-place""" |
382 """Processes functions in-place""" |
386 i = 0 |
383 i = 0 |
387 while i < len (expr): |
384 while i < len (self.tokens): |
388 if type (expr[i]) is list: |
385 if type (self.tokens[i]) is list: |
389 self.process_functions (expr[i]) |
386 self.process_functions (self.tokens[i]) |
390 |
387 |
391 if (type(expr[i]) is not str) or (expr[i] not in Functions): |
388 if (type(self.tokens[i]) is not str) or (self.tokens[i] not in Functions): |
392 i += 1 |
389 i += 1 |
393 continue |
390 continue |
394 |
391 |
395 # Ensure that arguments follow |
392 # Ensure that arguments follow |
396 if (i + 1 >= len (expr)) or (type (expr[i + 1]) is not list): |
393 if (i + 1 >= len (self.tokens)) or (type (self.tokens[i + 1]) is not list): |
397 raise ValueError ("""function %s used without arguments""" % expr[i]) |
394 raise ValueError ("""function %s used without arguments""" % self.tokens[i]) |
398 |
395 |
399 args = expr[i + 1] |
396 args = self.tokens[i + 1] |
400 del expr[i + 1] |
397 del self.tokens[i + 1] |
401 expr[i] = FunctionCall (expr[i], args) |
398 self.tokens[i] = FunctionCall (self.tokens[i], args) |
402 i += 1 |
399 i += 1 |
403 |
400 |
404 def is_operand (self, x): |
401 def is_operand (self, x): |
405 # Operands can be either lists (which also mean parens, thus can be single-expressions) |
402 # Operands can be either lists (which also mean parens, thus can be single-expressions) |
406 # or complex numbers |
403 # or complex numbers |
420 if op.symbol == sym: |
417 if op.symbol == sym: |
421 return op |
418 return op |
422 |
419 |
423 raise ValueError ('''unknown operator %s!''' % sym) |
420 raise ValueError ('''unknown operator %s!''' % sym) |
424 |
421 |
425 def process_operators (self, expr): |
422 def process_operators (self): |
426 """Processes operators""" |
423 """Processes operators""" |
427 i = 0 |
424 i = 0 |
428 |
425 |
429 # Find all operators in this expression |
426 # Find all operators in this expression |
430 while i < len (expr): |
427 while i < len (self.tokens): |
431 if type (expr[i]) is list: |
428 if type (self.tokens[i]) is list: |
432 self.process_functions (expr[i]) |
429 self.process_functions (self.tokens[i]) |
433 self.process_operators (expr[i]) |
430 self.process_operators (self.tokens[i]) |
434 |
431 |
435 if type (expr[i]) is FunctionCall: |
432 if type (self.tokens[i]) is FunctionCall: |
436 self.process_functions (expr[i].args) |
433 self.process_functions (self.tokens[i].args) |
437 self.process_operators (expr[i].args) |
434 self.process_operators (self.tokens[i].args) |
438 |
435 |
439 if (type(expr[i]) is not str) or (expr[i] not in OperatorSymbols): |
436 if (type(self.tokens[i]) is not str) or (self.tokens[i] not in OperatorSymbols): |
440 i += 1 |
437 i += 1 |
441 continue |
438 continue |
442 |
439 |
443 args = [] |
440 args = [] |
444 argIndices = [] |
441 argIndices = [] |
445 if i > 0 and self.is_operand (expr[i - 1]): |
442 if i > 0 and self.is_operand (self.tokens[i - 1]): |
446 args.append (expr[i - 1]) |
443 args.append (self.tokens[i - 1]) |
447 argIndices.append (i - 1) |
444 argIndices.append (i - 1) |
448 |
445 |
449 if i - 1 < len(expr) and self.is_operand (expr[i + 1]): |
446 if i - 1 < len(self.tokens) and self.is_operand (self.tokens[i + 1]): |
450 args.append (expr[i + 1]) |
447 args.append (self.tokens[i + 1]) |
451 argIndices.append (i + 1) |
448 argIndices.append (i + 1) |
452 |
449 |
453 # Resolve operators with the same symbol based on operand count |
450 # Resolve operators with the same symbol based on operand count |
454 numOperands = 0 |
451 numOperands = 0 |
455 for arg in args: |
452 for arg in args: |
456 if self.is_operand (arg): |
453 if self.is_operand (arg): |
457 numOperands += 1 |
454 numOperands += 1 |
458 |
455 |
459 expr[i] = self.find_fitting_operator (expr[i], numOperands) |
456 self.tokens[i] = self.find_fitting_operator (self.tokens[i], numOperands) |
460 i += 1 |
457 i += 1 |
461 |
458 |
462 def find_priority_operator (self, expr): |
459 def find_priority_operator (self): |
463 """Finds the operator with most priority in the expression""" |
460 """Finds the operator with most priority in the expression""" |
464 bestOp = None |
461 bestOp = None |
465 bestOpIndex = -1 |
462 bestOpIndex = -1 |
466 |
463 |
467 for i in range (0, len (expr)): |
464 for i in range (0, len (self.tokens)): |
468 sym = expr[i] |
465 sym = self.tokens[i] |
469 |
466 |
470 if type (sym) is not Operator: |
467 if type (sym) is not Operator: |
471 continue |
468 continue |
472 |
469 |
473 if not bestOp or sym.priority < bestOp.priority: |
470 if not bestOp or sym.priority < bestOp.priority: |
474 bestOp = sym |
471 bestOp = sym |
475 bestOpIndex = i |
472 bestOpIndex = i |
476 |
473 |
477 return (bestOp, bestOpIndex) |
474 return (bestOp, bestOpIndex) |
478 |
475 |
479 def evaluate (self, expr, verbose=False): |
476 def evaluate (self, verbose=False): |
480 printFunc = realPrint if verbose else lambda x:None |
477 printFunc = realPrint if verbose else lambda x:None |
481 printFunc (self.tabs + 'Preprocess: %s' % expr) |
478 printFunc (self.tabs + 'Preprocess: %s' % self.tokens) |
482 |
479 |
483 # If there are sub-expressions in here, those need to be evaluated first |
480 # If there are sub-expressions in here, those need to be evaluated first |
484 i = 0 |
481 i = 0 |
485 while i < len (expr): |
482 while i < len (self.tokens): |
486 sym = expr[i] |
483 sym = self.tokens[i] |
487 |
484 |
488 if type (sym) is list and sym: |
485 if type (sym) is list and sym: |
489 printFunc (self.tabs + 'Evaluating sub-expression: %s' % (sym)) |
486 printFunc (self.tabs + 'Evaluating sub-expression: %s' % (sym)) |
490 self.tabs += '\t' |
487 self.tabs += '\t' |
491 expr[i] = self.evaluate (list (sym), verbose) |
488 self.tokens[i] = self.evaluate (list (sym), verbose) |
492 self.tabs = self.tabs[:-1] |
489 self.tabs = self.tabs[:-1] |
493 printFunc (self.tabs + '-> %s' % expr[i]) |
490 printFunc (self.tabs + '-> %s' % self.tokens[i]) |
494 |
491 |
495 # If there are function calls, evaluate those |
492 # If there are function calls, evaluate those |
496 if type (sym) is FunctionCall: |
493 if type (sym) is FunctionCall: |
497 self.tabs += '\t' |
494 self.tabs += '\t' |
498 if sym.args: |
495 if sym.args: |
499 sym.args = [self.evaluate (sym.args, verbose)] |
496 sym.args = [self.evaluate (sym.args, verbose)] |
500 self.tabs = self.tabs[:-1] |
497 self.tabs = self.tabs[:-1] |
501 |
498 |
502 printFunc (self.tabs + 'Evaluating function call: %s' % (sym)) |
499 printFunc (self.tabs + 'Evaluating function call: %s' % (sym)) |
503 expr[i] = Functions[sym.funcname]['function'] (*sym.args) |
500 self.tokens[i] = Functions[sym.funcname]['function'] (*sym.args) |
504 printFunc (self.tabs + '-> %s' % expr[i]) |
501 printFunc (self.tabs + '-> %s' % self.tokens[i]) |
505 |
502 |
506 i += 1 |
503 i += 1 |
507 |
504 |
508 printFunc (self.tabs + 'Evaluate: %s' % expr) |
505 printFunc (self.tabs + 'Evaluate: %s' % self.tokens) |
509 runaway = 0 |
506 runaway = 0 |
510 while True: |
507 while True: |
511 runaway += 1 |
508 runaway += 1 |
512 if runaway > 1000: |
509 if runaway > 1000: |
513 raise ValueError ('infinite loop detected') |
510 raise ValueError ('infinite loop detected') |
514 |
511 |
515 op, i = self.find_priority_operator (expr) |
512 op, i = self.find_priority_operator() |
516 if not op: |
513 if not op: |
517 break |
514 break |
518 |
515 |
519 if op.operands == 2: |
516 if op.operands == 2: |
520 argIndices = [i - 1, i + 1] |
517 argIndices = [i - 1, i + 1] |
521 else: |
518 else: |
522 argIndices = [i + 1] |
519 argIndices = [i + 1] |
523 |
520 |
524 args = [expr[x] for x in argIndices] |
521 args = [self.tokens[x] for x in argIndices] |
525 argIndices = sorted (argIndices, reverse=True) |
522 argIndices = sorted (argIndices, reverse=True) |
526 printFunc (self.tabs + 'Processing: (%s, %d) with args %s' % (op, i, args)) |
523 printFunc (self.tabs + 'Processing: (%s, %d) with args %s' % (op, i, args)) |
527 expr[i] = op.function (*args) |
524 self.tokens[i] = op.function (*args) |
528 printFunc (self.tabs + '-> %s' % expr[i]) |
525 printFunc (self.tabs + '-> %s' % self.tokens[i]) |
529 |
526 |
530 for i2 in argIndices: |
527 for i2 in argIndices: |
531 del expr[i2] |
528 del self.tokens[i2] |
532 |
529 |
533 printFunc (self.tabs + 'Result: %s' % expr[0]) |
530 printFunc (self.tabs + 'Result: %s' % self.tokens[0]) |
534 |
531 |
535 if len(expr) != 1: |
532 if len (self.tokens) != 1: |
536 printFunc (self.tabs + 'Bad expression detected, tokens: %s' % expr) |
533 printFunc (self.tabs + 'Bad expression detected, tokens: %s' % self.tokens) |
537 raise ValueError ('malformed expression') |
534 raise ValueError ('malformed expression') |
538 |
535 |
539 return expr[0] |
536 return self.tokens[0] |
540 |
537 |
541 def repr_number (self, x): |
538 def repr_number (self, x): |
542 """Returns a string representation for a real number""" |
539 """Returns a string representation for a real number""" |
543 base = self.preferred_base if self.preferred_base else 10 |
540 base = self.preferred_base if self.preferred_base else 10 |
544 if math.fabs (x - math.floor(x)) < epsilon and base != 10: |
541 if math.fabs (x - math.floor(x)) < epsilon and base != 10: |