92 lines
2.2 KiB
Python
92 lines
2.2 KiB
Python
|
from collections import deque
|
||
|
|
||
|
from tokens import NumberTokenParser, OperatorTokenParser
|
||
|
|
||
|
class ParsingException(Exception):
|
||
|
pass
|
||
|
|
||
|
class Parser(object):
|
||
|
def __init__(self, token_stream):
|
||
|
self._token_stream = token_stream
|
||
|
self._stack = deque()
|
||
|
self._current_list = deque()
|
||
|
|
||
|
def parse(self):
|
||
|
state = 0
|
||
|
while True:
|
||
|
token = self._token_stream.get_token()
|
||
|
if(token == "("):
|
||
|
if(state == 1):
|
||
|
raise ParsingException(
|
||
|
"expected operator, not parenthesis: {} (near '{}')".format(
|
||
|
self._token_stream._offset
|
||
|
, token))
|
||
|
|
||
|
self._stack.append(self._current_list)
|
||
|
continue
|
||
|
|
||
|
if(NumberTokenParser.can_parse(token)):
|
||
|
if(state == 1):
|
||
|
raise ParsingException(
|
||
|
"expected operator, not number: {} (near '{}')".format(
|
||
|
self._token_stream._offset
|
||
|
, token))
|
||
|
self._current_list.append(NumberTokenParser(token).parse())
|
||
|
state = 1
|
||
|
continue
|
||
|
|
||
|
if(OperatorTokenParser.can_parse(token)):
|
||
|
if(state != 1):
|
||
|
raise ParsingException(
|
||
|
"expected number or parenthesis, not operator: {} (near '{}')".format(
|
||
|
self._token_stream._offset
|
||
|
, token))
|
||
|
|
||
|
self._current_list.append(OperatorTokenParser(token).parse())
|
||
|
state = 0
|
||
|
continue
|
||
|
|
||
|
if(token == ")"):
|
||
|
#if(state == 1):
|
||
|
# raise ParsingException(
|
||
|
# "expected operator, not parenthesis: {} (near '{}')".format(
|
||
|
# self._token_stream._offset
|
||
|
# , token))
|
||
|
state = 1
|
||
|
|
||
|
result = self.execute_branch(self._current_list)
|
||
|
self._current_list = self._stack.pop()
|
||
|
continue
|
||
|
|
||
|
if(not token):
|
||
|
if(self._stack):
|
||
|
raise ParsingException("unexpected EOF while parsing")
|
||
|
return self.execute_branch(self._current_list)
|
||
|
|
||
|
raise ParsingException("unknown token: {} (near '{}')".format(self._token_stream._offset, token))
|
||
|
|
||
|
return self.execute_branch(self._current_list)
|
||
|
|
||
|
def execute_branch(self, branch):
|
||
|
result = None
|
||
|
current_operator = None
|
||
|
|
||
|
for element in branch:
|
||
|
if(result is None):
|
||
|
result = element
|
||
|
continue
|
||
|
|
||
|
if(not isinstance(element, (float, int, complex))):
|
||
|
# Operator
|
||
|
current_operator = element
|
||
|
continue
|
||
|
|
||
|
if(current_operator):
|
||
|
result = current_operator(result, element)
|
||
|
current_operator = None
|
||
|
return result
|
||
|
|
||
|
|
||
|
|
||
|
|