예제 #1
0
파일: typecheck.go 프로젝트: akavel/c2go
func fixGoTypesStmt(prog *cc.Prog, fn *cc.Decl, x *cc.Stmt) {
	if x == nil {
		return
	}

	fixArrayStmt(fn, x)
	fixFormatStmt(fn, x)

	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)
	}
}
예제 #2
0
파일: array.go 프로젝트: akavel/c2go
func fixArrayStmt(fn *cc.Decl, x *cc.Stmt) {
	// Turn call to arrayfree into empty statement.
	// This is the only statment-level operation.
	// All other rewrites are done at the expression level
	// (or pseudo-expression, since assignments count as
	// expressions in our representation).
	if x.Op == cc.StmtExpr && isCall(x.Expr, "arrayfree") {
		x.Op = cc.Empty
		x.Expr = nil
	}
}
예제 #3
0
파일: syntax.go 프로젝트: akavel/c2go
// fixAndAndAssign rewrites if(x && (y = z) ...) ...  to if(x) { y = z; if(...) ... }
func fixAndAndAssign(stmt *cc.Stmt) {
	changed := false
	clauses := splitExpr(stmt.Expr, cc.AndAnd)
	for i := len(clauses) - 1; i > 0; i-- {
		before, _ := extractSideEffects(clauses[i], sideNoAfter)
		if len(before) == 0 {
			continue
		}
		changed = true
		stmt.Body = &cc.Stmt{
			Op: BlockNoBrace,
			Block: append(before, &cc.Stmt{
				Op:   cc.If,
				Expr: joinExpr(clauses[i:], cc.AndAnd),
				Body: stmt.Body,
			}),
		}
		clauses = clauses[:i]
	}
	if changed {
		stmt.Expr = joinExpr(clauses, cc.AndAnd)
	}
}
예제 #4
0
파일: typecheck.go 프로젝트: akavel/c2go
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(Byte) && !objType.Base.Is(Uint8) {
			// fprintf(x.Span, "unsupported %v - wrong size form for non-byte type", x)
			return
		}
	}

	if objType == nil {
		fprintf(x.Span, "unsupported %v - lost 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
}
예제 #5
0
파일: syntax.go 프로젝트: akavel/c2go
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 = 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: ExprBlock, Block: all}
		}

	case cc.If, cc.Return:
		if stmt.Op == cc.If && stmt.Else == nil {
			fixAndAndAssign(stmt)
		}
		before, _ := extractSideEffects(stmt.Expr, sideNoAfter)
		if len(before) > 0 {
			old := copyStmt(stmt)
			stmt.Expr = nil
			stmt.Body = nil
			stmt.Else = nil
			stmt.Op = 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 = 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)
		if len(before) > 0 {
			old := copyStmt(stmt)
			stmt.Expr = nil
			stmt.Body = nil
			stmt.Else = nil
			stmt.Op = BlockNoBrace
			stmt.Block = append(before, old)
			break // recursion will rewrite new inner switch
		}
		rewriteSwitch(stmt)
	}
}