Implemented complex expressions

This commit is contained in:
Eduard Urbach 2024-06-26 22:51:14 +02:00
parent 988a538661
commit d1a3ffb1a5
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
7 changed files with 137 additions and 102 deletions

View File

@ -11,7 +11,10 @@ hello() {
address += 4194304 address += 4194304
address += 1 address += 1
length = 0 length = 0 + 1
length -= length
length += write + stdout
length -= length
length += 50 length += 50
length -= 20 length -= 20
length *= 10 length *= 10

View File

@ -1,9 +1,6 @@
package build package build
import ( import (
"strconv"
"git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/expression"
"git.akyoto.dev/cli/q/src/errors" "git.akyoto.dev/cli/q/src/errors"
) )
@ -11,31 +8,21 @@ import (
// CompileAssignment compiles an assignment. // CompileAssignment compiles an assignment.
func (f *Function) CompileAssignment(expr *expression.Expression) error { func (f *Function) CompileAssignment(expr *expression.Expression) error {
name := expr.Children[0].Token.Text() name := expr.Children[0].Token.Text()
register := f.Variables[name].Register variable, exists := f.Variables[name]
switch expr.Token.Text() { if !exists {
case "=": return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Children[0].Token.Position)
f.ExpressionToRegister(expr.Children[1], register)
case "+=":
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
f.Assembler.RegisterNumber(asm.ADD, register, number)
case "-=":
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
f.Assembler.RegisterNumber(asm.SUB, register, number)
case "*=":
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
f.Assembler.RegisterNumber(asm.MUL, register, number)
case "/=":
number, _ := strconv.Atoi(expr.Children[1].Token.Text())
f.Assembler.RegisterNumber(asm.DIV, register, number)
default:
return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position)
} }
return nil if expr.Token.Text() == "=" {
return f.ExpressionToRegister(expr.Children[1], variable.Register)
}
right := expr.Children[1]
if right.IsLeaf() {
return f.Calculate(variable.Register, expr.Token, right.Token)
}
return f.Execute(expr.Token, variable.Register, expr.Children[1])
} }

81
src/build/Calculate.go Normal file
View File

@ -0,0 +1,81 @@
package build
import (
"strconv"
"git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/cli/q/src/errors"
)
// Calculate performs an operation on a register with the given operand.
func (f *Function) Calculate(register cpu.Register, operation token.Token, operand token.Token) error {
switch operand.Kind {
case token.Number:
value := operand.Text()
number, err := strconv.Atoi(value)
if err != nil {
return err
}
return f.CalculateRegisterNumber(operation, register, number)
case token.Identifier:
name := operand.Text()
variable, exists := f.Variables[name]
if !exists {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
}
return f.CalculateRegisterRegister(operation, register, variable.Register)
}
return errors.New(errors.NotImplemented, f.File, operation.Position)
}
// CalculateRegisterNumber performs an operation on a register and a number.
func (f *Function) CalculateRegisterNumber(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)
default:
return errors.New(errors.NotImplemented, f.File, operation.Position)
}
return nil
}
// CalculateRegisterRegister performs an operation on two registers.
func (f *Function) CalculateRegisterRegister(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)
default:
return errors.New(errors.NotImplemented, f.File, operation.Position)
}
return nil
}

View File

