Beispiel #1
0
Datei: main.go Projekt: 0x7cc/rsc
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.
			}
		}
	})
}
Beispiel #2
0
Datei: main.go Projekt: 0x7cc/rsc
// 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
			}
		}
	})
}
Beispiel #3
0
func inferTypes(cfg *Config, prog *cc.Prog) {
	cc.Postorder(prog, func(x cc.Syntax) {
		if t, ok := x.(*cc.Type); ok {
			if t.Kind == cc.Struct || t.Kind == cc.Enum {
				for _, d := range t.Decls {
					d.OuterType = t
				}
			}
		}
	})

	addFlow(cfg, prog)

	for _, f := range flowCache {
		if f.group != nil {
			continue
		}
		g := &flowGroup{}
		if f.stopFlow {
			addToGroup(g, f)
			continue
		}
		exploreGroup(g, f)
		if len(g.decls) == 0 {
			continue
		}
		flowGroups = append(flowGroups, g)
	}
	sort.Sort(flowGroupsBySize(flowGroups))

	for _, g := range flowGroups {
		var typ *cc.Type
		var typDecl *cc.Decl
		for _, d := range g.decls {
			if d.Type == nil {
				continue
			}
			dt := d.Type.Def()
			if typ == nil || typ.Kind == cc.Ptr && typ.Base.Is(cc.Void) {
				typ = dt
				typDecl = d
			}
			if !inferCompatible(dt, typ) {
				fmt.Printf("BAD INFER: mixing %v (%v) and %v (%v)\n", typ, declKey(typDecl), d.Type, declKey(d))
				findFlowPath(flowCache[typDecl], flowCache[d])
				os.Exit(1)
			}
			if isNumericCType(typ) && isNumericCType(dt) && typ.Kind == cc.Enum || dt.Kind != cc.Enum && typ.Kind < dt.Kind {
				typ = dt
				typDecl = d
			}
		}
		g.canon = typ
		g.canonDecl = typDecl
	}

	for _, g := range flowGroups {
		for _, f := range g.syntax {
			if f.usedAsBool {
				g.isBool = isNumericCType(g.canon) && g.canon.Kind <= cc.Int
				break
			}
		}
	}
	for {
		changed := false
		for _, g := range flowGroups {
			if !g.isBool {
				continue
			}
			for _, f := range g.syntax {
				x, ok := f.syntax.(*cc.Expr)
				if !ok {
					continue
				}
				switch x.Op {
				case cc.EqEq, cc.LtEq, cc.GtEq, cc.NotEq, cc.Lt, cc.Gt, cc.AndAnd, cc.OrOr:
					continue
				case cc.Number:
					if x.Text == "0" || x.Text == "1" {
						continue
					}
				case cc.Call:
					if x.Left.Op == cc.Name {
						f := flowCache[x.Left.XDecl]
						if f != nil && f.returnValue != nil && f.returnValue.group != nil && f.returnValue.group.isBool {
							continue
						}
					}
				}
				// can't be bool
				changed = true
				g.isBool = false
			}
		}
		if !changed {
			break
		}
	}

	if *src != "" && *dst != "" {
		var fsrc, fdst *flowSyntax
		for _, f := range flowCache {
			d, ok := f.syntax.(*cc.Decl)
			if ok {
				key := declKey(d)
				if key == "" {
					continue
				}
				if *src == key {
					fsrc = f
					fmt.Printf("%s in %p %p\n", key, f, f.group)
				}
				if strings.HasSuffix(*src, key) {
					fmt.Printf("near: %s\n", key)
				}
				if *dst == key {
					fdst = f
					fmt.Printf("%s in %p %p\n", key, f, f.group)
				}
				if strings.HasSuffix(*dst, key) {
					fmt.Printf("near: %s\n", key)
				}
			}
		}
		if fsrc != nil && fdst != nil {
			findFlowPath(fsrc, fdst)
			os.Exit(0)
		}
		fmt.Printf("%s and %s are not in the same group\n", *src, *dst)
		os.Exit(0)
	}
}
Beispiel #4
0
Datei: main.go Projekt: 0x7cc/rsc
func rewriteLen(cfg *Config, prog *cc.Prog) {
	cc.Postorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Expr:
			// Assign to len, generated by len rewrite. Change to reslice.
			if x.Op == cc.Eq && x.Left.Op == cc.Call && x.Left.Left.Op == cc.Name && x.Left.Left.Text == "len" && len(x.Left.List) > 0 {
				arg := x.Left.List[0]
				x.Left = arg
				x.Right = &cc.Expr{
					Op:   c2go.ExprSlice,
					List: []*cc.Expr{arg, nil, x.Right},
				}
				return
			}

			if (x.Op == cc.Arrow || x.Op == cc.Dot) && x.XDecl != nil {
				k := declKey(x.XDecl)
				name := cfg.Len[k]
				if name == "" {
					return
				}
				d := x.XDecl
				if d.OuterType == nil {
					fmt.Fprintf(os.Stderr, "found use of %s but missing type\n", k)
					return
				}
				t := d.OuterType
				var other *cc.Decl
				for _, dd := range t.Decls {
					if dd.Name == name {
						other = dd
						break
					}
				}
				if other == nil {
					fmt.Fprintf(os.Stderr, "found use of %s but cannot find field %s\n", k, name)
					return
				}
				left := x.Left
				x.Op = cc.Call
				x.Left = &cc.Expr{
					Op:    cc.Name,
					Text:  "len",
					XType: &cc.Type{Kind: cc.Func, Base: intType},
				}
				x.List = []*cc.Expr{
					{
						Op:    cc.Dot,
						Left:  left,
						Text:  name,
						XDecl: other,
					},
				}
			}
		}
	})

	cc.Postorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Type:
			out := x.Decls[:0]
			for _, d := range x.Decls {
				k := declKey(d)
				if cfg.Len[k] == "" && !cfg.Delete[k] {
					out = append(out, d)
				}
			}
			x.Decls = out
		}
	})
}
Beispiel #5
0
// Rewrite from C constructs to Go constructs.
func rewriteSyntax(prog *cc.Prog) {
	cc.Preorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Stmt:
			rewriteStmt(x)

		case *cc.Expr:
			switch x.Op {
			case cc.Number:
				// Rewrite char literal.
				// In general we'd need to rewrite all string and char literals
				// but these are the only forms that comes up.
				switch x.Text {
				case `'\0'`:
					x.Text = `'\x00'`
				case `'\"'`:
					x.Text = `'"'`
				}

			case cc.Paren:
				switch x.Left.Op {
				case cc.Number, cc.Name:
					fixMerge(x, x.Left)
				}

			case cc.OrEq, cc.AndEq, cc.Or, cc.Eq, cc.EqEq, cc.NotEq, cc.LtEq, cc.GtEq, cc.Lt, cc.Gt:
				cutParen(x, cc.Or, cc.And, cc.Lsh, cc.Rsh)
			}

		case *cc.Type:
			// Rewrite int f(void) to int f().
			if x.Kind == cc.Func && len(x.Decls) == 1 && x.Decls[0].Name == "" && x.Decls[0].Type.Is(cc.Void) {
				x.Decls = nil
			}
		}
	})

	// Apply changed struct tags to typedefs.
	// Excise dead pieces.
	cc.Postorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Type:
			if x.Kind == cc.TypedefType && x.Base != nil && x.Base.Tag != "" {
				x.Name = x.Base.Tag
			}

		case *cc.Stmt:
			if x.Op == cc.StmtExpr && x.Expr.Op == cc.Comma && len(x.Expr.List) == 0 {
				x.Op = cc.Empty
			}
			x.Block = filterBlock(x.Block)

		case *cc.Expr:
			if x.Op == c2go.ExprBlock {
				x.Block = filterBlock(x.Block)
			}

			switch x.Op {
			case cc.Add, cc.Sub:
				// Turn p + y - z, which is really (p + y) - z, into p + (y - z),
				// so that there is only one pointer addition (which will turn into
				// a slice operation using y-z as the index).
				if x.XType != nil && x.XType.Kind == cc.Ptr {
					switch x.Left.Op {
					case cc.Add, cc.Sub:
						if x.Left.XType != nil && x.Left.XType.Kind == cc.Ptr {
							p, op1, y, op2, z := x.Left.Left, x.Left.Op, x.Left.Right, x.Op, x.Right
							if op1 == cc.Sub {
								y = &cc.Expr{Op: cc.Minus, Left: y, XType: y.XType}
							}
							x.Op = cc.Add
							x.Left = p
							x.Right = &cc.Expr{Op: op2, Left: y, Right: z, XType: x.XType}
						}
					}
				}
			}

			// Turn c + p - q, which is really (c + p) - q, into c + (p - q),
			// so that there is no int + ptr addition, only a ptr - ptr subtraction.
			if x.Op == cc.Sub && x.Left.Op == cc.Add && !isPtrOrArray(x.XType) && isPtrOrArray(x.Left.XType) && !isPtrOrArray(x.Left.Left.XType) {
				c, p, q := x.Left.Left, x.Left.Right, x.Right
				expr := x.Left
				expr.Left = p
				expr.Right = q
				expr.Op = cc.Sub
				x.Op = cc.Add
				x.Left = c
				x.Right = expr
				expr.XType = x.XType
			}
		}
	})
}