--- a/calc.py Sun Apr 19 20:04:05 2015 +0300 +++ b/calc.py Sun Apr 19 20:49:43 2015 +0300 @@ -204,31 +204,47 @@ Symbols += Tokens Symbols = sorted (Symbols, key=lambda x: len (x), reverse=True) -ContainsHex = False +PreferredBase = 10 def parse_number (expr): """Tries to parse a number from the expression. Returns (value, length) on success.""" - global ContainsHex + global PreferredBase i = 0 value = None + base = 10 # Possibly it's hexadecimal if expr[0:2].lower() == '0x': - ContainsHex = True + base = PreferredBase = 0x10 + digits = string.hexdigits + digitname = 'hexit' + i = 2 + elif expr[0:2].lower() == '0b': + base = PreferredBase = 0b10 + digits = ['0', '1'] + digitname = 'bit' i = 2 - value = '' - while i < len (expr) and expr[i] in string.hexdigits: - value += expr[i] + if base != 10: + # Skip leading zeroes + while i < len (expr) and expr[i] == '0': + i += 1 + + startingIndex = i + while i < len (expr) and expr[i] in digits: i += 1 if i < len(expr) and expr[i] == '.': - raise ValueError ('hexadecimal floating point numbers are not supported') + raise ValueError ('non-decimal floating point numbers are not supported') - if not value: - raise ValueError ('not a valid hexadecimal number: %s' % expr[0:i+1]) + if i == startingIndex: + if i < len (expr): + raise ValueError ('not a valid %s "%s" in %s' % (digitname, expr[i], expr[0:i+1])) + else: + raise ValueError ('end of expression encountered while parsing ' + 'base-%d literal' % base) - return (complex (int (expr[2:i], 16), 0), i) + return (complex (int (expr[startingIndex:i], base), 0), i) if expr[0] == 'i': # Special case, we just have 'i' -- need special handling here because otherwise this would @@ -263,8 +279,8 @@ return None def tokenize (expr): - global ContainsHex - ContainsHex = False + global PreferredBase + PreferredBase = 10 expr = re.sub ('\s+', '', expr.strip()) i=0 tokens = [] @@ -480,6 +496,29 @@ def repr_number (x): """Returns a string representation for a real number""" + if math.fabs (x - math.floor(x)) < epsilon and PreferredBase != 10: + digits='0123456789abcdef' + assert PreferredBase <= len (digits), '''preferred base %d is too large''' % PreferredBase + + divisor = PreferredBase + rep = '' + x = int (x) + runaway = 0 + + while x > 0: + runaway += 1 + if runaway > 8: + raise ValueError('runaway triggered') + + i = (x % divisor) / (divisor / PreferredBase) + x -= i * (divisor / PreferredBase) + rep += digits[i] + divisor *= PreferredBase + + rep += 'x' if PreferredBase == 16 else 'b' + rep += '0' + return rep[::-1] + rep = '%.10f' % x if '.' in rep: @@ -489,8 +528,7 @@ if rep[-1] == '.': rep = rep[:-1] - if '.' not in rep and ContainsHex: - rep = '0x%X' % int (x) + return rep