diff --git a/examples/hello/hello.q b/examples/hello/hello.q index ef15401..afd5576 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -1,8 +1,4 @@ main() { - hello() -} - -hello() { address := 0 length := 0 @@ -15,6 +11,7 @@ hello() { length *= 10 length /= 100 length = (0 + 50 - 20) * 10 / 100 + length = 1 loop { print(address, length) @@ -22,7 +19,7 @@ hello() { } print(address, length) { - write(1, address, length) + write(length, address, length+1) } write(fd, address, length) { diff --git a/src/build/Execute.go b/src/build/Execute.go index 84e51d6..d636bed 100644 --- a/src/build/Execute.go +++ b/src/build/Execute.go @@ -33,6 +33,32 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value * return f.ExecuteRegisterRegister(operation, register, temporary) } +// ExecuteFunctionCall executes a function call. +func (f *Function) ExecuteFunctionCall(expr *expression.Expression) error { + funcName := expr.Children[0].Token.Text() + parameters := expr.Children[1:] + + if funcName == "syscall" { + err := f.ExpressionsToRegisters(parameters, f.CPU.Syscall) + + if err != nil { + return err + } + + f.Assembler.Syscall() + } else { + err := f.ExpressionsToRegisters(parameters, f.CPU.Call) + + if err != nil { + return err + } + + f.Assembler.Call(funcName) + } + + return nil +} + // ExecuteLeaf performs an operation on a register with the given leaf operand. func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, operand token.Token) error { switch operand.Kind { diff --git a/src/build/Function.go b/src/build/Function.go index ba070c2..fadb68b 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -113,7 +113,7 @@ func (f *Function) CompileInstruction(line token.List) error { } if isFunctionCall(expr) { - return f.CompileFunctionCall(expr) + return f.ExecuteFunctionCall(expr) } return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position) @@ -139,6 +139,19 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp 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 i := len(expressions) - 1; i >= 0; i-- { + err := f.ExpressionToRegister(expressions[i], registers[i]) + + 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 { diff --git a/src/build/FunctionCall.go b/src/build/FunctionCall.go deleted file mode 100644 index 8f2c2ea..0000000 --- a/src/build/FunctionCall.go +++ /dev/null @@ -1,32 +0,0 @@ -package build - -import ( - "git.akyoto.dev/cli/q/src/build/expression" -) - -// CompileFunctionCall compiles a top-level function call. -func (f *Function) CompileFunctionCall(expr *expression.Expression) error { - funcName := expr.Children[0].Token.Text() - parameters := expr.Children[1:] - registers := f.CPU.Syscall - - if funcName != "syscall" { - registers = registers[1:] - } - - for i := len(parameters) - 1; i >= 0; i-- { - err := f.ExpressionToRegister(parameters[i], registers[i]) - - if err != nil { - return err - } - } - - if funcName == "syscall" { - f.Assembler.Syscall() - } else { - f.Assembler.Call(funcName) - } - - return nil -} diff --git a/src/build/VariableDefinition.go b/src/build/VariableDefinition.go index 270b8e1..b7ac7ca 100644 --- a/src/build/VariableDefinition.go +++ b/src/build/VariableDefinition.go @@ -29,12 +29,12 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error return err } - f.CPU.Use(reg) - - f.Variables[name] = &Variable{ + variable := &Variable{ Name: name, Register: reg, } + f.Variables[name] = variable + f.CPU.Use(reg) return nil } diff --git a/src/build/arch/x64/Registers.go b/src/build/arch/x64/Registers.go index da154af..44807c4 100644 --- a/src/build/arch/x64/Registers.go +++ b/src/build/arch/x64/Registers.go @@ -21,6 +21,9 @@ const ( R15 ) -var GeneralRegisters = []cpu.Register{RBX, RBP, R12, R13, R14, R15} -var SyscallRegisters = []cpu.Register{RAX, RDI, RSI, RDX, R10, R8, R9} -var ReturnValueRegisters = []cpu.Register{RAX, RCX, R11} +var ( + CallRegisters = []cpu.Register{RDI, RSI, RDX, RCX, R8, R9} + GeneralRegisters = []cpu.Register{RBX, RBP, R12, R13, R14, R15} + SyscallRegisters = []cpu.Register{RAX, RDI, RSI, RDX, R10, R8, R9} + ReturnValueRegisters = []cpu.Register{RAX, RCX, R11} +) diff --git a/src/build/cpu/CPU.go b/src/build/cpu/CPU.go index f6a6f9b..0092154 100644 --- a/src/build/cpu/CPU.go +++ b/src/build/cpu/CPU.go @@ -2,6 +2,7 @@ package cpu // CPU represents the processor. type CPU struct { + Call []Register General []Register Syscall []Register Return []Register diff --git a/src/build/scan.go b/src/build/scan.go index af81199..f9b7ea0 100644 --- a/src/build/scan.go +++ b/src/build/scan.go @@ -225,6 +225,7 @@ func scanFile(path string, functions chan<- *Function) error { } cpu := cpu.CPU{ + Call: x64.CallRegisters, General: x64.GeneralRegisters, Syscall: x64.SyscallRegisters, Return: x64.ReturnValueRegisters,