Simplified code

This commit is contained in:
Eduard Urbach 2024-07-23 22:14:23 +02:00
parent 69245caf62
commit 26214366e3
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
30 changed files with 105 additions and 69 deletions

View File

@ -31,16 +31,16 @@ func (f *Function) Compare(comparison *expression.Expression) error {
return err return err
} }
return f.Execute(comparison.Token, f.CPU.Output[0], right) return f.ExecuteLeaf(comparison.Token, f.CPU.Output[0], right.Token)
} }
tmp := f.CurrentScope().MustFindFree(f.CPU.General) tmp := f.NewRegister()
err := f.ExpressionToRegister(left, tmp) err := f.ExpressionToRegister(left, tmp)
if err != nil { if err != nil {
return err return err
} }
defer f.CurrentScope().Free(tmp) defer f.FreeRegister(tmp)
return f.Execute(comparison.Token, tmp, right) return f.Execute(comparison.Token, tmp, right)
} }

View File

@ -11,8 +11,8 @@ import (
// 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(root *expression.Expression) error { func (f *Function) CompileCall(root *expression.Expression) error {
funcNameRoot := root.Children[0]
funcName := "" funcName := ""
funcNameRoot := root.Children[0]
if funcNameRoot.IsLeaf() { if funcNameRoot.IsLeaf() {
funcName = funcNameRoot.Token.Text(f.File.Bytes) funcName = funcNameRoot.Token.Text(f.File.Bytes)
@ -47,7 +47,7 @@ func (f *Function) CompileCall(root *expression.Expression) error {
// Push // Push
for _, register := range f.CPU.General { for _, register := range f.CPU.General {
if f.CurrentScope().IsUsed(register) { if f.RegisterIsUsed(register) {
f.Register(asm.PUSH, register) f.Register(asm.PUSH, register)
} }
} }
@ -59,19 +59,20 @@ func (f *Function) CompileCall(root *expression.Expression) error {
f.Call(funcName) f.Call(funcName)
} }
// Free parameter registers
for _, register := range registers { for _, register := range registers {
if register == f.CPU.Output[0] && root.Parent != nil { if register == f.CPU.Output[0] && root.Parent != nil {
continue continue
} }
f.CurrentScope().Free(register) f.FreeRegister(register)
} }
// Pop // Pop
for i := len(f.CPU.General) - 1; i >= 0; i-- { for i := len(f.CPU.General) - 1; i >= 0; i-- {
register := f.CPU.General[i] register := f.CPU.General[i]
if f.CurrentScope().IsUsed(register) { if f.RegisterIsUsed(register) {
f.Register(asm.POP, register) f.Register(asm.POP, register)
} }
} }

View File

@ -21,8 +21,7 @@ func (f *Function) CompileDefinition(node *ast.Define) error {
return errors.New(&errors.UnusedVariable{Name: name}, f.File, node.Name.Position) return errors.New(&errors.UnusedVariable{Name: name}, f.File, node.Name.Position)
} }
register := f.CurrentScope().MustFindFree(f.CPU.General) register := f.NewRegister()
f.CurrentScope().Reserve(register)
err := f.ExpressionToRegister(node.Value, register) err := f.ExpressionToRegister(node.Value, register)
f.AddVariable(&scope.Variable{ f.AddVariable(&scope.Variable{

View File

@ -23,8 +23,8 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
return f.ExecuteRegisterRegister(operation, register, f.CPU.Output[0]) return f.ExecuteRegisterRegister(operation, register, f.CPU.Output[0])
} }
tmp := f.CurrentScope().MustFindFree(f.CPU.General) tmp := f.NewRegister()
defer f.CurrentScope().Free(tmp) defer f.FreeRegister(tmp)
err := f.ExpressionToRegister(value, tmp) err := f.ExpressionToRegister(value, tmp)

View File

@ -33,10 +33,9 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
final := register final := register
if f.UsesRegister(right, register) { if f.UsesRegister(right, register) {
register = f.CurrentScope().MustFindFree(f.CPU.General) register = f.NewRegister()
} }
f.CurrentScope().Reserve(register)
err := f.ExpressionToRegister(left, register) err := f.ExpressionToRegister(left, register)
if err != nil { if err != nil {
@ -47,7 +46,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
if register != final { if register != final {
f.RegisterRegister(asm.MOVE, final, register) f.RegisterRegister(asm.MOVE, final, register)
f.CurrentScope().Free(register) f.FreeRegister(register)
} }
return err return err

View File

@ -2,13 +2,13 @@ package core
import ( import (
"git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/fs"
"git.akyoto.dev/cli/q/src/build/register"
"git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/cli/q/src/build/z"
) )
// Function represents the smallest unit of code. // Function represents the smallest unit of code.
type Function struct { type Function struct {
z.Compiler register.Machine
Name string Name string
File *fs.File File *fs.File
Body []token.Token Body []token.Token

View File

@ -5,9 +5,9 @@ import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/fs"
"git.akyoto.dev/cli/q/src/build/register"
"git.akyoto.dev/cli/q/src/build/scope" "git.akyoto.dev/cli/q/src/build/scope"
"git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/cli/q/src/build/z"
) )
// NewFunction creates a new function. // NewFunction creates a new function.
@ -16,7 +16,7 @@ func NewFunction(name string, file *fs.File, body []token.Token) *Function {
Name: name, Name: name,
File: file, File: file,
Body: body, Body: body,
Compiler: z.Compiler{ Machine: register.Machine{
Assembler: asm.Assembler{ Assembler: asm.Assembler{
Instructions: make([]asm.Instruction, 0, 8), Instructions: make([]asm.Instruction, 0, 8),
}, },

View File

@ -21,8 +21,8 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position) return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
} }
f.UseVariable(variable)
f.RegisterRegister(asm.MOVE, register, variable.Register) f.RegisterRegister(asm.MOVE, register, variable.Register)
f.UseVariable(variable)
return nil return nil
case token.Number, token.Rune: case token.Number, token.Rune:

View File

@ -1,8 +1,8 @@
package z package register
import "git.akyoto.dev/cli/q/src/build/asm" import "git.akyoto.dev/cli/q/src/build/asm"
func (f *Compiler) AddLabel(label string) { func (f *Machine) AddLabel(label string) {
f.Assembler.Label(asm.LABEL, label) f.Assembler.Label(asm.LABEL, label)
f.postInstruction() f.postInstruction()
} }

View File

@ -0,0 +1,7 @@
package register
func (f *Machine) Call(label string) {
f.Assembler.Call(label)
f.UseRegister(f.CPU.Output[0])
f.postInstruction()
}

View File

@ -1,8 +1,8 @@
package z package register
import "fmt" import "fmt"
func (f *Compiler) Comment(format string, args ...any) { func (f *Machine) Comment(format string, args ...any) {
f.Assembler.Comment(fmt.Sprintf(format, args...)) f.Assembler.Comment(fmt.Sprintf(format, args...))
f.postInstruction() f.postInstruction()
} }

View File

@ -0,0 +1,8 @@
package register
import "git.akyoto.dev/cli/q/src/build/cpu"
// FreeRegister frees a register.
func (f *Machine) FreeRegister(register cpu.Register) {
f.CurrentScope().Free(register)
}

View File

@ -1,8 +1,8 @@
package z package register
import "git.akyoto.dev/cli/q/src/build/asm" import "git.akyoto.dev/cli/q/src/build/asm"
func (f *Compiler) Jump(mnemonic asm.Mnemonic, label string) { func (f *Machine) Jump(mnemonic asm.Mnemonic, label string) {
f.Assembler.Label(mnemonic, label) f.Assembler.Label(mnemonic, label)
f.postInstruction() f.postInstruction()
} }

View File

@ -1,4 +1,4 @@
package z package register
import ( import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
@ -6,8 +6,8 @@ import (
"git.akyoto.dev/cli/q/src/build/scope" "git.akyoto.dev/cli/q/src/build/scope"
) )
// Compiler is a register usage aware assembler. // Machine is a register usage aware assembler.
type Compiler struct { type Machine struct {
scope.Stack scope.Stack
Assembler asm.Assembler Assembler asm.Assembler
CPU cpu.CPU CPU cpu.CPU

View File

@ -1,8 +1,8 @@
package z package register
import "git.akyoto.dev/cli/q/src/build/asm" import "git.akyoto.dev/cli/q/src/build/asm"
func (f *Compiler) MemoryNumber(mnemonic asm.Mnemonic, a asm.Memory, b int) { func (f *Machine) MemoryNumber(mnemonic asm.Mnemonic, a asm.Memory, b int) {
f.Assembler.MemoryNumber(mnemonic, a, b) f.Assembler.MemoryNumber(mnemonic, a, b)
f.postInstruction() f.postInstruction()
} }

View File

@ -0,0 +1,10 @@
package register
import "git.akyoto.dev/cli/q/src/build/cpu"
// NewRegister reserves a register.
func (f *Machine) NewRegister() cpu.Register {
register := f.CurrentScope().MustFindFree(f.CPU.General)
f.CurrentScope().Reserve(register)
return register
}

View File

@ -1,15 +1,15 @@
package z package register
import ( import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
) )
func (f *Compiler) Register(mnemonic asm.Mnemonic, a cpu.Register) { func (f *Machine) Register(mnemonic asm.Mnemonic, a cpu.Register) {
f.Assembler.Register(mnemonic, a) f.Assembler.Register(mnemonic, a)
if mnemonic == asm.POP { if mnemonic == asm.POP {
f.CurrentScope().Use(a) f.UseRegister(a)
} }
f.postInstruction() f.postInstruction()

View File

@ -0,0 +1,8 @@
package register
import "git.akyoto.dev/cli/q/src/build/cpu"
// RegisterIsUsed reserves a register.
func (f *Machine) RegisterIsUsed(register cpu.Register) bool {
return f.CurrentScope().IsUsed(register)
}

View File

@ -1,19 +1,19 @@
package z package register
import ( import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
) )
func (f *Compiler) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label string) { func (f *Machine) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label string) {
if f.CurrentScope().IsUsed(register) && isDestructive(mnemonic) { if f.RegisterIsUsed(register) && isDestructive(mnemonic) {
f.SaveRegister(register) f.SaveRegister(register)
} }
f.Assembler.RegisterLabel(mnemonic, register, label) f.Assembler.RegisterLabel(mnemonic, register, label)
if mnemonic == asm.MOVE { if mnemonic == asm.MOVE {
f.CurrentScope().Use(register) f.UseRegister(register)
} }
f.postInstruction() f.postInstruction()

View File

@ -1,19 +1,19 @@
package z package register
import ( import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
) )
func (f *Compiler) RegisterNumber(mnemonic asm.Mnemonic, a cpu.Register, b int) { func (f *Machine) RegisterNumber(mnemonic asm.Mnemonic, a cpu.Register, b int) {
if f.CurrentScope().IsUsed(a) && isDestructive(mnemonic) { if f.RegisterIsUsed(a) && isDestructive(mnemonic) {
f.SaveRegister(a) f.SaveRegister(a)
} }
f.Assembler.RegisterNumber(mnemonic, a, b) f.Assembler.RegisterNumber(mnemonic, a, b)
if mnemonic == asm.MOVE { if mnemonic == asm.MOVE {
f.CurrentScope().Use(a) f.UseRegister(a)
} }
f.postInstruction() f.postInstruction()

View File

@ -1,23 +1,23 @@
package z package register
import ( import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
) )
func (f *Compiler) RegisterRegister(mnemonic asm.Mnemonic, a cpu.Register, b cpu.Register) { func (f *Machine) RegisterRegister(mnemonic asm.Mnemonic, a cpu.Register, b cpu.Register) {
if mnemonic == asm.MOVE && a == b { if mnemonic == asm.MOVE && a == b {
return return
} }
if f.CurrentScope().IsUsed(a) && isDestructive(mnemonic) { if f.RegisterIsUsed(a) && isDestructive(mnemonic) {
f.SaveRegister(a) f.SaveRegister(a)
} }
f.Assembler.RegisterRegister(mnemonic, a, b) f.Assembler.RegisterRegister(mnemonic, a, b)
if mnemonic == asm.MOVE { if mnemonic == asm.MOVE {
f.CurrentScope().Use(a) f.UseRegister(a)
} }
f.postInstruction() f.postInstruction()

View File

@ -1,6 +1,6 @@
package z package register
func (f *Compiler) Return() { func (f *Machine) Return() {
f.Assembler.Return() f.Assembler.Return()
f.postInstruction() f.postInstruction()
} }

View File

@ -1,4 +1,4 @@
package z package register
import ( import (
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
@ -6,8 +6,8 @@ import (
) )
// SaveRegister attempts to move a variable occupying this register to another register. // SaveRegister attempts to move a variable occupying this register to another register.
func (f *Compiler) SaveRegister(register cpu.Register) { func (f *Machine) SaveRegister(register cpu.Register) {
if !f.CurrentScope().IsUsed(register) { if !f.RegisterIsUsed(register) {
return return
} }
@ -23,8 +23,7 @@ func (f *Compiler) SaveRegister(register cpu.Register) {
return return
} }
newRegister := f.CurrentScope().MustFindFree(f.CPU.General) newRegister := f.NewRegister()
f.CurrentScope().Reserve(newRegister)
f.RegisterRegister(asm.MOVE, newRegister, register) f.RegisterRegister(asm.MOVE, newRegister, register)
variable.Register = newRegister variable.Register = newRegister
} }

View File

@ -0,0 +1,7 @@
package register
func (f *Machine) Syscall() {
f.Assembler.Syscall()
f.UseRegister(f.CPU.Output[0])
f.postInstruction()
}

View File

@ -0,0 +1,8 @@
package register
import "git.akyoto.dev/cli/q/src/build/cpu"
// Use marks a register to be currently in use.
func (f *Machine) UseRegister(register cpu.Register) {
f.CurrentScope().Use(register)
}

View File

@ -1,4 +1,4 @@
package z package register
import "git.akyoto.dev/cli/q/src/build/asm" import "git.akyoto.dev/cli/q/src/build/asm"

View File

@ -1,8 +1,8 @@
package z package register
import "git.akyoto.dev/cli/q/src/build/config" import "git.akyoto.dev/cli/q/src/build/config"
func (f *Compiler) postInstruction() { func (f *Machine) postInstruction() {
if !config.Assembler { if !config.Assembler {
return return
} }

View File

@ -1,7 +0,0 @@
package z
func (f *Compiler) Call(label string) {
f.Assembler.Call(label)
f.CurrentScope().Use(f.CPU.Output[0])
f.postInstruction()
}

View File

@ -1,7 +0,0 @@
package z
func (f *Compiler) Syscall() {
f.Assembler.Syscall()
f.CurrentScope().Use(f.CPU.Output[0])
f.postInstruction()
}

View File

@ -63,6 +63,10 @@ main() {
sys.exit(1) sys.exit(1)
} }
if inc(x) == dec(x) {
sys.exit(1)
}
if x == 0 { if x == 0 {
sys.exit(0) sys.exit(0)
} }