Implemented definitions
This commit is contained in:
parent
247b82b529
commit
7e5d45f17d
@ -190,6 +190,16 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
|||||||
switch t.Kind {
|
switch t.Kind {
|
||||||
case token.Identifier:
|
case token.Identifier:
|
||||||
name := t.Text()
|
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]
|
variable, exists := f.variables[name]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
|
@ -133,6 +133,18 @@ func (f *Function) Wait() {
|
|||||||
// identifierExists returns true if the identifier has been defined.
|
// identifierExists returns true if the identifier has been defined.
|
||||||
func (f *Function) identifierExists(name string) bool {
|
func (f *Function) identifierExists(name string) bool {
|
||||||
_, exists := f.variables[name]
|
_, exists := f.variables[name]
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
_, exists = f.definitions[name]
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
_, exists = f.functions[name]
|
||||||
return exists
|
return exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,18 @@ package build
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
"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 {
|
type Variable struct {
|
||||||
Name string
|
Name string
|
||||||
Register cpu.Register
|
Register cpu.Register
|
||||||
Alive int
|
Alive int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Definitions are single use expressions that don't reside in a register yet.
|
||||||
|
type Definition struct {
|
||||||
|
Name string
|
||||||
|
Value *expression.Expression
|
||||||
|
}
|
||||||
|
@ -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)
|
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 {
|
err := value.EachLeaf(func(leaf *expression.Expression) error {
|
||||||
panic("no free registers")
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
f.addVariable(&Variable{
|
if uses == 1 {
|
||||||
|
expr.RemoveChild(value)
|
||||||
|
|
||||||
|
f.definitions[name] = &Definition{
|
||||||
Name: name,
|
Name: name,
|
||||||
Register: reg,
|
Value: value,
|
||||||
Alive: uses,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return f.storeVariableInRegister(name, value, uses)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Function) addVariable(variable *Variable) {
|
func (f *Function) addVariable(variable *Variable) {
|
||||||
if config.Verbose {
|
if config.Verbose {
|
||||||
f.Logf("%s occupies %s (alive: %d)", variable.Name, variable.Register, variable.Alive)
|
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 {
|
func countIdentifier(tokens token.List, name string) int {
|
||||||
count := 0
|
count := 0
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ type compiler struct {
|
|||||||
cpu cpu.CPU
|
cpu cpu.CPU
|
||||||
debug []debug
|
debug []debug
|
||||||
err error
|
err error
|
||||||
|
definitions map[string]*Definition
|
||||||
variables map[string]*Variable
|
variables map[string]*Variable
|
||||||
functions map[string]*Function
|
functions map[string]*Function
|
||||||
sideEffects int
|
sideEffects int
|
||||||
|
@ -250,6 +250,7 @@ func scanFile(path string, functions chan<- *Function) error {
|
|||||||
Syscall: x64.SyscallRegisters,
|
Syscall: x64.SyscallRegisters,
|
||||||
Return: x64.ReturnValueRegisters,
|
Return: x64.ReturnValueRegisters,
|
||||||
},
|
},
|
||||||
|
definitions: map[string]*Definition{},
|
||||||
variables: map[string]*Variable{},
|
variables: map[string]*Variable{},
|
||||||
finished: make(chan struct{}),
|
finished: make(chan struct{}),
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user