Skip to content

Instantly share code, notes, and snippets.

@ppsdatta
Created June 16, 2023 13:16
Show Gist options
  • Save ppsdatta/e4dc3eb60c9acff84ae655d7ba5a1b0a to your computer and use it in GitHub Desktop.
Save ppsdatta/e4dc3eb60c9acff84ae655d7ba5a1b0a to your computer and use it in GitHub Desktop.
A Forth like parser in Python
def get_next_token(s):
while s and s[0].isspace():
s = s[1:]
if not s:
return None, ""
if s[0] in "()":
return s[0], s[1:]
i = 0
while i < len(s) and not s[i].isspace() and s[i] not in "()":
i += 1
return s[:i], s[i:]
class Stack:
def __init__(self):
self.stack = []
def push(self, item):
self.stack.append(item)
def pop(self):
return self.stack.pop()
def peek(self):
return self.stack[-1]
def is_empty(self):
return len(self.stack) == 0
def size(self):
return len(self.stack)
def tokenize(s):
tokens = []
while s:
token, s = get_next_token(s)
if token:
tokens.append(token)
return tokens
def make_stack_op(f, n):
def stack_op(stk):
if stk.size() < n:
raise ValueError("Stack must have at least {} items".format(n))
args = reversed([stk.pop() for _ in range(n)])
result = f(*args)
stk.push(result)
return stack_op
d = {
"+": make_stack_op(lambda x, y: x + y, 2),
"-": make_stack_op(lambda x, y: x - y, 2),
"*": make_stack_op(lambda x, y: x * y, 2),
"/": make_stack_op(lambda x, y: x / y, 2),
"^": make_stack_op(lambda x, y: x**y, 2),
"%": make_stack_op(lambda x, y: x % y, 2),
}
def is_number(s):
try:
float(s)
return True
except ValueError:
return False
def apply_tokens(stk, tokens, d):
for token in tokens:
if is_number(token):
stk.push(int(token))
else:
if token in d:
op = d[token]
op(stk)
else:
raise ValueError(f"Unknown operator {token}")
def stk_eval(stk, expr, d):
tokens = tokenize(expr)
apply_tokens(stk, tokens, d)
def repl():
stk = Stack()
while True:
expr = input("? ")
stk_eval(stk, expr, d)
print(stk.stack)
if __name__ == "__main__":
repl()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment