Exemple #1
0
func finalEdits(prog *cc.Prog) {
	cc.Postorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Expr:
			if x.Op == cc.Arrow && x.Text == "prg" && c2go.GoString(x.Left) == "ctxt.arch" {
				x.Left = x.Left.Left // drop arch.
			}
		}
	})
}
Exemple #2
0
func fixGoTypesExpr(fn *cc.Decl, x *cc.Expr, targ *cc.Type) (ret *cc.Type) {
	if x == nil {
		return nil
	}

	defer func() {
		x.XType = ret
	}()

	if x.Op == cc.Paren {
		return fixGoTypesExpr(fn, x.Left, targ)
	}

	// Make explicit C's implicit conversions from boolean to non-boolean and vice versa.
	switch x.Op {
	case cc.AndAnd, cc.OrOr, cc.Not, cc.EqEq, cc.Lt, cc.LtEq, cc.Gt, cc.GtEq, cc.NotEq:
		if targ != nil && targ.Kind != c2go.Bool {
			old := copyExpr(x)
			if targ.Kind == c2go.Int {
				x.Op = cc.Call
				x.Left = &cc.Expr{Op: cc.Name, Text: "bool2int"}
				x.List = []*cc.Expr{old}
				x.Right = nil
			} else {
				x.Op = cc.Cast
				x.Left = &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: "bool2int"}, List: []*cc.Expr{old}}
				x.Type = targ
			}
			fixGoTypesExpr(fn, old, boolType)
			return targ
		}
	default:
		if targ != nil && targ.Kind == c2go.Bool {
			old := copyExpr(x)
			left := fixGoTypesExpr(fn, old, nil)
			if left != nil && left.Kind == c2go.Bool {
				return targ
			}
			if old.Op == cc.Number {
				switch old.Text {
				case "1":
					x.Op = cc.Name
					x.Text = "true"
					return targ
				case "0":
					x.Op = cc.Name
					x.Text = "false"
					return targ
				}
			}
			x.Op = cc.NotEq
			x.Left = old
			x.Right = zeroFor(left)
			return targ
		}
	}

	switch x.Op {
	default:
		panic(fmt.Sprintf("unexpected construct %v in fixGoTypesExpr - %v - %v", c2go.GoString(x), x.Op, x.Span))

	case c2go.ExprSlice:
		// inserted by rewriteLen
		left := fixGoTypesExpr(fn, x.List[0], targ)
		fixGoTypesExpr(fn, x.List[1], nil)
		fixGoTypesExpr(fn, x.List[2], nil)
		return left

	case cc.Comma:
		for i, y := range x.List {
			t := targ
			if i+1 < len(x.List) {
				t = nil
			}
			fixGoTypesExpr(fn, y, t)
		}
		return nil

	case c2go.ExprBlock:
		for _, stmt := range x.Block {
			fixGoTypesStmt(nil, fn, stmt)
		}
		return nil

	case cc.Add, cc.And, cc.Div, cc.Mod, cc.Mul, cc.Or, cc.Sub, cc.Xor:
		if x.Op == cc.Sub && isPtrSliceOrArray(x.Left.XType) && isPtrSliceOrArray(x.Right.XType) {
			left := fixGoTypesExpr(fn, x.Left, nil)
			right := fixGoTypesExpr(fn, x.Right, nil)
			if left != nil && right != nil && left.Kind != right.Kind {
				if left.Kind == c2go.Slice {
					forceConvert(fn, x.Right, right, left)
				} else {
					forceConvert(fn, x.Left, left, right)
				}
			}
			x.Left = &cc.Expr{Op: cc.Minus, Left: &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: "cap"}, List: []*cc.Expr{x.Left}}}
			x.Right = &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: "cap"}, List: []*cc.Expr{x.Right}}
			x.Op = cc.Add
			return intType
		}

		left := fixGoTypesExpr(fn, x.Left, targ)

		if x.Op == cc.And && x.Right.Op == cc.Twid {
			x.Op = c2go.AndNot
			x.Right = x.Right.Left
		}

		if x.Op == cc.Add && isSliceStringOrArray(left) {
			fixGoTypesExpr(fn, x.Right, nil)
			x.Op = c2go.ExprSlice
			x.List = []*cc.Expr{x.Left, x.Right, nil}
			x.Left = nil
			x.Right = nil
			if left.Kind == cc.Array {
				left = &cc.Type{Kind: c2go.Slice, Base: left.Base}
			}
			return left
		}

		right := fixGoTypesExpr(fn, x.Right, targ)
		return fixBinary(fn, x, left, right, targ)

	case cc.AddEq, cc.AndEq, cc.DivEq, cc.Eq, cc.ModEq, cc.MulEq, cc.OrEq, cc.SubEq, cc.XorEq:
		left := fixGoTypesExpr(fn, x.Left, nil)

		if x.Op == cc.AndEq && x.Right.Op == cc.Twid {
			x.Op = c2go.AndNotEq
			x.Right = x.Right.Left
		}

		if x.Op == cc.AddEq && isSliceOrString(left) {
			fixGoTypesExpr(fn, x.Right, nil)
			old := copyExpr(x.Left)
			x.Op = cc.Eq
			x.Right = &cc.Expr{Op: c2go.ExprSlice, List: []*cc.Expr{old, x.Right, nil}}
			return left
		}

		if x.Op == cc.Eq && x.Left.Op == cc.Index && sameType(x.Left.Left.XType, stringType) && c2go.GoString(x.Left.Right) == "0" && c2go.GoString(x.Right) == "0" {
			x.Left = x.Left.Left
			x.Right = &cc.Expr{Op: cc.Name, Text: `""`}
			return x.Left.XType
		}

		forceGoType(fn, x.Right, left)

		return left

	case c2go.ColonEq:
		left := fixGoTypesExpr(fn, x.Right, nil)
		x.Left.XType = left
		x.Left.XDecl.Type = left
		return left

	case cc.Addr:
		left := fixGoTypesExpr(fn, x.Left, nil)
		if left == nil {
			return nil
		}

		if targ != nil && targ.Kind == c2go.Slice && sameType(targ.Base, left) {
			l := x.Left
			l.Op = c2go.ExprSlice
			l.List = []*cc.Expr{l.Left, l.Right, nil}
			l.Left = nil
			l.Right = nil
			fixMerge(x, l)
			return targ
		}

		return &cc.Type{Kind: cc.Ptr, Base: left}

	case cc.AndAnd, cc.OrOr, cc.Not:
		fixGoTypesExpr(fn, x.Left, boolType)
		if x.Right != nil {
			fixGoTypesExpr(fn, x.Right, boolType)
		}
		return boolType

	case cc.Arrow, cc.Dot:
		left := fixGoTypesExpr(fn, x.Left, nil)

		if x.Op == cc.Arrow && isSliceOrString(left) {
			x.Left = &cc.Expr{Op: cc.Index, Left: x.Left, Right: &cc.Expr{Op: cc.Number, Text: "0"}}
		}

		return x.XDecl.Type

	case cc.Call:
		if fixPrintf(fn, x) {
			return x.XType
		}
		if fixSpecialCall(fn, x, targ) {
			return x.XType
		}
		left := fixGoTypesExpr(fn, x.Left, nil)
		for i, y := range x.List {
			if left != nil && left.Kind == cc.Func && i < len(left.Decls) {
				forceGoType(fn, y, left.Decls[i].Type)
			} else {
				fixGoTypesExpr(fn, y, nil)
			}
		}
		if left != nil && left.Kind == cc.Func {
			return left.Base
		}
		return nil

	case cc.Cast:
		fixGoTypesExpr(fn, x.Left, nil)
		return x.Type

	case cc.CastInit:
		fixGoTypesInit(nil, x.Init)
		return x.Type

	case cc.EqEq, cc.Gt, cc.GtEq, cc.Lt, cc.LtEq, cc.NotEq:
		if fixSpecialCompare(fn, x) {
			return boolType
		}
		left := fixGoTypesExpr(fn, x.Left, nil)
		if x.Right.Op == cc.Number && x.Right.Text == "0" {
			if isSliceOrPtr(left) {
				x.Right.Op = cc.Name
				x.Right.Text = "nil"
				return boolType
			}
			if left != nil && left.Kind == c2go.String {
				x.Right.Op = cc.String
				x.Right.Texts = []string{`""`}
				return boolType
			}
		}
		right := fixGoTypesExpr(fn, x.Right, nil)

		if isSliceOrArray(x.Left.XType) && isSliceOrArray(x.Right.XType) {
			x.Left = &cc.Expr{Op: cc.Minus, Left: &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: "cap"}, List: []*cc.Expr{x.Left}}}
			x.Right = &cc.Expr{Op: cc.Minus, Left: &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: "cap"}, List: []*cc.Expr{x.Right}}}
			return boolType
		}

		fixBinary(fn, x, left, right, nil)
		return boolType

	case cc.Index, cc.Indir:
		left := fixGoTypesExpr(fn, x.Left, nil)
		if x.Right != nil {
			fixGoTypesExpr(fn, x.Right, nil)
		}
		if left == nil {
			return nil
		}

		if isSliceOrString(left) && x.Op == cc.Indir {
			x.Op = cc.Index
			x.Right = &cc.Expr{Op: cc.Number, Text: "0"}
		}

		switch left.Kind {
		case cc.Ptr, c2go.Slice, cc.Array:
			return left.Base

		case c2go.String:
			return byteType
		}
		return nil

	case cc.Lsh, cc.Rsh:
		left := fixGoTypesExpr(fn, x.Left, targ)
		if left != nil && targ != nil && c2go.Int8 <= left.Kind && left.Kind <= c2go.Float64 && targ.Kind > left.Kind {
			forceConvert(fn, x.Left, left, targ)
			left = targ
		}
		fixShiftCount(fn, x.Right)
		return left

	case cc.LshEq, cc.RshEq:
		left := fixGoTypesExpr(fn, x.Left, nil)
		fixShiftCount(fn, x.Right)
		return left

	case cc.Name:
		if x.Text == "nelem" {
		}
		switch x.Text {
		case "T", "S", "N", "L", "P":
			x.Text = "nil"
			x.XDecl = nil
			return nil
		case "nelem":
			x.Text = "len"
			x.XDecl = nil
			fallthrough
		case "len":
			return &cc.Type{Kind: cc.Func, Base: intType}
		}
		if x.XDecl == nil {
			return nil
		}
		return x.XDecl.Type

	case cc.Number:
		return idealType

	case cc.Minus, cc.Plus, cc.Twid:
		return fixGoTypesExpr(fn, x.Left, targ)

	case cc.Offsetof:
		// TODO
		return nil

	case cc.Paren:
		return fixGoTypesExpr(fn, x.Left, targ)

	case cc.PostDec, cc.PostInc:
		left := fixGoTypesExpr(fn, x.Left, nil)

		if x.Op == cc.PostInc && isSliceOrString(left) {
			old := copyExpr(x.Left)
			x.Op = cc.Eq
			x.Right = &cc.Expr{Op: c2go.ExprSlice, List: []*cc.Expr{old, &cc.Expr{Op: cc.Number, Text: "1"}, nil}}
		}

		return nil

	case cc.SizeofExpr:
		left := fixGoTypesExpr(fn, x.Left, nil)
		if left != nil && (left.Kind == cc.Array || left.Kind == c2go.Slice) && left.Base.Def().Is(c2go.Uint8) {
			x.Op = cc.Call
			x.List = []*cc.Expr{x.Left}
			x.Left = &cc.Expr{Op: cc.Name, Text: "len"}
			return intType
		}
		return nil

	case cc.SizeofType:
		return nil

	case cc.String:
		return &cc.Type{Kind: c2go.String}

	case cc.VaArg:
		// TODO
		return nil
	}
}
Exemple #3
0
// Rewrite C types to be Go types.
func rewriteTypes(prog cc.Syntax) {
	// Assign overrides to groups.
	cc.Postorder(prog, func(x cc.Syntax) {
		if d, ok := x.(*cc.Decl); ok {
			key := declKey(d)
			t := override[key]
			if t == nil {
				return
			}
			if t.Kind == cc.Array {
				// Override only applies to specific decl. Skip for now.
				return
			}
			f := flowCache[d]
			if f == nil {
				return
			}
			g := f.group
			if g.goKind != 0 || g.goType != nil {
				fmt.Fprintf(os.Stderr, "multiple overrides: %v (%p) and %v (%p)\n", key, f.group, g.goKey, g.goFlow.group)
			}
			g.goKey = key
			g.goFlow = f
			if t.Kind <= cc.Enum {
				panic("bad go type override")
			}
			if (t.Kind == cc.Ptr || t.Kind == c2go.Slice) && t.Base == nil {
				g.goKind = t.Kind
			} else {
				g.goType = t
			}
		}
	})

	// Process overrides.
	cache := make(map[*cc.Type]*cc.Type)
	for _, g := range flowGroups {
		if g.goType != nil {
			continue
		}
		if c2go.Int8 <= g.goKind && g.goKind <= c2go.Float64 {
			g.goType = &cc.Type{Kind: g.goKind}
			continue
		}
		if g.goKind == cc.Ptr || g.goKind == c2go.Slice {
			t := g.decls[0].Type
			if t == nil || t.Base == nil {
				fmt.Printf("%s: expected ptr/array/slice for %s\n", g.decls[0].Span, declKey(g.decls[0]))
				continue
			}
			g.goType = &cc.Type{Kind: g.goKind, Base: toGoType(nil, nil, t.Base, cache)}
			continue
		}
		if g.goKind != 0 {
			fmt.Printf("%s: unexpected go kind %v\n", g.goKey, g.goKind)
			continue
		}
	}

	// Process defaults.
	// Each group has a 'canonical' instance of the type
	// that we can use as the initial hint.
	for _, g := range flowGroups {
		if g.goType != nil {
			continue
		}
		if g.canon == nil {
			fmt.Printf("group missing canonical\n")
			continue
		}
		if g.isBool {
			g.goType = boolType
			continue
		}
		t := g.canon.Def()
		if cc.Char <= t.Kind && t.Kind <= cc.Enum {
			// Convert to an appropriately sized number.
			// Canon is largest rank from C; convert to Go.
			g.goType = &cc.Type{Kind: c2goKind[t.Kind]}
			continue
		}

		if t.Kind == cc.Ptr || t.Kind == cc.Array {
			// Default is convert to pointer.
			// If there are any arrays or any pointer arithmetic, convert to slice instead.
			k := cc.Ptr
			for _, d := range g.decls {
				if d.Type != nil && d.Type.Kind == cc.Array {
					k = c2go.Slice
				}
			}
			for _, f := range g.syntax {
				if f.ptrAdd {
					k = c2go.Slice
				}
			}
			if t.Base.Kind == cc.Char {
				g.goType = &cc.Type{Kind: c2go.String}
				continue
			}
			g.goType = &cc.Type{Kind: k, Base: toGoType(nil, nil, t.Base, cache)}
			continue
		}
	}

	if *showGroups {
		fmt.Printf("%d groups\n", len(flowGroups))
		for _, g := range flowGroups {
			suffix := ""
			if g.isBool {
				suffix = " [bool]"
			}
			fmt.Printf("group(%d): %v (canon %v)%s\n", len(g.decls), c2go.GoString(g.goType), c2go.GoString(g.canon), suffix)
			for i := 0; i < 2; i++ {
				for _, f := range g.syntax {
					if d, ok := f.syntax.(*cc.Decl); ok == (i == 0) {
						suffix := ""
						if ok {
							suffix = ": " + declKey(d) + " " + c2go.GoString(d.Type)
						}
						if f.ptrAdd {
							suffix += " (ptradd)"
						}
						if f.usedAsBool {
							suffix += " (bool)"
						}
						fmt.Printf("\t%s %v%s\n", f.syntax.GetSpan(), f.syntax, suffix)
					}
				}
			}
		}
	}

	// Apply grouped decisions to individual declarations.
	cc.Postorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Decl:
			d := x
			if d.Name == "..." || d.Type == nil {
				return
			}
			if d.Name == "" && d.Type.Is(cc.Enum) && len(d.Type.Decls) > 0 {
				for _, dd := range d.Type.Decls {
					dd.Type = idealType
				}
				return
			}
			t := override[declKey(d)]
			if t != nil && t.Kind == cc.Array {
				d.Type = t
				return
			}
			f := flowCache[d]
			if f == nil {
				d.Type = toGoType(nil, d, d.Type, cache)
				if declKey(d) != "tmp" {
					fprintf(d.Span, "missing flow group for %s", d.Span, declKey(d))
				}
				return
			}
			g := f.group
			if d.Init != nil && len(d.Init.Braced) > 0 && d.Type != nil && d.Type.Kind == cc.Array {
				// Initialization of array - do not override type.
				// But if size is not given explicitly, change to slice.
				d.Type.Base = toGoType(nil, nil, d.Type.Base, cache)
				if d.Type.Width == nil {
					d.Type.Kind = c2go.Slice
				}
				return
			}
			d.Type = toGoType(g, d, d.Type, cache)
			if d.Type != nil && d.Type.Kind == cc.Func && d.Type.Base.Kind != cc.Void {
				if f != nil && f.returnValue != nil && f.returnValue.group != nil && f.returnValue.group.goType != nil {
					d.Type.Base = f.returnValue.group.goType
				}
			}

		case *cc.Expr:
			if x.Type != nil {
				t := toGoType(nil, nil, x.Type, cache)
				if t == nil {
					fprintf(x.Span, "cannot convert %v to go type\n", c2go.GoString(x.Type))
				}
				x.Type = t
			}
		}
	})
}
Exemple #4
0
func fixSpecialCall(fn *cc.Decl, x *cc.Expr, targ *cc.Type) bool {
	if x.Left.Op != cc.Name {
		return false
	}
	switch x.Left.Text {
	case "memmove":
		if len(x.List) != 3 {
			fprintf(x.Span, "unsupported %v", x)
			return false
		}
		siz := x.List[2]
		if siz.Op == cc.Number && siz.Text == "4" {
			obj1, obj1Type := objIndir(fn, x.List[0])
			obj2, obj2Type := objIndir(fn, x.List[1])
			if obj1Type == nil || obj2Type == nil {
				fprintf(x.Span, "unsupported %v - missing types", x)
				return true
			}
			if (obj1Type.Kind == c2go.Uint32 || obj1Type.Kind == c2go.Int32) && obj2Type.Kind == c2go.Float32 {
				x.Op = cc.Eq
				x.Left = obj1
				x.Right = &cc.Expr{
					Op: cc.Call,
					Left: &cc.Expr{Op: cc.Name,
						Text: "math.Float32bits",
					},
					List: []*cc.Expr{obj2},
				}
				x.XType = uint32Type
				return true
			}
			fprintf(x.Span, "unsupported %v - size 4 type %v %v", x, c2go.GoString(obj1Type), c2go.GoString(obj2Type))
		}
		if siz.Op == cc.Number && siz.Text == "8" {
			obj1, obj1Type := objIndir(fn, x.List[0])
			obj2, obj2Type := objIndir(fn, x.List[1])
			if obj1Type == nil || obj2Type == nil {
				fprintf(x.Span, "unsupported %v - missing types", x)
				return true
			}
			if (obj1Type.Kind == c2go.Uint64 || obj1Type.Kind == c2go.Int64) && obj2Type.Kind == c2go.Float64 {
				x.Op = cc.Eq
				x.Left = obj1
				x.Right = &cc.Expr{
					Op: cc.Call,
					Left: &cc.Expr{Op: cc.Name,
						Text: "math.Float64bits",
					},
					List: []*cc.Expr{obj2},
				}
				x.XType = uint64Type
				return true
			}
			fprintf(x.Span, "unsupported %v - size 8 type %v %v", x, c2go.GoString(obj1Type), c2go.GoString(obj2Type))
		}
		if siz.Op == cc.SizeofExpr {
			obj1Type := fixGoTypesExpr(fn, x.List[0], nil)
			obj2Type := fixGoTypesExpr(fn, x.List[1], nil)
			sizeType := fixGoTypesExpr(fn, siz.Left, nil)
			if obj1Type == nil || obj2Type == nil {
				fprintf(x.Span, "unsupported %v - bad types", x)
				return true
			}
			if obj2Type.Kind == cc.Array && sameType(obj2Type, sizeType) || obj2Type.Kind == c2go.Slice && c2go.GoString(x.List[1]) == c2go.GoString(siz.Left) {
				x.Left.Text = "copy"
				x.Left.XDecl = nil
				x.List = x.List[:2]
				return true
			}
			fprintf(x.Span, "unsupported %v - not array %v %v", x, c2go.GoString(obj2Type), c2go.GoString(sizeType))
			return true
		}
		left := fixGoTypesExpr(fn, x.List[0], nil)
		right := fixGoTypesExpr(fn, x.List[1], nil)
		fixGoTypesExpr(fn, siz, nil)
		if isSliceOrArray(left) && isSliceOrArray(right) && left.Base.Is(c2go.Uint8) && right.Base.Is(c2go.Uint8) {
			x.Left.Text = "copy"
			x.Left.XDecl = nil
			if x.List[1].Op == c2go.ExprSlice && x.List[1].List[1] == nil {
				x.List[1].List[2] = siz
			} else {
				x.List[1] = &cc.Expr{Op: c2go.ExprSlice, List: []*cc.Expr{x.List[1], nil, siz}}
			}
			x.List = x.List[:2]
			return true
		}
		fprintf(x.Span, "unsupported %v (%v %v)", x, c2go.GoString(left), c2go.GoString(right))
		return true

	case "mal", "malloc", "emallocz":
		if len(x.List) != 1 {
			fprintf(x.Span, "unsupported %v - too many args", x)
			return false
		}
		siz := x.List[0]
		var count *cc.Expr
		if siz.Op == cc.Mul {
			count = siz.Left
			siz = siz.Right
		}
		var typ *cc.Type
		switch siz.Op {
		default:
			typ = byteType
			count = siz

		case cc.SizeofExpr:
			typ = fixGoTypesExpr(fn, siz.Left, nil)
			if typ == nil {
				fprintf(siz.Span, "failed to type check %v", siz.Left)
			}

		case cc.SizeofType:
			typ = siz.Type
			if typ == nil {
				fprintf(siz.Span, "sizeoftype missing type")
			}
		}
		if typ == nil {
			fprintf(x.Span, "unsupported %v - cannot understand type", x)
			return true
		}
		if count == nil {
			x.Left.Text = "new"
			x.Left.XDecl = nil
			x.List = []*cc.Expr{&cc.Expr{Op: cc.Name, Text: c2go.GoString(typ)}}
			x.XType = &cc.Type{Kind: cc.Ptr, Base: typ}
		} else {
			x.Left.Text = "make"
			x.Left.XDecl = nil
			x.List = []*cc.Expr{
				&cc.Expr{Op: cc.Name, Text: "[]" + c2go.GoString(typ)},
				count,
			}
			x.XType = &cc.Type{Kind: c2go.Slice, Base: typ}
		}
		return true

	case "strdup", "estrdup":
		if len(x.List) != 1 {
			fprintf(x.Span, "unsupported %v - too many args", x)
			return false
		}
		fixGoTypesExpr(fn, x.List[0], stringType)
		fixMerge(x, x.List[0])
		x.XType = stringType
		return true

	case "strcpy", "strcat", "fmtstrcpy":
		if len(x.List) != 2 {
			fprintf(x.Span, "unsupported %v - too many args", x)
			return false
		}
		fixGoTypesExpr(fn, x.List[0], nil)
		fixGoTypesExpr(fn, x.List[1], stringType)
		x.Op = cc.Eq
		if x.Left.Text == "strcat" || x.Left.Text == "fmtstrcpy" {
			x.Op = cc.AddEq
		}
		x.Left = x.List[0]
		x.Right = x.List[1]
		x.XType = stringType
		return true

	case "strlen":
		x.Left.Text = "len"
		x.Left.XDecl = nil
		x.XType = intType
		return true

	case "TUP", "CASE":
		if len(x.List) != 2 {
			fprintf(x.Span, "unsupported %v - too many args", x)
			return false
		}
		left := fixGoTypesExpr(fn, x.List[0], targ)
		right := fixGoTypesExpr(fn, x.List[1], targ)
		x.Op = cc.Or
		x.Left = &cc.Expr{Op: cc.Lsh, Left: x.List[0], Right: &cc.Expr{Op: cc.Number, Text: "16"}, XType: left}
		x.Right = x.List[1]
		x.List = nil
		x.XType = fixBinary(fn, x, left, right, targ)
		return true
	}

	return false
}
Exemple #5
0
func fixQsortCmp(decl *cc.Decl) *cc.Type {
	ftyp := decl.Type
	if ftyp.Kind != cc.Func || len(ftyp.Decls) != 2 || !isGoVoidPtr(ftyp.Decls[0].Type) || !isGoVoidPtr(ftyp.Decls[1].Type) {
		fprintf(decl.Span, "invalid qsort cmp function %v - wrong args", c2go.GoString(ftyp))
		return nil
	}

	a1, a2 := ftyp.Decls[0], ftyp.Decls[1]
	var eq1, eq2, p1, p2 *cc.Expr
	var indir1, indir2 bool

	cc.Preorder(decl.Body, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Expr:
			if x.Op != cc.Eq {
				return
			}
			r := x.Right
			if r.Op == cc.Indir {
				r = r.Left
			}
			if r.Op == cc.Cast && r.Left.Op == cc.Name {
				if r.Left.XDecl == a1 && p1 == nil {
					p1 = x.Left
					eq1 = x
					indir1 = r != x.Right
				}
				if r.Left.XDecl == a2 && p2 == nil {
					p2 = x.Left
					eq2 = x
					indir1 = r != x.Right
				}
			}
		}
	})

	if p1 == nil || p2 == nil {
		fprintf(decl.Span, "invalid qsort cmp function - cannot find arg extraction")
		return nil
	}

	if !sameType(p1.XType, p2.XType) {
		fprintf(decl.Span, "invalid qsort cmp function - different arg types %v and %v", c2go.GoString(p1.XType), c2go.GoString(p2.XType))
		return nil
	}
	if indir1 != indir2 {
		fprintf(decl.Span, "invalid qsort cmp function - different arg indirection")
		return nil
	}

	typ := p1.XType
	if !indir1 {
		if typ.Def().Kind != cc.Ptr {
			fprintf(decl.Span, "invalid qsort cmp function - arg ptr cast to non-ptr %v", c2go.GoString(typ))
			return nil
		}
		typ = typ.Def().Base
	}

	// Have all the information. Committed.
	// Rewrite to take x, i, j, use x[i] for p1, x[j] for p2,
	// take address of x[i], x[j] if there was no indirect,
	// replace all return z with return z < 0.
	cmp := decl.Name
	decl.Name = "(x " + cmp + ") Less"
	decl.Type = &cc.Type{
		Kind: cc.Func,
		Base: boolType,
		Decls: []*cc.Decl{
			{Name: "i", Type: &cc.Type{Kind: cc.TypedefType}},
			{Name: "j", Type: intType},
		},
	}

	prefix := ""
	if !indir1 {
		prefix = "&"
	}
	eq1.Right = &cc.Expr{Op: cc.Name, Text: prefix + "x[i]", XType: p1.XType}
	eq2.Right = &cc.Expr{Op: cc.Name, Text: prefix + "x[j]", XType: p1.XType}

	cc.Preorder(decl.Body, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Stmt:
			if x.Op == cc.Return && x.Expr != nil {
				ret := x.Expr
				// Pick off 0, -1, +1.
				// Otherwise rewrite ret to ret < 0.
				switch ret.Op {
				case cc.Minus, cc.Plus:
					if ret.Left.Op == cc.Number {
						ret.Op = cc.Name
						if ret.Op == cc.Plus {
							ret.Text = "true"
						} else {
							ret.Text = "false"
						}
						ret.Left = nil
						ret.XType = boolType
						return
					}
				case cc.Number:
					ret.Op = cc.Name
					ret.Text = "false"
					ret.XType = boolType
					return
				}
				x.Expr = &cc.Expr{Op: cc.Lt, Left: ret, Right: &cc.Expr{Op: cc.Number, Text: "0"}, XType: boolType}
				return
			}
		}
	})

	return typ
}
Exemple #6
0
func fixPrintf(curfn *cc.Decl, x *cc.Expr) bool {
	if x.Op != cc.Call {
		return false
	}
	if tryPrintf(curfn, x, "sprint", 1, "fmt.Sprintf") {
		targ := x.List[0]
		x.List = x.List[1:]
		x.Right = copyExpr(x)
		x.List = nil
		x.Left = targ
		x.Op = cc.Eq

		// sprint(strchr(s, 0), "hello") => s += "hello"
		if targ.Op == cc.Call && len(targ.List) == 2 && targ.Left.Text == "strchr" && targ.List[1].Text == "0" {
			x.Left = targ.List[0]
			x.Op = cc.AddEq
		} else if targ.Op == cc.Add && targ.Right.Op == cc.Call && targ.Right.Left.Text == "strlen" && len(targ.Right.List) == 1 && c2go.GoString(targ.Left) == c2go.GoString(targ.Right.List[0]) {
			x.Left = targ.Left
			x.Op = cc.AddEq
		}
		return true
	}
	if tryPrintf(curfn, x, "snprint", 2, "fmt.Sprintf") {
		targ := x.List[0]
		x.List = x.List[2:]
		x.Right = copyExpr(x)
		x.List = nil
		x.Left = targ
		x.Op = cc.Eq
		return true
	}
	if tryPrintf(curfn, x, "fmtprint", 1, "fmt.Sprintf") {
		targ := x.List[0]
		x.List = x.List[1:]
		x.Right = copyExpr(x)
		x.List = nil
		x.Left = targ
		x.Op = cc.AddEq
		return true
	}
	if tryPrintf(curfn, x, "print", 0, "fmt.Printf") {
		return true
	}
	if tryPrintf(curfn, x, "sysfatal", 0, "log.Fatalf") {
		return true
	}
	if tryPrintf(curfn, x, "ctxt.diag", 0, "ctxt.diag") {
		return true
	}
	if tryPrintf(curfn, x, "Bprint", 1, "fmt.Fprintf") {
		return true
	}
	if tryPrintf(curfn, x, "smprint", 0, "fmt.Sprintf") {
		return true
	}

	return false
}