Skip to content

Instantly share code, notes, and snippets.

@jstitch
Last active March 7, 2017 23:21
Show Gist options
  • Save jstitch/0e616018b51cedd955403af4ca6dfc1c to your computer and use it in GitHub Desktop.
Save jstitch/0e616018b51cedd955403af4ca6dfc1c to your computer and use it in GitHub Desktop.
a calc in python based on tutorial at Ruslan's blog: https://ruslanspivak.com/lsbasi-part3/
NUMBER, OPER, NONE = "NUMBER", "OPER", "NONE"
VALID_OPERS = ["+", "-", "*", "/", "^"]
class Token(object):
def __init__(self, type, value):
self.type = type
self.value = value
def __str__(self):
return "{} {}".format(self.type, self.value)
# try to build a Token infering the type of the input
def build_token(tok):
type = NUMBER
try:
value = float(tok)
except ValueError:
try:
value = int(tok)
except ValueError:
if tok not in VALID_OPERS:
raise Exception("UNRECOGNIZED TOKEN '{}'".format(tok))
value = tok
type = OPER
return Token(type, value)
# Lexer
def get_tokens(stream):
string = stream
tok = ""
for c in string:
if c in VALID_OPERS:
yield build_token(tok.strip())
yield build_token(c)
tok = ""
else:
tok += c
if tok.strip():
yield build_token(tok.strip())
return Token(NONE,None)
from math import pow
oper = {
'+' : lambda x,y: x+y,
'-' : lambda x,y: x-y,
'*' : lambda x,y: x*y,
'/' : lambda x,y: x/y,
'^' : lambda x,y: pow(x,y)
}
# Parser
class Parser(object):
def __init__(self, string):
self.string = string
def parse(self):
gen = get_tokens(self.string)
first_term = next(gen)
result = first_term.value
try:
while True:
operator = next(gen)
next_term = next(gen)
result = oper[operator.value](first_term.value, next_term.value)
first_term = build_token(str(result))
except StopIteration:
return result
return None
def main():
while True:
try:
text = input('calc> ')
except IOError:
break
if not text:
continue
parser = Parser(text)
result = parser.parse()
print(result)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment