def _while(env, args): if len(args) < 2: raise CompileTimeError, 'while -- Missing blocks %r' % args pred = args[0] codes = args[1:] # create some labels loop_start_label = NewLabel('loop_start') loop_next_label = NewLabel('loop_next') loop_end_label = NewLabel('loop_end') env.while_stack.append((loop_start_label, loop_end_label)) env.emit(tac.label(loop_start_label)) # emit code for looping tmp_pred = env.eval_(pred) if not tmp_pred.can_cast_to_type('int'): print 'WARNING: while -- casting %r to boolean type' % tmp_pred env.print_block() # loop labels env.emit(tac.cbranch(tmp_pred.tacn, loop_next_label)) env.emit(tac.branch(loop_end_label)) env.emit(tac.label(loop_next_label)) ret_val = env.exec_block(codes) # XXX: the block need to know how to jump # out of this loop! hmm... a stack? env.emit(tac.branch(loop_start_label)) env.emit(tac.label(loop_end_label)) env.while_stack.pop() # remove while stack # while should not have a return value... things should be changed # by side effects. this is what loops are intended to do return obtype.Token('void')
def _defmacro(env, args): """no type checking""" mac_name = env.curr_evaling[1][0].n # get the macro name env = Env(env) env.emit(tac.mac_begin('%s' % mac_name)) env.emit(tac.label(util.mangle(mac_name))) # entrance fbody = args[2:] for mac in fbody: if mac[0].n != 'asm': raise CompileTimeError, 'defmacro -- body must be all asm' ret_val = env.exec_block(fbody) # must return one val ret_val.vt = 'omni' # can be cast to any type env.emit(tac.mac_end('%s' % mac_name)) return ret_val
def _cond(env, args): to_ret = [] # tac preparations pred_labels = [NewLabel('case') for i in xrange(len(args))] block_labels = [NewLabel('iftrue') for i in xrange(len(args))] else_label = NewLabel('else') final_label = NewLabel('final') final_result = NewVar() # for each predicate and code block: for i, pred_todo in enumerate(args): if len(pred_todo) == 1: # no todo? raise CompileTimeError, 'cond -- Missing code block '\ 'after predicate %r' % (pred_todo) pred = pred_todo[0] codes = pred_todo[1:] # XXX: here i dont check whether the else is placed at the last if isinstance(pred, obtype.Token) and pred.symbolp() \ and pred.n == 'else': # is else env.emit(tac.label(else_label)) ret_val = env.exec_block(codes) env.emit(tac.assign(final_result, ret_val.tacn)) else: # is predcate if i != 0: env.emit(tac.label(pred_labels[i])) # at case i pred = env.eval_(pred) # eval and emit code block if not pred.can_cast_to_type('int'): print 'WARNING: cond -- casting %r to boolean type' % pred env.print_block() env.emit(tac.cbranch(pred.tacn, block_labels[i])) # if true if i == len(args) - 1: # is the last case. XXX: somehow dirty.. env.emit(tac.branch(final_label)) elif isinstance(args[i + 1][0], obtype.Token) and \ args[i + 1][0].n == 'else': env.emit(tac.branch(else_label)) else: # still have more cases to check env.emit(tac.branch(pred_labels[i + 1])) env.emit(tac.label(block_labels[i])) # exec block ret_val = env.exec_block(codes) env.emit(tac.assign(final_result, ret_val.tacn)) env.emit(tac.branch(final_label)) to_ret.append(ret_val) # cond over, the final label env.emit(tac.label(final_label)) if not to_ret: return obtype.Token('void') else: first = to_ret[0] first.tacn = final_result # it's created on the fly so dont worry # about the side effect ^ ^ for item in to_ret: if not first.can_cast_to(item): print 'WARNING: cond -- returning different types: %r %r' % ( first, item) env.print_block() return first