Beispiel #1
0
func (v *CompileVisitor) Visit(n0 ast.Node) (w ast.Visitor) {
	// The following only handles functions (not methods)
	if n, ok := n0.(*ast.FuncDecl); ok && n.Recv == nil {
		v.FunctionPrologue(n)
		for _, statement := range n.Body.List {
			v.CompileStatement(statement)
		}
		v.FunctionPostlogue()
		v.Append(x86.GlobalSymbol("return_" + n.Name.Name))
		v.Append(x86.Commented(x86.PopL(x86.EAX), "Pop the return address"))
		// Pop off function arguments...
		fmt.Println("Function", v.Stack.Name, "has stack size", v.Stack.Size)
		fmt.Println("Function", v.Stack.Name, "has return values size", v.Stack.ReturnSize)
		v.Append(x86.Commented(x86.AddL(x86.Imm32(v.Stack.Size-4-v.Stack.ReturnSize), x86.ESP),
			"Popping "+v.Stack.Name+" arguments."))
		// Then we return!
		v.Append(x86.RawAssembly("\tjmp *%eax"))
		v.Stack = v.Stack.Parent
		return nil // No need to peek inside the func declaration!
	}
	return v
}
Beispiel #2
0
func (v *CompileVisitor) FunctionPrologue(fn *ast.FuncDecl) {
	v.Stack = v.Stack.New(fn.Name.Name)
	ftype := ast.NewType(ast.Function)
	ftype.N = uint(fn.Type.Results.NumFields())
	ftype.Params = ast.NewScope(nil)
	fmt.Println("Working on function", fn.Name.Name)
	if fn.Type.Results != nil {
		resultnum := 0
		for _, resultfield := range fn.Type.Results.List {
			names := []string{"_"}
			if resultfield.Names != nil {
				names = []string{}
				for _, i := range resultfield.Names {
					names = append(names, i.Name)
				}
			}
			t := TypeExpression(resultfield.Type)
			for _, n := range names {
				ftype.Params.Insert(&ast.Object{ast.Fun, n, t, resultfield, 0})
				resultnum++
				v.Stack.DefineVariable(n, t, fmt.Sprintf("return_value_%d", resultnum))

				// The return values are actually allocated elsewhere... here
				// we just need to define the function type properly so it
				// gets called properly.
			}
		}
	}
	fmt.Println("Stack size after results is", v.Stack.Size)
	v.Stack.ReturnSize = v.Stack.Size
	// The arguments are pushed last argument first, so that eventually
	// the types of the "later" arguments can depend on the first
	// arguments, which seems nice to me.
	for pi := len(fn.Type.Params.List) - 1; pi >= 0; pi-- {
		paramfield := fn.Type.Params.List[pi]
		names := []string{"_"}
		if paramfield.Names != nil {
			names = []string{}
			for _, i := range paramfield.Names {
				names = append(names, i.Name)
			}
		}
		t := TypeExpression(paramfield.Type)
		for i := len(names) - 1; i >= 0; i-- {
			n := names[i]
			ftype.Params.Insert(&ast.Object{ast.Fun, n, t, paramfield, 0})
			v.Stack.DefineVariable(n, t)

			// The function parameters are actually allocated
			// elsewhere... here we just need to define the function type
			// properly so it gets called properly.
		}
	}
	fmt.Println("Stack size after params is", v.Stack.Size)
	v.Stack.DefineVariable("return", IntType)
	fmt.Println("Stack size after return is", v.Stack.Size)
	v.Stack = v.Stack.New("_")
	DefineGlobal(fn.Name.Name, ftype)
	// symbol for the start name
	pos := myfiles.Position(fn.Pos())
	v.Append(x86.Commented(x86.GlobalSymbol("main_"+fn.Name.Name),
		fmt.Sprint(pos.Filename, ": line ", pos.Line)))
	// If we had arguments, we'd want to swap them with the return
	// address here...
}