Implemented definitions

This commit is contained in:
Eduard Urbach 2024-06-30 12:28:43 +02:00
parent 247b82b529
commit 7e5d45f17d
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
6 changed files with 70 additions and 14 deletions

View File

@ -190,6 +190,16 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
switch t.Kind {
case token.Identifier:
name := t.Text()
constant, exists := f.definitions[name]
if exists {
if config.Verbose {
f.Logf("constant %s = %s", constant.Name, constant.Value)
}
return f.ExpressionToRegister(constant.Value, register)
}
variable, exists := f.variables[name]
if !exists {

View File

@ -133,6 +133,18 @@ func (f *Function) Wait() {
// identifierExists returns true if the identifier has been defined.
func (f *Function) identifierExists(name string) bool {
_, exists := f.variables[name]
if exists {
return true
}
_, exists = f.definitions[name]
if exists {
return true
}
_, exists = f.functions[name]
return exists
}

View File

@ -2,11 +2,18 @@ package build
import (
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/expression"
)
// Variable represents a variable in a function.
// Variable represents a named register.
type Variable struct {
Name string
Register cpu.Register
Alive int
}
// Definitions are single use expressions that don't reside in a register yet.
type Definition struct {
Name string
Value *expression.Expression
}

View File

@ -25,27 +25,34 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error
return errors.New(&errors.UnusedVariable{Name: name}, f.File, expr.Children[0].Token.Position)
}
reg, exists := f.cpu.FindFree(f.cpu.General)
value := expr.Children[1]
if !exists {
panic("no free registers")
err := value.EachLeaf(func(leaf *expression.Expression) error {
if leaf.Token.Kind == token.Identifier && !f.identifierExists(leaf.Token.Text()) {
return errors.New(&errors.UnknownIdentifier{Name: leaf.Token.Text()}, f.File, leaf.Token.Position)
}
err := f.ExpressionToRegister(expr.Children[1], reg)
return nil
})
if err != nil {
return err
}
f.addVariable(&Variable{
if uses == 1 {
expr.RemoveChild(value)
f.definitions[name] = &Definition{
Name: name,
Register: reg,
Alive: uses,
})
Value: value,
}
return nil
}
return f.storeVariableInRegister(name, value, uses)
}
func (f *Function) addVariable(variable *Variable) {
if config.Verbose {
f.Logf("%s occupies %s (alive: %d)", variable.Name, variable.Register, variable.Alive)
@ -75,6 +82,24 @@ func (f *Function) useVariable(variable *Variable) {
}
}
func (f *Function) storeVariableInRegister(name string, value *expression.Expression, uses int) error {
reg, exists := f.cpu.FindFree(f.cpu.General)
if !exists {
panic("no free registers")
}
err := f.ExpressionToRegister(value, reg)
f.addVariable(&Variable{
Name: name,
Register: reg,
Alive: uses,
})
return err
}
func countIdentifier(tokens token.List, name string) int {
count := 0

View File

@ -16,6 +16,7 @@ type compiler struct {
cpu cpu.CPU
debug []debug
err error
definitions map[string]*Definition
variables map[string]*Variable
functions map[string]*Function
sideEffects int

View File

@ -250,6 +250,7 @@ func scanFile(path string, functions chan<- *Function) error {
Syscall: x64.SyscallRegisters,
Return: x64.ReturnValueRegisters,
},
definitions: map[string]*Definition{},
variables: map[string]*Variable{},
finished: make(chan struct{}),
},