def __init__(self): self.global_frame = self.new_callframe(None, None) #save global variable. self.global_code = ByteData() #save global function #self._active_code = None self._active_frame = None self.stdout = self.stdin = self.stderr = None #temporary used in compile process. self.statement_stack = []
class Interpreter(object): """this module is support to compile AST as byte code, and run byte code.""" def __init__(self): self.global_frame = self.new_callframe(None, None) #save global variable. self.global_code = ByteData() #save global function #self._active_code = None self._active_frame = None self.stdout = self.stdin = self.stderr = None #temporary used in compile process. self.statement_stack = [] def assemble_ast(self, ast, code=None): """convert AST to byte code.""" if code is None: code = ByteData() assert ast, "AST object is required." handler = "_c_%s" % type(ast).__name__ if hasattr(self, handler): getattr(self, handler)(ast, code) else: self.error_msg("not found AST handler:%s" % handler, ast.coord) return code def interpreter(self, bytecode, frame=None): if frame is None: frame = new_callframe(self.global_frame, bytecode) else: frame.load_code(bytecode) #self.frame = frame self.active_frame(frame) while self.active_frame() is not None: op = self.active_frame().next_operation() if op is None: break handler_name = "_op_%s" % op if hasattr(self, handler_name): handler = getattr(self, handler_name) handler(self.active_frame(), ) else: self.error_msg("Not supported operation '%s'" % op) return frame.return_value #property def active_frame(self, frame='null'): if frame != 'null': self._active_frame = frame return self._active_frame def init_builtin_function(self, builtin_list): for func in builtin_list: if callable(func): name = func.func_code.co_name args_length = func.func_code.co_argcount decl = Function(name, 'unknown', args_length, None, func) self.function_reference(name, decl) elif isinstance(func, types.TupleType): decl = Function(*func) self.function_reference(decl.name, decl) def new_callframe(self, frame, bytedata): cur_frame = CallFrame(bytedata=bytedata, parent=frame) return cur_frame def link_global_code(self, bytecode): """load byte data in global scope.""" for name, func in bytecode.functions.iteritems(): if self.global_code.func_reference(name) is None: self.global_code.func_reference(name, func) else: self.error_msg("function %s is defined!" % name) self.interpreter(bytecode, self.global_frame) def function_reference(self, name, ref=None): #It's not a bad code. the ByteData object should not reference a Function that's # a interpreter concept. func = None #if self.bytedata: func = self.bytedata.func_reference(name, ref) #if func is None: func = self.global_code.func_reference(name, ref) if func: func.inter = self return func else: self.error_msg("function '%s' not define!" % name) def var_reference(self, name, ref=None): var = self.active_frame().var_reference(name, ref) or self.global_frame.var_reference(name) if var: return var else: self.error_msg("variable '%s' not define!" % var) def error_msg(self, msg, coord=None): print "msg: %s, coord:%s" % (msg, coord) def _eval_param(self, frame, val): """[C0] --- register [-1] --- stack tail [1] --- stack pop """ if type(val) == str: if val[0] == '[': reg = val[1:-2] try: reg = int(reg) if reg > 0: for e in range(reg): reg = frame.pop() else: reg = frame.stack[reg] return reg except: return frame.register(reg) else: return val def _c_FunctionDecl(self, funDecl, code): func_code = ByteData() param_len = 0 if funDecl.param: self._c_ParamList(funDecl.param, func_code) param_len = len(funDecl.param.params) self.assemble_ast(funDecl.stmt, func_code) func = Function(funDecl.name.name, funDecl.type, param_len, func_code) code.func_reference(funDecl.name.name, func) def _c_FileAST(self, ast, code): for ext in ast.children(): self.assemble_ast(ext, code) def _c_ParamList(self, paramList, code): for param in paramList.children(): self._c_Param(param, code) def _c_ExprList(self, expr, code): for e in expr.children(): self.assemble_ast(e, code) def _c_Param(self, param, code): init_op = None if param.out: op = OP.decl_ref init_op = OP.save_ref elif param.var.type == 'array': op = OP.decl_array init_op = OP.save_ref #the array is passed as ref. else: op = OP.decl_var init_op = OP.save_var code.add_operation(op, None, param.type, param.var.name.name) code.add_operation(init_op, param.var.name.name) def _c_Compound(self, comp, code): for decl in comp.decls or []: self._c_Decl(decl, code) for stmt in comp.stmts or []: self.assemble_ast(stmt, code) def _c_BinaryOp(self, node, code): op = node.op #self._c_expression(node.left) #self._c_expression(node.right) if op.type == 'OR': true_label = code.new_label() self.assemble_ast(node.left, code) code.add_operation(OP.if_goto, true_label) code.add_operation(OP.pop) self.assemble_ast(node.right, code) code.add_label(true_label) elif op.type == 'AND': false_label = code.new_label() self.assemble_ast(node.left, code) code.add_operation(OP.unless_goto, false_label) code.add_operation(OP.pop) self.assemble_ast(node.right, code) code.add_label(false_label) else: self.assemble_ast(node.left, code) self.assemble_ast(node.right, code) code.add_operation(op.type) def _c_FuncCall(self, func_call, code): """ """ len_args = 0 #args is a ExprList object if func_call.args: args_expr = func_call.args.exprs len_args = len(args_expr) for expr in args_expr: self.assemble_ast(expr, code) code.add_operation(OP.call, func_call.name.name, len_args) def _c_Decl(self, decl, code): qualifier = decl.qualifier type = decl.type code.update_coord(decl.coord) def init_array(name, length, init): code.add_operation(OP.decl_array, qualifier, type, name, length) if init: for value in init: self.assemble_ast(value, code) code.add_operation(OP.save_array, name, 0, len(init)) def init_var(name, init): #length = len(init) code.add_operation(OP.decl_var, qualifier, type, name) if init: self.assemble_ast(init, code) else: code.add_operation(OP.null_var) code.add_operation(OP.save_var, name) for var in decl.vars: op = OP.decl_array if var.name.type == 'array' else OP.decl_var if var.name.type == 'array': length = var.name.index and eval(var.name.index.value) or \ len(var.init or []) init_array(var.name.name.name, length, var.init) else: init_var(var.name.name.name, var.init) def _c_Constant(self, const, code): #ord if const.type == 'char': code.add_operation(OP.push, ord(const.value)) elif const.type == 'integer': if const.value.startswith("0x"): code.add_operation(OP.push, int(const.value, 16)) elif const.value.startswith("0"): code.add_operation(OP.push, int(const.value, 8)) else: code.add_operation(OP.push, int(const.value)) elif const.type == 'string': code.add_operation(OP.push, const.value[1:-1]) else: self.error_msg("invalid const", const.coord) def _c_Assignment(self, assign, code): """ a<-[0], a[0]<-[0] """ self.assemble_ast(assign.value, code) var = assign.var if var.type == 'array': self.assemble_ast(var.index, code) code.add_operation(OP.pop_reg, "[C0]") code.add_operation(OP.save_array, var.name.name, '[C0]', 1) else: code.add_operation(OP.save_var, var.name.name) def _c_Varible(self, var, code): if var.type == 'array': self.assemble_ast(var.index, code) code.add_operation(OP.pop_reg, "[C0]") code.add_operation(OP.load_array, var.name.name, '[C0]', 1) else: code.add_operation(OP.load_var, var.name.name) def _c_If(self, stmt, code): true_label = code.new_label() false_label = code.new_label() end_label = code.new_label() self.assemble_ast(stmt.cond, code) code.add_operation(OP.unless_goto, false_label) self.assemble_ast(stmt.iftrue, code) code.add_operation(OP.goto, end_label) code.add_label(false_label) if stmt.iffalse: self.assemble_ast(stmt.iffalse, code) code.add_label(end_label) code.add_operation(OP.pop) #pop the result of expression def _c_For(self, stmt, code): self.statement_stack.append(stmt) if stmt.init: self.assemble_ast(stmt.init, code) stmt.cond_label = code.new_label() stmt.next_label = code.new_label() stmt.end_label = code.new_label() stmt.pop_label = code.new_label() #start condition expression code.add_label(stmt.cond_label) if stmt.cond: self.assemble_ast(stmt.cond, code) else: #always is true, if omit condtion expression. code.add_operation(OP.push, 1) code.add_operation(OP.unless_goto, stmt.pop_label) #start statement code.add_operation(OP.pop) self.assemble_ast(stmt.stmt, code) #start next statement code.add_label(stmt.next_label) if stmt.next: self.assemble_ast(stmt.next, code) code.add_operation(OP.goto, stmt.cond_label) #pop condition result. code.add_label(stmt.pop_label) code.add_operation(OP.pop) code.add_label(stmt.end_label) self.statement_stack.pop() def _c_Break(self, st, code): if len(self.statement_stack) > 0: stmt = self.statement_stack[-1] code.add_operation(OP.goto, stmt.end_label) else: pass def _c_Continue(self, st, code): if len(self.statement_stack) > 0: stmt = self.statement_stack[-1] code.add_operation(OP.goto, stmt.next_label) else: pass def _c_Return(self, stmt, code): if stmt.expr: self.assemble_ast(stmt.expr, code) code.add_operation(OP.ret_func) else: code.add_operation(OP.ret_void_func) def _c_While(self, stmt, code): self.statement_stack.append(stmt) stmt.cond_label = code.new_label() stmt.end_label = code.new_label() stmt.pop_label = code.new_label() #start condition expression code.add_label(stmt.cond_label) self.assemble_ast(stmt.cond, code) code.add_operation(OP.unless_goto, stmt.pop_label) #start statement code.add_operation(OP.pop) self.assemble_ast(stmt.stmt, code) code.add_operation(OP.goto, stmt.cond_label) #pop condition result. code.add_label(stmt.pop_label) code.add_operation(OP.pop) code.add_label(stmt.end_label) self.statement_stack.pop() def _op_POP(self, frame): frame.pop() def _op_PUSH(self, frame): data = frame.next_data() frame.push(data) def _op_DECL_VAR(self, frame): #decl variable: OP, qualifier, TYPE, NAME. const, type, name = frame.next_data(), frame.next_data(), frame.next_data() #self, name, type, array=False, length=0, const=False var = InternalVariable(name, type, const == 'const') self.var_reference(name, var) def _op_DECL_ARRAY(self, frame): self._op_DECL_VAR(frame) def _op_IF_GOTO(self, frame): label = frame.next_data() if frame.top(): frame.goto(label) def _op_UNLESS_GOTO(self, frame): label = frame.next_data() if not frame.top(): frame.goto(label) def _op_LOAD_VAR(self, frame): name = frame.next_data() var = self.var_reference(name) frame.push(var.value) def _op_LOAD_ARRAY(self, frame): name = frame.next_data() index = frame.next_data() length = frame.next_data() index = self._eval_param(frame, index) length = self._eval_param(frame, length) var = self.var_reference(name) if var is not None: value = var.value[index: index + length] for v in value: frame.push(v) if length != 1: frame.push(length) def _op_SAVE_VAR(self, frame): name = frame.next_data() value = frame.pop() var = self.var_reference(name) if var.const and var.value is not None: self.error_msg("variable '%s' is const." % name) else: if var.type == 'string' and isinstance(value, basestring): var.value = value elif var.type == 'integer' and isinstance(value, int): var.value = value elif var.type == 'float' and isinstance(value, float): var.value = value else: self.error_msg("error variable type '%s' != '%s<%s>'" % (var.type, value, type(value))) def _op_SAVE_ARRAY(self, frame): name = frame.next_data() index = frame.next_data() length = frame.next_data() index = self._eval_param(frame, index) length = self._eval_param(frame, length) var = self.var_reference(name) value = [] for v in range(length): value.insert(0, frame.pop()) var.value[index: index + length] = value def _op_SAVE_REF(self, frame): name = frame.next_data() def _op_CALL(self, frame): self.return_value = None name = frame.next_data() args_length = frame.next_data() args = [] for e in range(args_length): args.append(frame.pop()) func = self.function_reference(name) if func == None: self.error_msg("function %s not defined before!" % name) if func.builtIn: args.reverse() result = func.call(*args) if result is not None: frame.push(result) else: frame = self.new_callframe(frame, func.bytedata) for arg in args: frame.push(arg) self.active_frame(frame) def _op_RETURN_FUNC(self, frame): frame.return_value = value = frame.pop() parent_frame = frame.parentFrame if parent_frame is not None: parent_frame.push(value) self.active_frame(parent_frame) def _op_RETURN_VOID_FUNC(self, frame): frame.return_value = 'void' self.active_frame(frame.parentFrame) def _op_PLUS(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 + var1) def _op_MINUS(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 - var1) def _op_TIMES(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 * var1) def _op_DIVIDE(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 / var1) def _op_MOD(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 % var1) def _op_LT(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(1 if var2 < var1 else 0) def _op_LE(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(1 if var2 <= var1 else 0) def _op_GT(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(1 if var2 > var1 else 0) def _op_GE(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(1 if var2 >= var1 else 0) def _op_EQ(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(1 if var2 == var1 else 0) def _op_NE(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(1 if var2 != var1 else 0) def _op_BOR(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 | var1) def _op_BAND(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 & var1) def _op_BNOT(self, frame): var1 = frame.pop() frame.push(~var1) def _op_BXOR(self, frame): var1 = frame.pop() var2 = frame.pop() frame.push(var2 ^ var1)