def test_pushpop(): table = SymbolTable() t1 = Symbol("t1", Int(0, 1)) t2_1 = Symbol("t2", Int(0, 2)) t3 = Symbol("t3", Int(0, 3)) t2_2 = Symbol("t2", Int(0, 4)) t4_1 = Symbol("t4", FuncPointer(0, 5)) t4_2 = Symbol("t4", FuncPointer(0, 6)) t5 = Symbol("t5", FuncPointer(0, 7)) table.add(t1) table.add(t2_1) assert table == {"t1": t1, "t2": t2_1} table = table.push() assert table == {"t1": t1, "t2": t2_1} table.update({"t3": t3, "t2": t2_2}) assert table == {"t1": t1, "t3": t3, "t2": t2_2} table = table.push() assert table == {"t1": t1, "t3": t3, "t2": t2_2} table.update({"t4": t4_1}) assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1} table = table.push() assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1} table.update({"t4": t4_2, "t5": t5}) assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_2, "t5": t5} table = table.pop() assert table == {"t1": t1, "t3": t3, "t2": t2_2, "t4": t4_1} table = table.pop() assert table == {"t1": t1, "t3": t3, "t2": t2_2} table = table.pop() assert table == {"t1": t1, "t2": t2_1} assert_raises(Exception, table.pop)
class generate(object): def __new__(cls, root, debug=False): self = super(generate, cls).__new__(cls) self.__init__() self.debug = debug self.push_func("main") self.cfunc.scope_depth = 1 entry = self.block() blk = self.Stmts(root, entry) main = self.pop_func() main.entry = entry main.exit = blk if debug: print_blks(self.blocks.values()) print "Functions:" for name, f in sorted(self.functions.iteritems(), key=lambda x: x[0]): print f print print return self.objs, self.blocks, self.functions def __init__(self): il.Symbol.IDC = 0 il.Type.IDC = 0 self.fcount = 0 self.tcount = 0 self.bcount = 0 self.blocks = dict() self.functions = dict() self.fstack = list() self.objs = SymbolTable() def tmp(self): self.tcount += 1 return "t%i" % self.tcount def block(self): self.bcount += 1 name = "b%i" % self.bcount blk = il.Block(name) self.blocks[name] = blk self.cfunc.blks.append(blk) return blk def push_func(self, name=None): self.fcount += 1 if name is None: name = "f%i" % self.fcount self.functions[name] = il.Function(name) self.fstack.append(self.functions[name]) self.cfunc.scope_depth = self.objs.depth + 1 def pop_func(self): return self.fstack.pop() @property def cfunc(self): return self.fstack[-1] def Stmts(self, node, blk): assert node.label == "Stmts" for c in node.children: if c.label == "Assign": self.PreAssign(c) elif c.label == "Var": self.PreVar(c) for c in node.children: # print c.label if c.label == "Assign": blk = self.Assign(c, blk) elif c.label == "Var": blk = self.Var(c, blk) elif c.label == "Call": blk = self.Call(c, None, blk) elif c.label == "Print": blk = self.Print(c, blk) elif c.label == "If": blk = self.If(c, blk) else: raise Exception, c.label return blk def If(self, node, blk): assert node.label == "If" thenblk = self.block() finalblk = self.block() elseblk = None if len(node.children) == 3: elseblk = self.block() blk = self.BooleanExpr(node.children[0], blk, thenblk, elseblk) else: blk = self.BooleanExpr(node.children[0], blk, thenblk, finalblk) thenblk = self.Stmts(node.children[1], thenblk) thenblk.link(finalblk, il.UNCONDITIONAL) thenblk.insts += [il.Inst(il.J, finalblk, 0, 0)] if len(node.children) == 3: # blk.insts += [ il.Inst(il.J, elseblk, 0, 0) ] ## This line must go here. subtle bug elseblk = self.Stmts(node.children[2], elseblk) elseblk.link(finalblk, il.UNCONDITIONAL) elseblk.insts += [il.Inst(il.J, finalblk, 0, 0)] return finalblk def Print(self, node, blk): assert node.label == "Print" c = node.children[0] if c.label == "Expr": result = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(c, result, blk) else: raise Exception, c.label blk.insts += [il.Inst(il.PRNT, result, 0, 0)] return blk def PreAssign(self, node): assert node.label == "Assign" name = node.children[0] c = node.children[1] if c.label == "Func": s = il.Symbol(name, il.Func(None)) if name in self.objs.myscope: self.objs.add(s) elif name in self.objs: raise TypeError, "Cannot assign a function to a non local var." else: raise TypeError, "Variable name %s not declared." % (name) def PreVar(self, node): assert node.label == "Var" name = node.children[0] if len(node.children) == 2: c = node.children[1] if c.label == "Func": s = il.Symbol(name, il.Func(None)) if name in self.objs.myscope: raise TypeError, "Name '%s' redeclared in same scope." % name self.objs.add(s) def Assign(self, node, blk): assert node.label == "Assign" name = node.children[0] c = node.children[1] if name in self.objs: result = self.objs[name] else: raise TypeError, "Use of name %s without prior declaration" % name if c.label == "Expr": if isinstance(result.type, il.Null): result.type = il.Int() blk = self.Expr(c, result, blk, toplevel=True) elif c.label == "Func": if isinstance(result.type, il.Null): result.type = il.Func(None) blk = self.Func(c, name, blk) else: raise Exception, c.label return blk def Var(self, node, blk): assert node.label == "Var" name = node.children[0] if len(node.children) == 1: if name in self.objs.myscope: raise TypeError, "Name '%s' redeclared in same scope." % name self.objs.add(il.Symbol(name, il.Null())) else: c = node.children[1] if c.label == "Expr": if name in self.objs.myscope: raise TypeError, "Name '%s' redeclared in same scope." % name result = il.Symbol(name, il.Int()) self.objs.add(result) blk = self.Expr(c, result, blk, toplevel=True) elif c.label == "Func": blk = self.Func(c, name, blk) else: raise Exception, c.label return blk def Func(self, node, name, blk): assert node.label == "Func" parent_blk = blk self.push_func() blk = self.block() self.cfunc.entry = blk self.objs[name].type.entry = self.cfunc.name self.objs = self.objs.push() for c in node.children: if c.label == "DParams": blk = self.DParams(node.children[0], blk) elif c.label == "Stmts": blk = self.Stmts(c, blk) elif c.label == "Return": blk = self.Return(c, blk) else: raise Exception, c.label self.cfunc.exit = blk self.objs = self.objs.pop() self.pop_func() return parent_blk def Return(self, node, blk): assert node.label == "Return" if node.children: if node.children[0].label == "Expr": result = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(node.children[0], result, blk) blk.insts += [il.Inst(il.OPRM, 0, result, 0)] self.cfunc.oparam_count += 1 else: raise Exception, "Expected Expr got %s" % node.children[0].label blk.insts += [il.Inst(il.RTRN, 0, 0, 0)] return blk def DParams(self, node, blk): assert node.label == "DParams" for i, c in enumerate(node.children): t = il.Symbol(c, il.Int()) self.objs.add(t) self.cfunc.params.append(c) blk.insts += [il.Inst(il.GPRM, i, 0, t)] return blk def Expr(self, node, result, blk, toplevel=False): if node.label == "Expr": c = node.children[0] else: c = node if c.label == "INT": blk = self.Int(c.children[0], result, blk) elif c.label == "/" or c.label == "*" or c.label == "-" or c.label == "+": blk = self.Op(c, result, blk) elif c.label == "NAME": ## If it this is a top level expression (eg. c = a) then ## this is a copy instruction. Otherwise, this is a reference ## instruction, (eg. c = a + 2) ## c = a ## MV A, 0, C ## c = a + 2 ## IMM 2, 0, tmp ## ADD a, tmp, c if toplevel: blk.insts += [il.Inst(il.MV, self.objs[c.children[0]], 0, result)] else: result.clone(self.objs[c.children[0]]) elif c.label == "Call": blk = self.Call(c, result, blk) else: raise Exception, "Unexpected Node %s" % str(c) return blk def BooleanExpr(self, node, blk, thenblk, elseblk): assert node.label == "BooleanExpr" c = node.children[0] return self.BooleanOp(c, blk, thenblk, elseblk) def BooleanOp(self, c, blk, thenblk, elseblk, negate=False): if c.label == "BooleanExpr": return self.BooleanOp(c.children[0], blk, thenblk, elseblk, negate) elif c.label in ["==", "!=", "<", "<=", ">", ">="]: Ar = il.Symbol("r" + self.tmp(), il.Int()) Br = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(c.children[0], Ar, blk) blk = self.Expr(c.children[1], Br, blk) inst = self.CmpOp(c, negate) blk.insts += [il.Inst(inst, Ar, Br, thenblk), il.Inst(il.J, elseblk, 0, 0)] blk.link(thenblk, il.TRUE) blk.link(elseblk, il.FALSE) elif c.label in ("Or", "And"): ## the blk become the A expressions block ## we allocate a new blk for B, the previous block is blk a = c.children[0] b = c.children[1] ablk = blk bblk = self.block() op = c.label bresult = self.BooleanOp(b, bblk, thenblk, elseblk, negate) if negate: if op == "Or": op = "And" elif op == "And": op = "Or" if op == "Or": aresult = self.BooleanOp(a, ablk, thenblk, bresult, negate) elif op == "And": aresult = self.BooleanOp(a, ablk, bresult, elseblk, negate) blk = aresult elif c.label == "Not": blk = self.BooleanOp(c.children[0], blk, thenblk, elseblk, not negate) else: raise Exception, "Unexpected Node %s" % c.label return blk def CmpOp(self, node, negate=False): ops = {"==": il.IFEQ, "!=": il.IFNE, "<": il.IFLT, "<=": il.IFLE, ">": il.IFGT, ">=": il.IFGE} ops_ = {"==": il.IFNE, "!=": il.IFEQ, "<": il.IFGE, "<=": il.IFGT, ">": il.IFLE, ">=": il.IFLT} if negate: return ops_[node.label] else: return ops[node.label] def Op(self, node, result, blk): ops = {"/": "DIV", "*": "MUL", "-": "SUB", "+": "ADD"} Ar = il.Symbol("r" + self.tmp(), il.Int()) Br = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(node.children[0], Ar, blk) blk = self.Expr(node.children[1], Br, blk) blk.insts += [il.Inst(il.ops[ops[node.label]], Ar, Br, result)] return blk def Call(self, node, result, blk): assert node.label == "Call" fun = self.objs[node.children[0]] # print self.objs, fun, node.children[0], self.objs['f'] if isinstance(fun.type, il.Int): fun.type = fun.type.cast(il.FuncPointer) # print fun # print repr(fun) if len(node.children) != 1: blk = self.Params(node.children[1], blk) blk.insts += [il.Inst(il.CALL, fun, 0, 0)] if result is not None: blk.insts += [il.Inst(il.RPRM, 0, 0, result)] return blk def Params(self, node, blk): assert node.label == "Params" params = list() for c in node.children: result = il.Symbol("r" + self.tmp(), il.Int()) blk = self.Expr(c, result, blk) params.append(result) params.reverse() for i, p in enumerate(params): blk.insts += [il.Inst(il.IPRM, len(params) - 1 - i, p, 0)] return blk def Int(self, node, result, blk): blk.insts += [il.Inst(il.IMM, node, 0, result)] return blk