Implemented an abstract syntax tree
This commit is contained in:
parent
3b29d4cdee
commit
8453273d73
28 changed files with 422 additions and 315 deletions
|
@ -3,7 +3,6 @@ package build
|
|||
import (
|
||||
"strconv"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
"git.akyoto.dev/cli/q/src/build/config"
|
||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
|
@ -72,110 +71,3 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope
|
|||
|
||||
return errors.New(errors.NotImplemented, f.File, operation.Position)
|
||||
}
|
||||
|
||||
// ExpressionToRegister moves the result of an expression into the given register.
|
||||
func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error {
|
||||
if config.Verbose {
|
||||
f.Logf("%s to register %s", root, register)
|
||||
}
|
||||
|
||||
operation := root.Token
|
||||
|
||||
if root.IsLeaf() {
|
||||
return f.TokenToRegister(operation, register)
|
||||
}
|
||||
|
||||
if isFunctionCall(root) {
|
||||
err := f.CompileFunctionCall(root)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if register != f.cpu.Return[0] {
|
||||
f.assembler.RegisterRegister(asm.MOVE, register, f.cpu.Return[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
left := root.Children[0]
|
||||
right := root.Children[1]
|
||||
|
||||
err := f.ExpressionToRegister(left, register)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.SaveRegister(register)
|
||||
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 {
|
||||
for _, register := range registers {
|
||||
f.SaveRegister(register)
|
||||
}
|
||||
|
||||
for i := len(expressions) - 1; i >= 0; i-- {
|
||||
expression := expressions[i]
|
||||
register := registers[i]
|
||||
|
||||
err := f.ExpressionToRegister(expression, register)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
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 {
|
||||
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