@ -122,60 +122,45 @@ func (f *Function) CompileInstruction(line token.List) error {
// ExpressionToRegister moves the result of an expression into the given register. // ExpressionToRegister moves the result of an expression into the given register.
func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error { func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error {
operation := root.Token
if root.IsLeaf() { if root.IsLeaf() {
return f.TokenToRegister(root.Token, register) return f.TokenToRegister(operation, register)
} }
left := root.Children[0] left := root.Children[0]
right := root.Children[1] right := root.Children[1]
f.ExpressionToRegister(left, register) err := f.ExpressionToRegister(left, register)
if right.IsLeaf() {
value := right.Token.Text()
n, err := strconv.Atoi(value)
if err != nil { if err != nil {
return err return err
} }
switch root.Token.Text() { return f.Execute(operation, register, right)
case "+": }
f.Assembler.RegisterNumber(asm.ADD, register, n)
// Execute executes an operation on a register with a value operand.
case "-": func (f *Function) Execute(operation token.Token, register cpu.Register, value *expression.Expression) error {
f.Assembler.RegisterNumber(asm.SUB, register, n) if value.IsLeaf() {
return f.Calculate(register, operation, value.Token)
case "*": }
f.Assembler.RegisterNumber(asm.MUL, register, n)
temporary, found := f.CPU.FindFree(f.CPU.General)
case "/":
f.Assembler.RegisterNumber(asm.DIV, register, n) if !found {
panic("no free registers")
} }
return nil
} else {
temporary, _ := f.CPU.FindFree(f.CPU.General)
f.CPU.Use(temporary) f.CPU.Use(temporary)
f.ExpressionToRegister(right, temporary) defer f.CPU.Free(temporary)
f.CPU.Free(temporary) err := f.ExpressionToRegister(value, temporary)
switch root.Token.Text() { if err != nil {
case "+": return err
f.Assembler.RegisterRegister(asm.ADD, register, temporary)
case "-":
f.Assembler.RegisterRegister(asm.SUB, register, temporary)
case "*":
f.Assembler.RegisterRegister(asm.MUL, register, temporary)
case "/":
f.Assembler.RegisterRegister(asm.DIV, register, temporary)
}
} }
return errors.New(errors.NotImplemented, f.File, root.Token.Position) return f.CalculateRegisterRegister(operation, register, temporary)
} }
// TokenToRegister moves a token into a register. // TokenToRegister moves a token into a register.
@ -190,7 +175,7 @@ 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.Assembler.MoveRegisterRegister(register, variable.Register) f.Assembler.RegisterRegister(asm.MOVE, register, variable.Register)
return nil return nil
case token.Number: case token.Number:

View File

@ -2,7 +2,6 @@ package build
import ( import (
"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/errors" "git.akyoto.dev/cli/q/src/errors"
) )
@ -18,27 +17,18 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error
return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, expr.Children[0].Token.Position) return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, expr.Children[0].Token.Position)
} }
value := expr.Children[1]
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)
}
return nil
})
if err != nil {
return err
}
reg, exists := f.CPU.FindFree(f.CPU.General) reg, exists := f.CPU.FindFree(f.CPU.General)
if !exists { if !exists {
panic("no free registers") panic("no free registers")
} }
f.ExpressionToRegister(value, reg) err := f.ExpressionToRegister(expr.Children[1], reg)
if err != nil {
return err
}
f.CPU.Use(reg) f.CPU.Use(reg)
f.Variables[name] = &Variable{ f.Variables[name] = &Variable{

View File

@ -24,17 +24,6 @@ func (a *Assembler) RegisterRegister(mnemonic Mnemonic, left cpu.Register, right
}) })
} }
// MoveRegisterRegister moves a register value into another register.
func (a *Assembler) MoveRegisterRegister(destination cpu.Register, source cpu.Register) {
a.Instructions = append(a.Instructions, Instruction{
Mnemonic: MOVE,
Data: &RegisterRegister{
Destination: destination,
Source: source,
},
})
}
// Label adds a label at the current position. // Label adds a label at the current position.
func (a *Assembler) Label(name string) { func (a *Assembler) Label(name string) {
a.Instructions = append(a.Instructions, Instruction{ a.Instructions = append(a.Instructions, Instruction{

View File

@ -14,5 +14,5 @@ type RegisterNumber struct {
// String returns a human readable version. // String returns a human readable version.
func (data *RegisterNumber) String() string { func (data *RegisterNumber) String() string {
return fmt.Sprintf("%s, %Xₕ", data.Register, data.Number) return fmt.Sprintf("%s, %d", data.Register, data.Number)
} }