basic precedence algorithm - not tested yet

This commit is contained in:
Dave Halter
2014-03-07 14:40:57 +01:00
parent ca460ac34f
commit 77bfb0fb7b
+80 -70
View File
@@ -12,37 +12,41 @@ class PythonGrammar(object):
Some kind of mirror of http://docs.python.org/3/reference/grammar.html. Some kind of mirror of http://docs.python.org/3/reference/grammar.html.
""" """
class AtStart(tuple):
pass
class MultiPart(str): class MultiPart(str):
def __new__(cls, first, second): def __new__(cls, first, second):
self = str.__new__(cls, first) self = str.__new__(cls, first)
self.second = second self.second = second
factor = AtStart(('+', '-', '~')) def __str__(self):
power = '**', return self.__str__() + ' ' + self.second
term = '*', '/', '%', '//'
arith_expr = '+', '-'
shift_expr = '<<', '>>' FACTOR = '+', '-', '~'
and_expr = '&', POWER = '**',
xor_expr = '^', TERM = '*', '/', '%', '//'
expr = '|', ARITH_EXPR = '+', '-'
comparison = ('<', '>', '==', '>=', '<=', '!=', 'in', SHIFT_EXPR = '<<', '>>'
MultiPart('not', 'in'), 'is', MultiPart('is', 'not')) AND_EXPR = '&',
XOR_EXPR = '^',
EXPR = '|',
not_test = AtStart(('not',)) COMPARISON = ('<', '>', '==', '>=', '<=', '!=', 'in',
and_test = 'and', MultiPart('not', 'in'), MultiPart('is', 'not')), 'is'
or_test = 'or',
#test = or_test ['if' or_test 'else' test] | lambdef NOT_TEST = 'not',
AND_TEST = 'and',
OR_TEST = 'or',
#sliceop = ':' [test] #TEST = or_test ['if' or_test 'else' test] | lambdef
#subscript = test | [test] ':' [test] [sliceop]
order = (factor, power, term, arith_expr, shift_expr, and_expr, xor_expr, #SLICEOP = ':' [test]
expr, comparison, not_test, and_test, or_test) #SUBSCRIPT = test | [test] ':' [test] [sliceop]
ORDER = (POWER, TERM, ARITH_EXPR, SHIFT_EXPR, AND_EXPR, XOR_EXPR,
EXPR, COMPARISON, AND_TEST, OR_TEST)
FACTOR_PRIORITY = 0 # highest priority
LOWEST_PRIORITY = len(ORDER)
NOT_TEST_PRIORITY = LOWEST_PRIORITY - 2 # priority only lower for `and`/`or`
class Precedence(object): class Precedence(object):
@@ -51,58 +55,64 @@ class Precedence(object):
self.operator = operator self.operator = operator
self.right = right self.right = right
def __repr__(self):
return '(%s %s %s)' % (self.left, self.operator, self.right)
def create_precedence(expression_list): def create_precedence(expression_list):
def get_op(current, expression_list): iterator = PushBackIterator(expression_list)
for element in expression_list: return _check_operator(iterator)
return
if not isinstance(obj, str):
debug.warning('normal element in place of operator: %s', element) def _syntax_error(element, msg='SyntaxError in precedence'):
debug.warning('%s: %s, %s' % (msg, element, element.start_pos))
def _get_number(iterator, priority=PythonGrammar.LOWEST_PRIORITY):
el = next(iterator)
if isinstance(el, pr.Operator):
if el in PythonGrammar.FACTOR:
right = _get_number(iterator, PythonGrammar.FACTOR_PRIORITY)
elif el in PythonGrammar.NOT_TEST and priority <= PythonGrammar.FACTOR_PRIORITY:
right = _get_number(iterator, PythonGrammar.NOT_TEST_PRIORITY)
else:
_syntax_error(el)
return _get_number(iterator, priority)
return Precedence(None, el, right)
else:
return el
def _check_operator(iterator, priority=PythonGrammar.LOWEST_PRIORITY):
"""
"""
left = _get_number(iterator, priority)
for el in iterator:
if not isinstance(el, pr.Operator):
_syntax_error(el)
continue
operator = None
for check_prio, check in enumerate(PythonGrammar.ORDER):
if check_prio >= priority:
break # respect priorities.
try:
match = check.index(el)
except ValueError:
continue continue
def is_operator(obj): if isinstance(match, PythonGrammar.MultiPart):
if isinstance(obj, pr.Call): next_tok = next(iterator)
element = str(obj.name) if next_tok != match.second:
for term in PythonGrammar.order: iterator.push_back(next_tok)
pass continue
return element
def tokenize(): operator = check
pass break
new if operator is None:
current = None _syntax_error(el)
exp_iterator = PushBackIterator(expression_list) continue
for element in expression_list: left = Precedence(left, operator, _check_operator(iterator, check_prio))
op_name = element return left
if isinstance(element, pr.Call):
op_name = str(element.name)
current = s
if isinstance(element, pr.Call):
x = str(element.name)
new = _process_element(element, expression_list)
if current is None:
current = new
else:
current = _process_element(element, expression_list)
return current
def _process_element(element, expression_list, previous=None):
if element is None:
return previous
if isinstance(element, pr.Call):
element = str(element.name)
elif not isinstance(element, str):
if previous is None:
previous = element
return _process_element(expression_list, previous=previous)
for term in PythonGrammar.order:
if element in term:
right = _process_element(expression_list)
if right is None:
return previous
else:
return Precedence(previous, element, right)