Cleaned up function type
This commit is contained in:
parent
f870a5f1f8
commit
67b3a3d820
14 changed files with 310 additions and 294 deletions
|
@ -3,6 +3,7 @@ package build
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/arch/x64"
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
|
@ -16,14 +17,14 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
|
|||
return f.ExecuteLeaf(operation, register, value.Token)
|
||||
}
|
||||
|
||||
temporary, found := f.CPU.FindFree(f.CPU.General)
|
||||
temporary, found := f.cpu.FindFree(f.cpu.General)
|
||||
|
||||
if !found {
|
||||
panic("no free registers")
|
||||
}
|
||||
|
||||
f.CPU.Use(temporary)
|
||||
defer f.CPU.Free(temporary)
|
||||
f.cpu.Use(temporary)
|
||||
defer f.cpu.Free(temporary)
|
||||
err := f.ExpressionToRegister(value, temporary)
|
||||
|
||||
if err != nil {
|
||||
|
@ -33,38 +34,12 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
|
|||
return f.ExecuteRegisterRegister(operation, register, temporary)
|
||||
}
|
||||
|
||||
// ExecuteFunctionCall executes a function call.
|
||||
func (f *Function) ExecuteFunctionCall(expr *expression.Expression) error {
|
||||
funcName := expr.Children[0].Token.Text()
|
||||
parameters := expr.Children[1:]
|
||||
|
||||
if funcName == "syscall" {
|
||||
err := f.ExpressionsToRegisters(parameters, f.CPU.Syscall)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Assembler.Syscall()
|
||||
} else {
|
||||
err := f.ExpressionsToRegisters(parameters, f.CPU.Call)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.Assembler.Call(funcName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecuteLeaf performs an operation on a register with the given leaf operand.
|
||||
func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, operand token.Token) error {
|
||||
switch operand.Kind {
|
||||
case token.Identifier:
|
||||
name := operand.Text()
|
||||
variable, exists := f.Variables[name]
|
||||
variable, exists := f.variables[name]
|
||||
|
||||
if !exists {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
|
||||
|
@ -91,19 +66,19 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope
|
|||
func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error {
|
||||
switch operation.Text() {
|
||||
case "+", "+=":
|
||||
f.Assembler.RegisterNumber(asm.ADD, register, number)
|
||||
f.assembler.RegisterNumber(asm.ADD, register, number)
|
||||
|
||||
case "-", "-=":
|
||||
f.Assembler.RegisterNumber(asm.SUB, register, number)
|
||||
f.assembler.RegisterNumber(asm.SUB, register, number)
|
||||
|
||||
case "*", "*=":
|
||||
f.Assembler.RegisterNumber(asm.MUL, register, number)
|
||||
f.assembler.RegisterNumber(asm.MUL, register, number)
|
||||
|
||||
case "/", "/=":
|
||||
f.Assembler.RegisterNumber(asm.DIV, register, number)
|
||||
f.assembler.RegisterNumber(asm.DIV, register, number)
|
||||
|
||||
case "=":
|
||||
f.Assembler.RegisterNumber(asm.MOVE, register, number)
|
||||
f.assembler.RegisterNumber(asm.MOVE, register, number)
|
||||
|
||||
default:
|
||||
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
||||
|
@ -116,20 +91,20 @@ func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Reg
|
|||
func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error {
|
||||
switch operation.Text() {
|
||||
case "+", "+=":
|
||||
f.Assembler.RegisterRegister(asm.ADD, destination, source)
|
||||
f.assembler.RegisterRegister(asm.ADD, destination, source)
|
||||
|
||||
case "-", "-=":
|
||||
f.Assembler.RegisterRegister(asm.SUB, destination, source)
|
||||
f.assembler.RegisterRegister(asm.SUB, destination, source)
|
||||
|
||||
case "*", "*=":
|
||||
f.Assembler.RegisterRegister(asm.MUL, destination, source)
|
||||
f.assembler.RegisterRegister(asm.MUL, destination, source)
|
||||
|
||||
case "/", "/=":
|
||||
f.Assembler.RegisterRegister(asm.DIV, destination, source)
|
||||
f.assembler.RegisterRegister(asm.DIV, destination, source)
|
||||
|
||||
case "=":
|
||||
if destination != source {
|
||||
f.Assembler.RegisterRegister(asm.MOVE, destination, source)
|
||||
f.assembler.RegisterRegister(asm.MOVE, destination, source)
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -138,3 +113,103 @@ func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cp
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExpressionToRegister moves the result of an expression into the given register.
|
||||
func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error {
|
||||
operation := root.Token
|
||||
|
||||
if root.IsLeaf() {
|
||||
return f.TokenToRegister(operation, register)
|
||||
}
|
||||
|
||||
left := root.Children[0]
|
||||
right := root.Children[1]
|
||||
|
||||
err := f.ExpressionToRegister(left, register)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.Execute(operation, register, right)
|
||||
}
|
||||
|
||||
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
||||
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
||||
var destinations []cpu.Register
|
||||
|
||||
for i := len(expressions) - 1; i >= 0; i-- {
|
||||
original := registers[i]
|
||||
expression := expressions[i]
|
||||
|
||||
if expression.IsLeaf() {
|
||||
variable, exists := f.variables[expression.Token.Text()]
|
||||
|
||||
if exists && variable.Register == original {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
register := original
|
||||
save := !f.cpu.IsFree(register)
|
||||
|
||||
if save {
|
||||
register = x64.RAX
|
||||
}
|
||||
|
||||
err := f.ExpressionToRegister(expression, register)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if save {
|
||||
destinations = append(destinations, original)
|
||||
f.assembler.Register(asm.PUSH, x64.RAX)
|
||||
}
|
||||
}
|
||||
|
||||
for i := len(destinations) - 1; i >= 0; i-- {
|
||||
f.assembler.Register(asm.POP, destinations[i])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TokenToRegister moves a token into a register.
|
||||
// It only works with identifiers, numbers and strings.
|
||||
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
||||
switch t.Kind {
|
||||
case token.Identifier:
|
||||
name := t.Text()
|
||||
variable, exists := f.variables[name]
|
||||
|
||||
if !exists {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
|
||||
}
|
||||
|
||||
if register != variable.Register {
|
||||
f.assembler.RegisterRegister(asm.MOVE, register, variable.Register)
|
||||
}
|
||||
|
||||
f.useVariable(variable)
|
||||
return nil
|
||||
|
||||
case token.Number:
|
||||
value := t.Text()
|
||||
n, err := strconv.Atoi(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.assembler.RegisterNumber(asm.MOVE, register, n)
|
||||
return nil
|
||||
|
||||
case token.String:
|
||||
return errors.New(errors.NotImplemented, f.File, t.Position)
|
||||
|
||||
default:
|
||||
return errors.New(errors.InvalidExpression, f.File, t.Position)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue