calc.py

changeset 126
0fc519afba89
parent 125
c44b1aa85257
child 127
66b206bd9510
--- 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
 

mercurial