Example #1
0
func (v *CompileVisitor) Declare(vname string, t *ast.Type) {
	switch SizeOnStack(t) {
	case 4:
		v.Append(x86.Commented(x86.PushL(x86.Imm32(0)), "This is variable "+vname))
	case 8:
		v.Append(x86.Commented(x86.PushL(x86.Imm32(0)), "This is variable "+vname))
		v.Append(x86.Commented(x86.PushL(x86.Imm32(0)), "This is variable "+vname))
	default:
		panic(fmt.Sprintf("I don't handle variables with length %s", SizeOnStack(t)))
	}
	v.Stack.DefineVariable(vname, t)
}
Example #2
0
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))
	}
}