Improved code generation
This commit is contained in:
parent
795935ddfb
commit
4d88260333
@ -1,7 +1,7 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -9,9 +9,43 @@ import (
|
|||||||
// All call registers must hold the correct parameter values before the function invocation.
|
// All call registers must hold the correct parameter values before the function invocation.
|
||||||
// Registers that are in use must be saved if they are modified by the function.
|
// Registers that are in use must be saved if they are modified by the function.
|
||||||
// After the function call, they must be restored in reverse order.
|
// After the function call, they must be restored in reverse order.
|
||||||
func (f *Function) CompileCall(expr *expression.Expression) error {
|
func (f *Function) CompileCall(root *expression.Expression) error {
|
||||||
_, err := f.EvaluateCall(expr)
|
funcName := root.Children[0].Token.Text()
|
||||||
return err
|
parameters := root.Children[1:]
|
||||||
|
registers := f.cpu.Input[:len(parameters)]
|
||||||
|
isSyscall := funcName == "syscall"
|
||||||
|
|
||||||
|
if isSyscall {
|
||||||
|
registers = f.cpu.Syscall[:len(parameters)]
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.ExpressionsToRegisters(parameters, registers)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, register := range f.cpu.General {
|
||||||
|
if !f.cpu.IsFree(register) {
|
||||||
|
f.assembler.Register(asm.PUSH, register)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isSyscall {
|
||||||
|
f.assembler.Syscall()
|
||||||
|
} else {
|
||||||
|
f.assembler.Call(funcName)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(f.cpu.General) - 1; i >= 0; i-- {
|
||||||
|
register := f.cpu.General[i]
|
||||||
|
|
||||||
|
if !f.cpu.IsFree(register) {
|
||||||
|
f.assembler.Register(asm.POP, register)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileSyscall executes a syscall.
|
// CompileSyscall executes a syscall.
|
||||||
@ -23,17 +57,3 @@ func (f *Function) CompileSyscall(expr *expression.Expression) error {
|
|||||||
f.sideEffects++
|
f.sideEffects++
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
|
||||||
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
|
||||||
for i := len(registers) - 1; i >= 0; i-- {
|
|
||||||
f.SaveRegister(registers[i])
|
|
||||||
err := f.EvaluateTo(expressions[i], registers[i])
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -59,27 +59,6 @@ func (f *Function) AddVariable(variable *Variable) {
|
|||||||
f.cpu.Use(variable.Register)
|
f.cpu.Use(variable.Register)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) addTemporary(root *expression.Expression) *Variable {
|
|
||||||
f.count.tmps++
|
|
||||||
name := fmt.Sprintf("t%d", f.count.tmps)
|
|
||||||
register := f.cpu.MustUseFree(f.cpu.General)
|
|
||||||
|
|
||||||
tmp := &Variable{
|
|
||||||
Name: name,
|
|
||||||
Value: root,
|
|
||||||
Alive: 1,
|
|
||||||
Register: register,
|
|
||||||
}
|
|
||||||
|
|
||||||
f.variables[name] = tmp
|
|
||||||
|
|
||||||
if config.Comments {
|
|
||||||
f.assembler.Comment(fmt.Sprintf("%s = %s (%s)", name, root, register))
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Function) useVariable(variable *Variable) {
|
func (f *Function) useVariable(variable *Variable) {
|
||||||
variable.Alive--
|
variable.Alive--
|
||||||
|
|
||||||
@ -121,7 +100,7 @@ func (f *Function) storeVariableInRegister(name string, value *expression.Expres
|
|||||||
panic("no free registers")
|
panic("no free registers")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := f.EvaluateTo(value, reg)
|
err := f.ExpressionToRegister(value, reg)
|
||||||
|
|
||||||
f.AddVariable(&Variable{
|
f.AddVariable(&Variable{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@ -12,5 +12,5 @@ func (f *Function) CompileReturn(node *ast.Return) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.EvaluateTo(node.Value, f.cpu.Return[0])
|
return f.ExpressionToRegister(node.Value, f.cpu.Output[0])
|
||||||
}
|
}
|
||||||
|
@ -1,123 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.akyoto.dev/cli/q/src/build/asm"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/ast"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Evaluate evaluates the result of an expression and saves it into a temporary register.
|
|
||||||
func (f *Function) Evaluate(root *expression.Expression) (*Variable, error) {
|
|
||||||
if root.IsLeaf() {
|
|
||||||
return f.EvaluateLeaf(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ast.IsFunctionCall(root) {
|
|
||||||
return f.EvaluateCall(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
left := root.Children[0]
|
|
||||||
right := root.Children[1]
|
|
||||||
|
|
||||||
tmpLeft, err := f.Evaluate(left)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpLeftExpr := expression.NewLeaf(token.Token{
|
|
||||||
Kind: token.Identifier,
|
|
||||||
Position: left.Token.Position,
|
|
||||||
Bytes: []byte(tmpLeft.Name),
|
|
||||||
})
|
|
||||||
|
|
||||||
tmpLeftExpr.Parent = root
|
|
||||||
root.Children[0].Parent = nil
|
|
||||||
root.Children[0] = tmpLeftExpr
|
|
||||||
|
|
||||||
tmpRight, err := f.Evaluate(right)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpRightExpr := expression.NewLeaf(token.Token{
|
|
||||||
Kind: token.Identifier,
|
|
||||||
Position: left.Token.Position,
|
|
||||||
Bytes: []byte(tmpRight.Name),
|
|
||||||
})
|
|
||||||
|
|
||||||
tmpRightExpr.Parent = root
|
|
||||||
root.Children[1].Parent = nil
|
|
||||||
root.Children[1] = tmpRightExpr
|
|
||||||
|
|
||||||
tmp := f.addTemporary(root)
|
|
||||||
|
|
||||||
f.assembler.RegisterRegister(asm.MOVE, tmp.Register, tmpLeft.Register)
|
|
||||||
f.useVariable(tmpLeft)
|
|
||||||
|
|
||||||
err = f.opRegisterRegister(root.Token, tmp.Register, tmpRight.Register)
|
|
||||||
f.useVariable(tmpRight)
|
|
||||||
|
|
||||||
return tmp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Function) EvaluateCall(root *expression.Expression) (*Variable, error) {
|
|
||||||
funcName := root.Children[0].Token.Text()
|
|
||||||
parameters := root.Children[1:]
|
|
||||||
registers := f.cpu.Call[:len(parameters)]
|
|
||||||
isSyscall := funcName == "syscall"
|
|
||||||
|
|
||||||
if isSyscall {
|
|
||||||
registers = f.cpu.Syscall[:len(parameters)]
|
|
||||||
}
|
|
||||||
|
|
||||||
err := f.ExpressionsToRegisters(parameters, registers)
|
|
||||||
|
|
||||||
for _, register := range f.cpu.General {
|
|
||||||
if !f.cpu.IsFree(register) {
|
|
||||||
f.assembler.Register(asm.PUSH, register)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isSyscall {
|
|
||||||
f.assembler.Syscall()
|
|
||||||
} else {
|
|
||||||
f.assembler.Call(funcName)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := len(f.cpu.General) - 1; i >= 0; i-- {
|
|
||||||
register := f.cpu.General[i]
|
|
||||||
|
|
||||||
if !f.cpu.IsFree(register) {
|
|
||||||
f.assembler.Register(asm.POP, register)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp := f.addTemporary(root)
|
|
||||||
f.assembler.RegisterRegister(asm.MOVE, tmp.Register, f.cpu.Return[0])
|
|
||||||
return tmp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Function) EvaluateLeaf(root *expression.Expression) (*Variable, error) {
|
|
||||||
tmp := f.addTemporary(root)
|
|
||||||
err := f.TokenToRegister(root.Token, tmp.Register)
|
|
||||||
return tmp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Function) EvaluateTo(root *expression.Expression, register cpu.Register) error {
|
|
||||||
tmp, err := f.Evaluate(root)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if register != tmp.Register {
|
|
||||||
f.assembler.RegisterRegister(asm.MOVE, register, tmp.Register)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.useVariable(tmp)
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,11 +1,8 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/build/ast"
|
"git.akyoto.dev/cli/q/src/build/ast"
|
||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
"git.akyoto.dev/cli/q/src/build/errors"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
)
|
)
|
||||||
@ -16,54 +13,24 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
|
|||||||
return f.ExecuteLeaf(operation, register, value.Token)
|
return f.ExecuteLeaf(operation, register, value.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
var temporary cpu.Register
|
|
||||||
|
|
||||||
if ast.IsFunctionCall(value) {
|
if ast.IsFunctionCall(value) {
|
||||||
temporary = f.cpu.Return[0]
|
err := f.CompileCall(value)
|
||||||
} else {
|
|
||||||
found := false
|
|
||||||
temporary, found = f.cpu.FindFree(f.cpu.General)
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
panic("no free registers")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.cpu.Use(temporary)
|
|
||||||
defer f.cpu.Free(temporary)
|
|
||||||
err := f.EvaluateTo(value, temporary)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.opRegisterRegister(operation, register, temporary)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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]
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer f.useVariable(variable)
|
|
||||||
return f.opRegisterRegister(operation, register, variable.Register)
|
|
||||||
|
|
||||||
case token.Number:
|
|
||||||
value := operand.Text()
|
|
||||||
number, err := strconv.Atoi(value)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.opRegisterNumber(operation, register, number)
|
return f.ExecuteRegisterRegister(operation, register, f.cpu.Output[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New(errors.NotImplemented, f.File, operation.Position)
|
tmp := f.cpu.MustUseFree(f.cpu.General)
|
||||||
|
defer f.cpu.Free(tmp)
|
||||||
|
|
||||||
|
err := f.ExpressionToRegister(value, tmp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.ExecuteRegisterRegister(operation, register, tmp)
|
||||||
}
|
}
|
||||||
|
37
src/build/core/ExecuteLeaf.go
Normal file
37
src/build/core/ExecuteLeaf.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.useVariable(variable)
|
||||||
|
return f.ExecuteRegisterRegister(operation, register, variable.Register)
|
||||||
|
|
||||||
|
case token.Number:
|
||||||
|
value := operand.Text()
|
||||||
|
number, err := strconv.Atoi(value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.ExecuteRegisterNumber(operation, register, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New(errors.NotImplemented, f.File, operation.Position)
|
||||||
|
}
|
33
src/build/core/ExecuteRegisterNumber.go
Normal file
33
src/build/core/ExecuteRegisterNumber.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExecuteRegisterNumber performs an operation on a register and a number.
|
||||||
|
func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error {
|
||||||
|
switch operation.Text() {
|
||||||
|
case "+", "+=":
|
||||||
|
f.assembler.RegisterNumber(asm.ADD, register, number)
|
||||||
|
|
||||||
|
case "-", "-=":
|
||||||
|
f.assembler.RegisterNumber(asm.SUB, register, number)
|
||||||
|
|
||||||
|
case "*", "*=":
|
||||||
|
f.assembler.RegisterNumber(asm.MUL, register, number)
|
||||||
|
|
||||||
|
case "/", "/=":
|
||||||
|
f.assembler.RegisterNumber(asm.DIV, register, number)
|
||||||
|
|
||||||
|
case "=":
|
||||||
|
f.assembler.RegisterNumber(asm.MOVE, register, number)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
35
src/build/core/ExecuteRegisterRegister.go
Normal file
35
src/build/core/ExecuteRegisterRegister.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExecuteRegisterRegister performs an operation on two registers.
|
||||||
|
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)
|
||||||
|
|
||||||
|
case "-", "-=":
|
||||||
|
f.assembler.RegisterRegister(asm.SUB, destination, source)
|
||||||
|
|
||||||
|
case "*", "*=":
|
||||||
|
f.assembler.RegisterRegister(asm.MUL, destination, source)
|
||||||
|
|
||||||
|
case "/", "/=":
|
||||||
|
f.assembler.RegisterRegister(asm.DIV, destination, source)
|
||||||
|
|
||||||
|
case "=":
|
||||||
|
if destination != source {
|
||||||
|
f.assembler.RegisterRegister(asm.MOVE, destination, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
33
src/build/core/ExpressionToRegister.go
Normal file
33
src/build/core/ExpressionToRegister.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/ast"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExpressionToRegister puts the result of an expression into the specified register.
|
||||||
|
func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error {
|
||||||
|
if root.IsLeaf() {
|
||||||
|
return f.TokenToRegister(root.Token, register)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ast.IsFunctionCall(root) {
|
||||||
|
err := f.CompileCall(root)
|
||||||
|
f.assembler.RegisterRegister(asm.MOVE, register, f.cpu.Output[0])
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
left := root.Children[0]
|
||||||
|
right := root.Children[1]
|
||||||
|
|
||||||
|
err := f.ExpressionToRegister(left, register)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.SaveRegister(register)
|
||||||
|
return f.Execute(root.Token, register, right)
|
||||||
|
}
|
20
src/build/core/ExpressionsToRegisters.go
Normal file
20
src/build/core/ExpressionsToRegisters.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
||||||
|
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
||||||
|
for i := len(registers) - 1; i >= 0; i-- {
|
||||||
|
f.SaveRegister(registers[i])
|
||||||
|
err := f.ExpressionToRegister(expressions[i], registers[i])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -31,10 +31,10 @@ func NewFunction(name string, file *fs.File, body token.List) *Function {
|
|||||||
Instructions: make([]asm.Instruction, 0, 32),
|
Instructions: make([]asm.Instruction, 0, 32),
|
||||||
},
|
},
|
||||||
cpu: cpu.CPU{
|
cpu: cpu.CPU{
|
||||||
Call: x64.CallRegisters,
|
Input: x64.CallRegisters,
|
||||||
General: x64.GeneralRegisters,
|
General: x64.GeneralRegisters,
|
||||||
Syscall: x64.SyscallRegisters,
|
Syscall: x64.SyscallRegisters,
|
||||||
Return: x64.ReturnValueRegisters,
|
Output: x64.ReturnValueRegisters,
|
||||||
},
|
},
|
||||||
definitions: map[string]*Definition{},
|
definitions: map[string]*Definition{},
|
||||||
variables: map[string]*Variable{},
|
variables: map[string]*Variable{},
|
||||||
|
@ -18,7 +18,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
|||||||
constant, exists := f.definitions[name]
|
constant, exists := f.definitions[name]
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
return f.EvaluateTo(constant.Value, register)
|
return f.ExpressionToRegister(constant.Value, register)
|
||||||
}
|
}
|
||||||
|
|
||||||
variable, exists := f.variables[name]
|
variable, exists := f.variables[name]
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.akyoto.dev/cli/q/src/build/asm"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/errors"
|
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
// opRegisterNumber performs an operation on a register and a number.
|
|
||||||
func (f *Function) opRegisterNumber(operation token.Token, register cpu.Register, number int) error {
|
|
||||||
switch operation.Text() {
|
|
||||||
case "+", "+=":
|
|
||||||
f.assembler.RegisterNumber(asm.ADD, register, number)
|
|
||||||
|
|
||||||
case "-", "-=":
|
|
||||||
f.assembler.RegisterNumber(asm.SUB, register, number)
|
|
||||||
|
|
||||||
case "*", "*=":
|
|
||||||
f.assembler.RegisterNumber(asm.MUL, register, number)
|
|
||||||
|
|
||||||
case "/", "/=":
|
|
||||||
f.assembler.RegisterNumber(asm.DIV, register, number)
|
|
||||||
|
|
||||||
case "=":
|
|
||||||
f.assembler.RegisterNumber(asm.MOVE, register, number)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// opRegisterRegister performs an operation on two registers.
|
|
||||||
func (f *Function) opRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error {
|
|
||||||
switch operation.Text() {
|
|
||||||
case "+", "+=":
|
|
||||||
f.assembler.RegisterRegister(asm.ADD, destination, source)
|
|
||||||
|
|
||||||
case "-", "-=":
|
|
||||||
f.assembler.RegisterRegister(asm.SUB, destination, source)
|
|
||||||
|
|
||||||
case "*", "*=":
|
|
||||||
f.assembler.RegisterRegister(asm.MUL, destination, source)
|
|
||||||
|
|
||||||
case "/", "/=":
|
|
||||||
f.assembler.RegisterRegister(asm.DIV, destination, source)
|
|
||||||
|
|
||||||
case "=":
|
|
||||||
if destination != source {
|
|
||||||
f.assembler.RegisterRegister(asm.MOVE, destination, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -24,7 +24,6 @@ type state struct {
|
|||||||
// counter stores how often a certain statement appeared so we can generate a unique label from it.
|
// counter stores how often a certain statement appeared so we can generate a unique label from it.
|
||||||
type counter struct {
|
type counter struct {
|
||||||
loop int
|
loop int
|
||||||
tmps int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintInstructions shows the assembly instructions.
|
// PrintInstructions shows the assembly instructions.
|
||||||
|
@ -2,10 +2,10 @@ package cpu
|
|||||||
|
|
||||||
// CPU represents the processor.
|
// CPU represents the processor.
|
||||||
type CPU struct {
|
type CPU struct {
|
||||||
Call []Register
|
|
||||||
General []Register
|
General []Register
|
||||||
Syscall []Register
|
Syscall []Register
|
||||||
Return []Register
|
Input []Register
|
||||||
|
Output []Register
|
||||||
usage uint64
|
usage uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user