func (v *CompileVisitor) FunctionPostlogue() { // First we roll back the stack from where we started... for v.Stack.Name == "_" { // We need to pop off any extra layers of stack we've added... if v.Stack.Size > 0 { v.Append(x86.Commented(x86.AddL(x86.Imm32(v.Stack.Size), x86.ESP), "We stored this much on the stack so far.")) } v.Stack = v.Stack.Parent // We've popped off the arguments... } // Now jump to the "real" postlogue. This is a little stupid, but I // expect it'll come in handy when I implement defer (not to mention // panic/recover). v.Append(x86.Jmp(x86.Symbol("return_" + v.Stack.Name))) }
func (v StringVisitor) Visit(n0 ast.Node) (w ast.Visitor) { //fmt.Printf("in StringVisitor, n0 is %s of type %T\n", n0, n0) if n, ok := n0.(*ast.BasicLit); ok && n != nil && n.Kind == token.STRING { str, err := strconv.Unquote(string(n.Value)) if err != nil { panic(err) } sanitize := func(rune int) int { if unicode.IsLetter(rune) { return rune } return -1 } fmt.Println("string literals are: ", v.string_literals) if _, ok := v.string_literals[str]; !ok { strname := "string_" + strings.Map(sanitize, str) for { // See if our strname is valid... nameexists := false for _, n := range v.string_literals { if n == strname { nameexists = true } } if !nameexists { break // we've got a unique name already! } strname = strname + "X" } *v.assembly = append(*v.assembly, x86.Symbol(strname), x86.Commented(x86.Ascii(str), "a non-null-terminated string")) v.string_literals[str] = strname fmt.Println("Got new string literal: ", str) } } return v }
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)) } }
func (g *GlobalVariable) InMemory() x86.Memory { return x86.Memory{x86.Symbol(g.N), nil, nil, nil} }