Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # -*- coding: utf-8 -*-
- from tokenizer import ZTokenizer
- class ZParserError(Exception):
- pass
- # X.Y.Z() = call. X.Y.Z should be callable type.
- # call(..., ..., ..., ...) = call expression. contains call name and list of subexpressions (parameters)
- # X ... Y = regular expession between X and Y
- # 4 + 8 * 6 * 2 + 4
- # push 2
- # push 6
- # mul
- # push 8
- # mul
- # push 4
- # add
- # push 4
- # add
- # top of stack should contain result of the expression
- # then:
- # (4 + 8) * 6 * 2 + 4
- # push 8
- # push 4
- # add
- # push 6
- # mul
- # push 2
- # mul
- # push 4
- # add
- class ZExpression:
- def __init__(self, t, v):
- self.type = t
- self.value = v
- def __repr__(self):
- return repr({'type': self.type, 'value': self.value})
- class ZParser:
- def __init__(self, fn):
- with open(fn, 'r') as f:
- text = f.read()
- tok = ZTokenizer(text)
- self.parse(tok)
- def parse_expression_part(self, tok, depth, args):
- tok.get_whitespace()
- paren = tok.get_other('(')
- if paren is not None:
- return ZExpression('expression', self.parse_expression(tok, depth+1, False))
- id = tok.get_identifier()
- if id is not None:
- if id == 'true' or id == 'false':
- return ZExpression('bool', id=='true')
- # otherwise store an identifier
- # identifier can be either dot-separated or simple
- idc = id
- tok.get_whitespace()
- dot = tok.get_other('.')
- while dot is not None:
- tok.get_whitespace()
- id = tok.require_identifier()
- idc += '.'+id
- tok.get_whitespace()
- dot = tok.get_other('.')
- return ZExpression('id', idc)
- num = tok.require_integer()
- return ZExpression('int', num)
- def parse_expression(self, tok, depth=0, args=False):
- current_level = []
- current_level.append(self.parse_expression_part(tok, depth, args))
- while not tok.is_eof():
- tok.get_whitespace()
- op = tok.get_other('<>=-+/*;,()')
- if op == '=' or op == '<' or op == '>':
- op2 = tok.get_other('=')
- if op2 is not None:
- op += '='
- if op is None or op == ';' or op == ',' or op == ')':
- if op is None:
- raise ZParserError('Invalid operator at line %d'%tok.line)
- elif op == ')' and (depth < 0 or (depth == 0 and not args)):
- raise ZParserError('Invalid expression at line %d'%tok.line)
- elif op == ',' and not args:
- raise ZParserError('Invalid expression at line %d'%tok.line)
- break
- rvalue = self.parse_expression_part(tok, depth, args)
- if op == '==' or op == '>' or op == '<' or op == '>=' or op == '<=':
- # whole current level goes into first subexpression.
- opa = {'==': 'eq', '>': 'gt', '<': 'lt', '>=': 'ge', '<=': 'le'}
- current_level = [ZExpression('operator', ['cmp_%s'%opa[op], ZExpression('expression', current_level), rvalue])]
- elif op == '*' or op == '/':
- #current_level[:] = current_level[:-1]
- #current_level.append()
- if current_level[-1].type == 'operator':
- current_level[-1].value[2] = ZExpression('expression', [ZExpression('operator', ['mul' if op == '*' else 'div', current_level[-1].value[2], rvalue])])
- else:
- current_level[-1] = ZExpression('expression', [ZExpression('operator', ['mul' if op == '*' else 'div', current_level[-1], rvalue])])
- elif op == '+' or op == '-':
- #tok.position = posa
- lvalue = current_level[-1]
- current_level[:] = current_level[:-1]
- current_level.append(ZExpression('operator', ['add' if op == '+' else 'sub', lvalue, rvalue]))
- else:
- raise ZParserError('Invalid operator at line %d'%tok.line)
- return current_level
- def compile_expression(self, exprl, depth=0):
- expra = []
- for expr in exprl:
- if expr.type == 'expression':
- expra += self.compile_expression(expr.value, depth+1)
- elif expr.type == 'operator':
- #expra.append(expr)
- expra += self.compile_expression([expr.value[1]]) # push ...
- expra += self.compile_expression([expr.value[2]]) # push ...
- expra.append([expr.value[0]])
- elif expr.type == 'int':
- expra.append(['push', expr.value])
- elif expr.type == 'bool':
- expra.append(['push', 1 if expr.value else 0])
- return expra
- def parse(self, tok):
- actions = self.compile_expression(self.parse_expression(tok))
- self.code = actions
- par = ZParser('test.zs')
- for action in par.code:
- actionstr = []
- for actionany in action:
- actionstr.append(str(actionany))
- print('%s' % (' '.join(actionstr)))
- class ZExecutor:
- def __init__(self):
- self.stack = []
- def stack_pop(self):
- val = self.stack[-1]
- self.stack[:] = self.stack[:-1]
- return val
- def op_push(self, what):
- self.stack.append(what)
- def op_mul(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(val1 * val2)
- def op_div(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(val1 / val2)
- def op_add(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(val1 + val2)
- def op_sub(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(val1 - val2)
- def op_cmp_gt(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(1 if val1 > val2 else 0)
- def op_cmp_lt(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(1 if val1 < val2 else 0)
- def op_cmp_ge(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(1 if val1 >= val2 else 0)
- def op_cmp_le(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(1 if val1 <= val2 else 0)
- def op_cmp_eq(self):
- val2 = self.stack_pop()
- val1 = self.stack_pop()
- self.stack.append(1 if val1 == val2 else 0)
- executor = ZExecutor()
- for action in par.code:
- met = getattr(executor, 'op_%s'%action[0])
- met(*action[1:])
- result = executor.stack_pop()
- print('\nresult: %d'%result)
Add Comment
Please, Sign In to add comment