Example #1
0
func addFlow(cfg *Config, prog *cc.Prog) {
	for _, d := range prog.Decls {
		addFlowDecl(cfg, nil, d)
	}

	// Mop up the rest.
	cc.Preorder(prog, func(x cc.Syntax) {
		if d, ok := x.(*cc.Decl); ok {
			addFlowDecl(cfg, nil, d)
		}
	})
}
Example #2
0
func fixBools(prog *cc.Prog) {
	cc.Preorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Expr:
			if x.Op == cc.Not {
				switch x.Left.Op {
				case cc.OrOr, cc.AndAnd, cc.EqEq, cc.NotEq, cc.LtEq, cc.GtEq, cc.Lt, cc.Gt, cc.Paren:
					x.Left = negate(x.Left)
					fixMerge(x, x.Left)
				}
			}
		}
	})
}
Example #3
0
func doExports(cfg *Config, prog *cc.Prog) {
	for _, d := range cfg.TopDecls {
		if shouldExport(cfg, d.Name) {
			exportDecl(d)
		}
		pkg := d.GoPackage
		if pkg == "" {
			continue
		}
		cc.Preorder(d, func(x cc.Syntax) {
			switch x := x.(type) {
			case *cc.Expr:
				if x.Op == cc.Name && x.XDecl != nil && x.XDecl.GoPackage != "" && x.XDecl.GoPackage != pkg {
					exportDecl(x.XDecl)
				}
			case *cc.Type:
				if x.Kind == cc.TypedefType && x.TypeDecl != nil && x.TypeDecl.GoPackage != "" && x.TypeDecl.GoPackage != pkg {
					exportDecl(x.TypeDecl)
					x.Name = x.TypeDecl.Name
				}
			}
		})
	}
}
Example #4
0
func fixPrintFormat(curfn *cc.Decl, fx *cc.Expr, args []*cc.Expr) {
	for _, arg := range args {
		fixGoTypesExpr(curfn, arg, nil)
		cc.Preorder(arg, func(x cc.Syntax) {
			if x, ok := x.(*cc.Expr); ok && x.Op == cc.Name && strings.HasPrefix(x.Text, "bigP") {
				x.Text = "p"
				x.XDecl = nil
			}
		})
	}

	format, err := strconv.Unquote(fx.Texts[0])
	if err != nil {
		fprintf(fx.Span, "cannot parse quoted string: %v", err)
		return
	}

	suffix := ""

	var buf bytes.Buffer
	start := 0
	narg := 0
	for i := 0; i < len(format); i++ {
		if format[i] != '%' {
			continue
		}
		buf.WriteString(format[start:i])
		start = i
		i++
		for i < len(format) {
			c := format[i]
			switch c {
			case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '#', '-', '.', ',', ' ', 'h', 'l', 'u':
				i++
				continue
			}
			break
		}
		if i >= len(format) {
			fprintf(fx.Span, "print format ends mid-verb")
			return
		}
		flags, verb := format[start:i], format[i]
		start = i + 1

		allFlags := flags
		_ = allFlags

		flags = strings.Replace(flags, "h", "", -1)
		flags = strings.Replace(flags, "l", "", -1)
		flags = strings.Replace(flags, "u", "", -1)

		if j := strings.Index(flags, "#0"); j >= 0 && verb == 'x' {
			k := j + 2
			for k < len(flags) && '0' <= flags[k] && flags[k] <= '9' {
				k++
			}
			n, _ := strconv.Atoi(flags[j+2 : k])
			flags = flags[:j+2] + fmt.Sprint(n-2) + flags[k:]
		}

		convert := ""
		switch verb {
		default:
			fprintf(fx.Span, "unrecognized format %s%c", flags, verb)
			buf.WriteString("%")
			buf.WriteString(flags)
			buf.WriteString(string(verb))

		case 'f', 'e', 'E', 'g', 'G', 's', 'c', 'p':
			// usual meanings
			buf.WriteString(flags)
			buf.WriteString(string(verb))

		case 'x', 'X', 'o', 'd', 'b':
			// usual meanings, but force unsigned if u is given
			buf.WriteString(flags)
			buf.WriteString(string(verb))
			if narg >= len(args) || !strings.Contains(allFlags, "u") {
				break
			}
			arg := args[narg]
			if t := arg.XType.Def(); t != nil {
				switch t.Kind {
				case c2go.Int8:
					convert = "uint8"
				case c2go.Int16:
					convert = "uint16"
				case c2go.Int32:
					convert = "uint32"
				case c2go.Int64:
					convert = "uint64"
				case c2go.Int:
					convert = "uint"
				}
			}

		case 'A': // address
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
			convert = "Aconv" + suffix

		case 'L':
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
			if narg >= len(args) {
				break
			}
			arg := args[narg]
			if (arg.Op == cc.Dot || arg.Op == cc.Arrow) && arg.Text == "lineno" {
				arg.Text = "Line"
				arg.XDecl = nil
				args[narg] = &cc.Expr{Op: cc.Call, Left: arg, XType: stringType}
				break
			}
			convert = "ctxt.Line"

		case '@':
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
			convert = "RAconv" + suffix

		case 'D':
			if allFlags != "%" && allFlags != "%l" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
			if narg >= len(args) {
				break
			}
			flag := &cc.Expr{Op: cc.Name, Text: "0"}
			if strings.Contains(allFlags, "l") {
				flag.Text = "fmtLong"
			}
			arg := args[narg]
			args[narg] = &cc.Expr{
				Op:   cc.Call,
				Left: &cc.Expr{Op: cc.Name, Text: "Dconv" + suffix},
				List: []*cc.Expr{
					&cc.Expr{Op: cc.Name, Text: "p"},
					flag,
					arg,
				},
				XType: stringType,
			}

		case 'M':
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
			convert = "Mconv" + suffix

		case 'R':
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
			convert = "Rconv" + suffix

		case '$':
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%q")

		case 'P':
			if allFlags != "%" {
				fprintf(fx.Span, "format %s%c", allFlags, verb)
			}
			buf.WriteString("%v")
		}

		if convert != "" && narg < len(args) {
			arg := args[narg]
			args[narg] = &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: convert}, List: []*cc.Expr{arg}, XType: stringType}
		}

		if verb != 'r' {
			narg++
		}
	}
	buf.WriteString(format[start:])

	fx.Texts[0] = strconv.Quote(buf.String())
}
Example #5
0
func fixFormatter(fn *cc.Decl) {
	// Find va_arg assignment.
	var arg *cc.Expr
	var argType *cc.Type
	var ps []*cc.Expr
	cc.Preorder(fn.Body, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Expr:
			if x.Op == cc.Name && strings.HasPrefix(x.Text, "bigP") {
				ps = append(ps, x)
			}
		case *cc.Stmt:
			stmt := x
			if stmt.Op != cc.StmtExpr {
				return
			}
			expr := stmt.Expr
			if expr.Op != cc.Eq {
				return
			}
			if expr.Left.Op == cc.Name && strings.HasPrefix(expr.Left.Text, "bigP") {
				stmt.Op = cc.Empty
				stmt.Expr = nil
				return
			}
			if expr.Op != cc.Eq || expr.Right.Op != cc.VaArg {
				return
			}
			if arg != nil {
				fprintf(fn.Span, "multiple va_arg in formatter")
			}
			arg = expr.Left
			argType = expr.Right.Type
			stmt.Op = cc.Empty
		}
	})

	if arg == nil {
		fprintf(fn.Span, "missing va_arg in formatter")
		return
	}

	fp := fn.Type.Decls[0]
	fp.Type = stringType
	fn.Type.Decls[0] = arg.XDecl
	fn.Type.Base = stringType

	if strings.HasPrefix(fn.Name, "Dconv") && len(ps) > 0 {
		pd := &cc.Decl{Name: "p", Type: ps[0].XDecl.Type}
		fd := &cc.Decl{Name: "flag", Type: intType}
		for _, p := range ps {
			p.XDecl = pd
		}
		fn.Type.Decls = []*cc.Decl{
			pd,
			fd,
			arg.XDecl,
		}
	}

	cc.Preorder(fn.Body, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Stmt:
			if x.Op == cc.StmtDecl && x.Decl == arg.XDecl {
				x.Decl = fp
			}

			if x.Op == cc.Return && x.Expr != nil && x.Expr.Text == "0" {
				x.Expr = &cc.Expr{Op: cc.Name, Text: fp.Name, XDecl: fp}
			}

		case *cc.Expr:
			if x.Op == cc.Arrow && x.Text == "flags" {
				x.Op = cc.Name
				x.Text = "flag"
				x.XDecl = nil
				x.Left = nil
			}

			if x.Op == cc.Name {
				switch x.Text {
				case "FmtLong":
					x.Text = "fmtLong"
					x.XDecl = nil
				}
			}
		}
	})

}
Example #6
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
}
Example #7
0
// renameDecls renames file-local declarations to make them
// unique across the whole set of files being considered.
// For now, it appends the file base name to the declared name.
// Eventually it could be smarter and not do that when not necessary.
// It also renames names like 'type' and 'func' to avoid Go keywords.
func renameDecls(cfg *Config, prog *cc.Prog) {
	// Rewrite C identifiers to avoid important Go words (keywords, iota, etc).
	cc.Preorder(prog, func(x cc.Syntax) {
		switch x := x.(type) {
		case *cc.Decl:
			if k := goKeyword[x.Name]; k != "" {
				x.Name = k
			}

		case *cc.Stmt:
			for _, lab := range x.Labels {
				if k := goKeyword[lab.Name]; k != "" {
					lab.Name = k
				}
			}
			switch x.Op {
			case cc.Goto:
				if k := goKeyword[x.Text]; k != "" {
					x.Text = k
				}
			}
		}
	})

	// Build list of declared top-level names.
	// Not just prog.Decls because of enums and struct definitions.
	typedefs := map[*cc.Type]bool{}
	for _, d := range prog.Decls {
		if d.Storage&cc.Typedef != 0 {
			typedefs[d.Type] = true
		}
	}

	var decls []*cc.Decl
	for _, d := range prog.Decls {
		if d.Name == "" {
			if typedefs[d.Type] {
				continue
			}
			switch d.Type.Kind {
			case cc.Struct:
				if d.Type.Tag != "" {
					decls = append(decls, d)
					d.Name = d.Type.Tag
					d.Storage = cc.Typedef
				}
				if d.Type.TypeDecl == nil {
					d.Type.TypeDecl = d
				}
			case cc.Enum:
				d.Type.Tag = "" // enum tags are worthless
				for _, dd := range d.Type.Decls {
					decls = append(decls, dd)
				}
			}
			continue
		}
		decls = append(decls, d)
		if d.Storage&cc.Typedef != 0 && d.Type != nil && d.Type.TypeDecl == nil {
			d.Type.TypeDecl = d
		}
	}

	// Assign declarations to packages and identify conflicts.
	count := make(map[string]int)
	src := make(map[string]string)
	for _, d := range decls {
		pkg := findPkg(cfg, d.Span.Start.File)
		if pkg == "" {
			continue
		}
		d.GoPackage = pkg
		key := d.GoPackage + "." + d.Name
		if count[key]++; count[key] > 1 {
			fprintf(d.Span, "conflicting name %s in %s (last at %s)", d.Name, pkg, src[key])
			continue
		}
		src[key] = fmt.Sprintf("%s:%d", d.Span.Start.File, d.Span.Start.Line)
	}

	// Rename static, conflicting names.
	for _, d := range decls {
		key := d.GoPackage + "." + d.Name
		if count[key] > 1 {
			file := filepath.Base(d.Span.Start.File)
			if i := strings.Index(file, "."); i >= 0 {
				file = file[:i]
			}
			d.Name += "_" + file
		}
	}

	cfg.TopDecls = decls
}
Example #8
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
			}
		}
	})
}