// PopTo returns code to save data from the stack into the variable. // It also changes the stack size accordingly. func (s *Stack) PopTo(name string) x86.X86 { v := s.Lookup(name) off := SizeOnStack(v.Type()) if TypeToSize(v.Type()) != off { panic("I can't yet handle types with sizes that aren't a multiple of 4") } comment := "Popping to variable " + v.Name() if v.Name() == "_" { comment = fmt.Sprint("Popping to ", name, " of type ", PrettyType(v.Type()), " at ", v.InMemory()) } code := []x86.X86{x86.Comment(s.PrettyComments())} switch off { case 4: s.Size -= off vnew := s.Lookup(name) // Its location relative to stack may have changed! return x86.RawAssembly(x86.Assembly([]x86.X86{ x86.PopL(x86.EAX), x86.Commented(x86.MovL(x86.EAX, vnew.InMemory()), comment), })) case 8: s.Size -= 4 vnew := s.Lookup(name) // Its location relative to stack may have changed! code = append(code, x86.PopL(x86.EAX), x86.Commented(x86.MovL(x86.EAX, vnew.InMemory()), comment)) s.Size -= 4 vnew = s.Lookup(name) // Its location relative to stack may have changed again! code = append(code, x86.PopL(x86.EAX), x86.Commented(x86.MovL(x86.EAX, vnew.InMemory().Add(4)), comment)) return x86.RawAssembly(x86.Assembly(code)) default: panic(fmt.Sprintf("I don't pop variables with length %s", SizeOnStack(v.Type()))) } panic("This can't happen") }
func (v *CompileVisitor) CompileExpression(exp ast.Expr) { switch e := exp.(type) { case *ast.BasicLit: switch e.Kind { case token.STRING: str, err := strconv.Unquote(string(e.Value)) if err != nil { panic(err) } n, ok := v.string_literals[str] if !ok { panic(fmt.Sprintf("I don't recognize the string: %s", string(e.Value))) } v.Append( x86.Commented(x86.PushL(x86.Symbol(n)), "Pushing string literal "+string(e.Value)), x86.PushL(x86.Imm32(len(str)))) v.Stack.Push(StringType) // let the stack know we've pushed a literal default: panic(fmt.Sprintf("I don't know how to deal with literal: %s", e)) } case *ast.CallExpr: if fn, ok := e.Fun.(*ast.Ident); ok { pos := myfiles.Position(fn.Pos()) switch fn.Name { case "println", "print": if len(e.Args) != 1 { panic(fmt.Sprintf("%s expects just one argument, not %d", fn.Name, len(e.Args))) } argtype := ExprType(e.Args[0], v.Stack) if argtype.N != ast.String || argtype.Form != ast.Basic { panic(fmt.Sprintf("Argument to %s has type %s but should have type string!", fn.Name, argtype)) } v.Stack = v.Stack.New("arguments") v.CompileExpression(e.Args[0]) v.Append(x86.Commented(x86.Call(x86.Symbol(fn.Name)), fmt.Sprint(pos.Filename, ": line ", pos.Line))) v.Stack = v.Stack.Parent // A hack to let the callee clean up arguments default: // This must not be a built-in function... functype := v.Stack.Lookup(fn.Name) if functype.Type().Form != ast.Function { panic("Function " + fn.Name + " is not actually a function!") } for i := 0; i < int(functype.Type().N); i++ { // Put zeros on the stack for the return values (and define these things) v.Declare(functype.Type().Params.Objects[i].Name, functype.Type().Params.Objects[i].Type) } v.Stack = v.Stack.New("arguments") for i := len(e.Args) - 1; i >= 0; i-- { v.CompileExpression(e.Args[i]) } // FIXME: I assume here that there is no return value! v.Append(x86.Commented(x86.Call(x86.Symbol("main_"+fn.Name)), fmt.Sprint(pos.Filename, ": line ", pos.Line))) v.Stack = v.Stack.Parent // A hack to let the callee clean up arguments } } else { panic(fmt.Sprintf("I don't know how to deal with complicated function: %s", e.Fun)) } case *ast.Ident: evar := v.Stack.Lookup(e.Name) switch SizeOnStack(evar.Type()) { case 4: v.Append(x86.Commented(x86.MovL(evar.InMemory(), x86.EAX), "Reading variable "+e.Name)) v.Append(x86.PushL(x86.EAX)) v.Stack.DefineVariable("_copy_of_"+e.Name, evar.Type()) case 8: v.Append(x86.Comment(fmt.Sprintf("The offset of %s is %s", e.Name, evar.InMemory()))) v.Append(x86.Commented(x86.MovL(evar.InMemory().Add(4), x86.EAX), "Reading variable "+e.Name)) v.Append(x86.MovL(evar.InMemory(), x86.EBX)) v.Append(x86.PushL(x86.EAX)) v.Append(x86.PushL(x86.EBX)) v.Stack.DefineVariable("_copy_of_"+e.Name, evar.Type()) default: panic(fmt.Sprintf("I don't handle variables with length %s", SizeOnStack(evar.Type()))) } default: panic(fmt.Sprintf("I can't handle expressions such as: %T value %s", exp, exp)) } }