예제 #1
0
파일: typecheck.go 프로젝트: akavel/c2go
// rewriteTypes rewrites C types appearing in the program to equivalent Go types.
func rewriteTypes(cfg *Config, prog cc.Syntax) {
	// Cache is needed to cut off translation of recursive types.
	cache := make(map[*cc.Type]*cc.Type)

	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
				}
			}
			if t.Kind == cc.Func && len(t.Decls) == 1 && t.Decls[0].Type.Is(cc.Void) {
				t.Decls = nil
			}
		}
		if d, ok := x.(*cc.Decl); ok {
			if d.Type != nil && d.Type.Kind == cc.Func {
				for _, d1 := range d.Type.Decls {
					d1.CurFn = d
				}
				if d.Body != nil {
					for _, s := range d.Body.Block {
						if s.Op == cc.StmtDecl {
							s.Decl.CurFn = d
						}
					}
				}
			}
		}
	})

	/*
		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 = Slice
				}
			}
			for _, f := range g.syntax {
				if f.ptrAdd {
					k = Slice
				}
			}
			if t.Base.Kind == cc.Char {
				g.goType = &cc.Type{Kind: String}
				continue
			}
			g.goType = &cc.Type{Kind: k, Base: toGoType(cfg, nil, nil, t.Base, cache)}
			continue
		}
	*/

	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
			}
			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(cfg, nil, d.Type.Base, cache)
				if d.Type.Width == nil {
					d.Type.Kind = Slice
				}
				return
			}
			d.Type = toGoType(cfg, d, d.Type, cache)

		case *cc.Expr:
			if x.Type != nil {
				t := toGoType(cfg, nil, x.Type, cache)
				if t == nil {
					fprintf(x.Span, "cannot convert %v to go type\n", GoString(x.Type))
				}
				x.Type = t
			}
		}
	})
}
예제 #2
0
파일: typecheck.go 프로젝트: akavel/c2go
// rewriteLen rewrites references to length/capacity fields to use len(f) and cap(f) instead.
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:   ExprSlice,
					List: []*cc.Expr{arg, nil, x.Right},
				}
				return
			}

			if x.Op == cc.Call {
				// Rewrite call with args x, len(x) to drop len(x).
				var out []*cc.Expr
				for _, arg := range x.List {
					if arg.Op == cc.Call && arg.Left.Op == cc.Name && arg.Left.Text == "len" && len(arg.List) == 1 && len(out) > 0 && arg.List[0].String() == out[len(out)-1].String() {
						continue
					}
					out = append(out, arg)
				}
				x.List = out
			}

			if (x.Op == cc.Arrow || x.Op == cc.Dot || x.Op == cc.Name) && x.XDecl != nil {
				k := declKey(x.XDecl)
				name := cfg.len[k]
				op := "len"
				if name == "" {
					name = cfg.cap[k]
					op = "cap"
					if name == "" {
						return
					}
				}
				var lenExpr *cc.Expr
				if x.Op == cc.Name {
					i := strings.Index(name, ".")
					if i >= 0 {
						name = name[i+1:]
					}
					if goKeyword[name] {
						name += "_"
					} else if cfg.rename[name] != "" {
						name = cfg.rename[name]
					}
					lenExpr = &cc.Expr{Op: cc.Name, Text: name}
				} else {
					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
					if i := strings.Index(name, "."); i >= 0 {
						name = name[i+1:]
					}
					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
					lenExpr = &cc.Expr{
						Op:    cc.Dot,
						Left:  left,
						Text:  name,
						XDecl: other,
					}
				}
				x.Op = cc.Call
				x.Left = &cc.Expr{
					Op:    cc.Name,
					Text:  op,
					XType: &cc.Type{Kind: cc.Func, Base: intType},
				}
				x.List = []*cc.Expr{lenExpr}
			}
		}
	})

	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.cap[k] == "" && !cfg.delete[k] {
					out = append(out, d)
				}
			}
			x.Decls = out
		}
	})
}
예제 #3
0
파일: syntax.go 프로젝트: akavel/c2go
// Rewrite from C constructs to Go constructs.
func rewriteSyntax(cfg *Config, prog *cc.Prog) {
	numRewrite++
	cc.Preorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Stmt:
			rewriteStmt(x)

		case *cc.Expr:
			switch x.Op {
			case cc.Name:
				switch x.Text {
				case "nil":
					x.XDecl = nil // just nil, not main.Nil
				case "nelem":
					x.Text = "len"
					x.XDecl = nil
				}
			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 == 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
			}
		}
	})
}