func fixGoTypesStmt(prog *cc.Prog, fn *cc.Decl, x *cc.Stmt) { if x == nil { return } switch x.Op { case cc.StmtDecl: fixGoTypesExpr(fn, x.Expr, nil) case cc.StmtExpr: if x.Expr != nil && x.Expr.Op == cc.Call && x.Expr.Left.Op == cc.Name { switch x.Expr.Left.Text { case "qsort": fixQsort(prog, x.Expr) return case "memset": fixMemset(prog, fn, x) return case "free": x.Op = cc.Empty x.Expr = nil return } } fixGoTypesExpr(fn, x.Expr, nil) case cc.If, cc.For: fixGoTypesExpr(fn, x.Pre, nil) fixGoTypesExpr(fn, x.Post, nil) fixGoTypesExpr(fn, x.Expr, boolType) case cc.Switch: fixGoTypesExpr(fn, x.Expr, nil) case cc.Return: if x.Expr != nil { forceGoType(fn, x.Expr, fn.Type.Base) } } for _, stmt := range x.Block { fixGoTypesStmt(prog, fn, stmt) } if len(x.Block) > 0 && x.Body != nil { panic("block and body") } fixGoTypesStmt(prog, fn, x.Body) fixGoTypesStmt(prog, fn, x.Else) for _, lab := range x.Labels { // TODO: use correct type fixGoTypesExpr(fn, lab.Expr, nil) } }
func fixMemset(prog *cc.Prog, fn *cc.Decl, stmt *cc.Stmt) { x := stmt.Expr if len(x.List) != 3 || x.List[1].Op != cc.Number || x.List[1].Text != "0" { fprintf(x.Span, "unsupported %v - nonzero", x) return } if x.List[2].Op == cc.SizeofExpr || x.List[2].Op == cc.SizeofType { obj, objType := objIndir(fn, x.List[0]) if !matchSize(fn, obj, objType, x.List[2]) { fprintf(x.Span, "unsupported %v - wrong size", x) return } x.Op = cc.Eq x.Left = obj x.Right = zeroFor(objType) x.List = nil return } siz := x.List[2] var count *cc.Expr var objType *cc.Type if siz.Op == cc.Mul { count = siz.Left siz = siz.Right if siz.Op != cc.SizeofExpr && siz.Op != cc.SizeofType { fprintf(x.Span, "unsupported %v - wrong array size", x) return } switch siz.Op { case cc.SizeofExpr: p := unparen(siz.Left) if p.Op != cc.Indir && p.Op != cc.Index || !sameType(p.Left.XType, x.List[0].XType) { fprintf(x.Span, "unsupported %v - wrong size", x) } objType = fixGoTypesExpr(fn, x.List[0], nil) case cc.SizeofType: objType = fixGoTypesExpr(fn, x.List[0], nil) if !sameType(siz.Type, objType.Base) { fprintf(x.Span, "unsupported %v - wrong size", x) } } } else { count = siz objType = fixGoTypesExpr(fn, x.List[0], nil) if !objType.Base.Is(c2go.Byte) && !objType.Base.Is(c2go.Uint8) { fprintf(x.Span, "unsupported %v - wrong size form for non-byte type", x) return } } // Found it. Replace with zeroing for loop. stmt.Op = cc.For stmt.Pre = &cc.Expr{ Op: cc.Eq, Left: &cc.Expr{ Op: cc.Name, Text: "i", XType: intType, }, Right: &cc.Expr{ Op: cc.Number, Text: "0", XType: intType, }, XType: boolType, } stmt.Expr = &cc.Expr{ Op: cc.Lt, Left: &cc.Expr{ Op: cc.Name, Text: "i", XType: intType, }, Right: count, XType: boolType, } stmt.Post = &cc.Expr{ Op: cc.PostInc, Left: &cc.Expr{ Op: cc.Name, Text: "i", XType: intType, }, XType: intType, } stmt.Body = &cc.Stmt{ Op: cc.Block, Block: []*cc.Stmt{ { Op: cc.StmtExpr, Expr: &cc.Expr{ Op: cc.Eq, Left: &cc.Expr{ Op: cc.Index, Left: x.List[0], Right: &cc.Expr{Op: cc.Name, Text: "i"}, }, Right: zeroFor(objType.Base), }, }, }, } return }
func rewriteStmt(stmt *cc.Stmt) { // TODO: Double-check stmt.Labels switch stmt.Op { case cc.ARGBEGIN: panic(fmt.Sprintf("unexpected ARGBEGIN")) case cc.Do: // Rewrite do { ... } while(x) // to for(;;) { ... if(!x) break } // Since rewriteStmt is called in a preorder traversal, // the recursion into the children will clean up x // in the if condition as needed. stmt.Op = cc.For x := stmt.Expr stmt.Expr = nil stmt.Body = forceBlock(stmt.Body) stmt.Body.Block = append(stmt.Body.Block, &cc.Stmt{ Op: cc.If, Expr: &cc.Expr{Op: cc.Not, Left: x}, Body: &cc.Stmt{Op: cc.Break}, }) case cc.While: stmt.Op = cc.For fallthrough case cc.For: before1, _ := extractSideEffects(stmt.Pre, sideStmt|sideNoAfter) before2, _ := extractSideEffects(stmt.Expr, sideNoAfter) if len(before2) > 0 { x := stmt.Expr stmt.Expr = nil stmt.Body = forceBlock(stmt.Body) top := &cc.Stmt{ Op: cc.If, Expr: &cc.Expr{Op: cc.Not, Left: x}, Body: &cc.Stmt{Op: cc.Break}, } stmt.Body.Block = append(append(before2, top), stmt.Body.Block...) } if len(before1) > 0 { old := copyStmt(stmt) stmt.Pre = nil stmt.Expr = nil stmt.Post = nil stmt.Body = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(before1, old) } before, after := extractSideEffects(stmt.Post, sideStmt) if len(before)+len(after) > 0 { all := append(append(before, &cc.Stmt{Op: cc.StmtExpr, Expr: stmt.Post}), after...) stmt.Post = &cc.Expr{Op: c2go.ExprBlock, Block: all} } case cc.If, cc.Return: before, _ := extractSideEffects(stmt.Expr, sideNoAfter) if len(before) > 0 { old := copyStmt(stmt) stmt.Expr = nil stmt.Body = nil stmt.Else = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(before, old) } case cc.StmtExpr: before, after := extractSideEffects(stmt.Expr, sideStmt) if len(before)+len(after) > 0 { old := copyStmt(stmt) stmt.Expr = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(append(before, old), after...) } case cc.Goto: // TODO: Figure out where the goto goes and maybe rewrite // to labeled break/continue. // Otherwise move code or something. case cc.Switch: // TODO: Change default fallthrough to default break. before, _ := extractSideEffects(stmt.Expr, sideNoAfter) rewriteSwitch(stmt) if len(before) > 0 { old := copyStmt(stmt) stmt.Expr = nil stmt.Body = nil stmt.Else = nil stmt.Op = c2go.BlockNoBrace stmt.Block = append(before, old) } } }