Cleaned up function type

This commit is contained in:
Eduard Urbach 2024-06-29 11:49:32 +02:00
parent 5f2ff5e74e
commit 3e47a12ecd
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
14 changed files with 310 additions and 294 deletions

View File

@ -8,7 +8,7 @@ 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()
variable, exists := f.Variables[name] variable, exists := f.variables[name]
if !exists { if !exists {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Children[0].Token.Position) return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Children[0].Token.Position)

View File

@ -3,6 +3,7 @@ package build
import ( import (
"strconv" "strconv"
"git.akyoto.dev/cli/q/src/build/arch/x64"
"git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/expression"
@ -16,14 +17,14 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
return f.ExecuteLeaf(operation, register, value.Token) return f.ExecuteLeaf(operation, register, value.Token)
} }
temporary, found := f.CPU.FindFree(f.CPU.General) temporary, found := f.cpu.FindFree(f.cpu.General)
if !found { if !found {
panic("no free registers") panic("no free registers")
} }
f.CPU.Use(temporary) f.cpu.Use(temporary)
defer f.CPU.Free(temporary) defer f.cpu.Free(temporary)
err := f.ExpressionToRegister(value, temporary) err := f.ExpressionToRegister(value, temporary)
if err != nil { if err != nil {
@ -33,38 +34,12 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
return f.ExecuteRegisterRegister(operation, register, temporary) 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. // 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 { func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, operand token.Token) error {
switch operand.Kind { switch operand.Kind {
case token.Identifier: case token.Identifier:
name := operand.Text() name := operand.Text()
variable, exists := f.Variables[name] variable, exists := f.variables[name]
if !exists { if !exists {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position) return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
@ -91,19 +66,19 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope
func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error { func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error {
switch operation.Text() { switch operation.Text() {
case "+", "+=": case "+", "+=":
f.Assembler.RegisterNumber(asm.ADD, register, number) f.assembler.RegisterNumber(asm.ADD, register, number)
case "-", "-=": case "-", "-=":
f.Assembler.RegisterNumber(asm.SUB, register, number) f.assembler.RegisterNumber(asm.SUB, register, number)
case "*", "*=": case "*", "*=":
f.Assembler.RegisterNumber(asm.MUL, register, number) f.assembler.RegisterNumber(asm.MUL, register, number)
case "/", "/=": case "/", "/=":
f.Assembler.RegisterNumber(asm.DIV, register, number) f.assembler.RegisterNumber(asm.DIV, register, number)
case "=": case "=":
f.Assembler.RegisterNumber(asm.MOVE, register, number) f.assembler.RegisterNumber(asm.MOVE, register, number)
default: default:
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
@ -116,20 +91,20 @@ func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Reg
func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error { func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error {
switch operation.Text() { switch operation.Text() {
case "+", "+=": case "+", "+=":
f.Assembler.RegisterRegister(asm.ADD, destination, source) f.assembler.RegisterRegister(asm.ADD, destination, source)
case "-", "-=": case "-", "-=":
f.Assembler.RegisterRegister(asm.SUB, destination, source) f.assembler.RegisterRegister(asm.SUB, destination, source)
case "*", "*=": case "*", "*=":
f.Assembler.RegisterRegister(asm.MUL, destination, source) f.assembler.RegisterRegister(asm.MUL, destination, source)
case "/", "/=": case "/", "/=":
f.Assembler.RegisterRegister(asm.DIV, destination, source) f.assembler.RegisterRegister(asm.DIV, destination, source)
case "=": case "=":
if destination != source { if destination != source {
f.Assembler.RegisterRegister(asm.MOVE, destination, source) f.assembler.RegisterRegister(asm.MOVE, destination, source)
} }
default: default:
@ -138,3 +113,103 @@ func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cp
return nil return nil
} }
// ExpressionToRegister moves the result of an expression into the given register.
func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error {
operation := root.Token
if root.IsLeaf() {
return f.TokenToRegister(operation, register)
}
left := root.Children[0]
right := root.Children[1]
err := f.ExpressionToRegister(left, register)
if err != nil {
return err
}
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 {
var destinations []cpu.Register
for i := len(expressions) - 1; i >= 0; i-- {
original := registers[i]
expression := expressions[i]
if expression.IsLeaf() {
variable, exists := f.variables[expression.Token.Text()]
if exists && variable.Register == original {
continue
}
}
register := original
save := !f.cpu.IsFree(register)
if save {
register = x64.RAX
}
err := f.ExpressionToRegister(expression, register)
if err != nil {
return err
}
if save {
destinations = append(destinations, original)
f.assembler.Register(asm.PUSH, x64.RAX)
}
}
for i := len(destinations) - 1; i >= 0; i-- {
f.assembler.Register(asm.POP, destinations[i])
}
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()
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)
}
}

View File

@ -1,18 +1,11 @@
package build package build
import ( import (
"fmt"
"strconv"
"git.akyoto.dev/cli/q/src/build/arch/x64"
"git.akyoto.dev/cli/q/src/build/asm"
"git.akyoto.dev/cli/q/src/build/config" "git.akyoto.dev/cli/q/src/build/config"
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/expression"
"git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/fs"
"git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/cli/q/src/errors" "git.akyoto.dev/cli/q/src/errors"
"git.akyoto.dev/go/color/ansi"
) )
// Function represents a function. // Function represents a function.
@ -20,25 +13,14 @@ type Function struct {
Name string Name string
File *fs.File File *fs.File
Body token.List Body token.List
Variables map[string]*Variable compiler
Assembler asm.Assembler
CPU cpu.CPU
Error error
count struct{ loop int }
debug []debug
} }
// Compile turns a function into machine code. // Compile turns a function into machine code.
func (f *Function) Compile() { func (f *Function) Compile() {
f.Assembler.Label(f.Name) f.assembler.Label(f.Name)
err := f.CompileTokens(f.Body) f.err = f.CompileTokens(f.Body)
f.assembler.Return()
if err != nil {
f.Error = err
return
}
f.Assembler.Return()
} }
// CompileTokens compiles a token list. // CompileTokens compiles a token list.
@ -59,13 +41,12 @@ func (f *Function) CompileTokens(body token.List) error {
continue continue
} }
if start != -1 {
instruction := body[start:i] instruction := body[start:i]
if config.Verbose { if config.Verbose {
f.debug = append(f.debug, debug{ f.debug = append(f.debug, debug{
position: len(f.Assembler.Instructions), position: len(f.assembler.Instructions),
instruction: instruction, source: instruction,
}) })
} }
@ -74,7 +55,6 @@ func (f *Function) CompileTokens(body token.List) error {
if err != nil { if err != nil {
return err return err
} }
}
start = i + 1 start = i + 1
@ -113,152 +93,21 @@ func (f *Function) CompileInstruction(line token.List) error {
defer expr.Close() defer expr.Close()
if isVariableDefinition(expr) { switch true {
case isVariableDefinition(expr):
return f.CompileVariableDefinition(expr) return f.CompileVariableDefinition(expr)
}
if isAssignment(expr) { case isAssignment(expr):
return f.CompileAssignment(expr) return f.CompileAssignment(expr)
}
if isFunctionCall(expr) { case isFunctionCall(expr):
return f.ExecuteFunctionCall(expr) return f.CompileFunctionCall(expr)
}
return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position)
}
// ExpressionToRegister moves the result of an expression into the given register.
func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error {
operation := root.Token
if root.IsLeaf() {
return f.TokenToRegister(operation, register)
}
left := root.Children[0]
right := root.Children[1]
err := f.ExpressionToRegister(left, register)
if err != nil {
return err
}
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 {
var destinations []cpu.Register
for i := len(expressions) - 1; i >= 0; i-- {
original := registers[i]
expression := expressions[i]
if expression.IsLeaf() {
variable, exists := f.Variables[expression.Token.Text()]
if exists && variable.Register == original {
continue
}
}
register := original
save := !f.CPU.IsFree(register)
if save {
register = x64.RAX
}
err := f.ExpressionToRegister(expression, register)
if err != nil {
return err
}
if save {
destinations = append(destinations, original)
f.Assembler.Register(asm.PUSH, x64.RAX)
}
}
for i := len(destinations) - 1; i >= 0; i-- {
f.Assembler.Register(asm.POP, destinations[i])
}
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()
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: default:
return errors.New(errors.InvalidExpression, f.File, t.Position) return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position)
} }
} }
// PrintAsm shows the assembly instructions.
func (f *Function) PrintAsm() {
ansi.Dim.Println("╭──────────────────────────────────────╮")
for i, x := range f.Assembler.Instructions {
instruction := f.instructionAt(i)
if instruction != nil {
ansi.Dim.Println("├──────────────────────────────────────┤")
}
ansi.Dim.Print("│ ")
if x.Mnemonic == asm.LABEL {
ansi.Yellow.Printf("%-36s", x.Data.String()+":")
} else {
ansi.Green.Printf("%-8s", x.Mnemonic.String())
if x.Data != nil {
fmt.Printf("%-28s", x.Data.String())
} else {
fmt.Printf("%-28s", "")
}
}
ansi.Dim.Print(" │\n")
}
ansi.Dim.Println("╰──────────────────────────────────────╯")
}
// String returns the function name. // String returns the function name.
func (f *Function) String() string { func (f *Function) String() string {
return f.Name return f.Name
@ -266,7 +115,7 @@ func (f *Function) String() string {
// 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]
return exists return exists
} }

17
src/build/FunctionCall.go Normal file
View File

@ -0,0 +1,17 @@
package build
import "git.akyoto.dev/cli/q/src/build/expression"
// CompileFunctionCall executes a function call.
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
funcName := expr.Children[0].Token.Text()
parameters := expr.Children[1:]
if funcName == "syscall" {
defer f.assembler.Syscall()
return f.ExpressionsToRegisters(parameters, f.cpu.Syscall)
}
defer f.assembler.Call(funcName)
return f.ExpressionsToRegisters(parameters, f.cpu.Call)
}

View File

@ -1,46 +1,20 @@
package build package build
import ( import (
"fmt"
"git.akyoto.dev/cli/q/src/build/expression"
"git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/cli/q/src/errors" "git.akyoto.dev/cli/q/src/errors"
) )
// CompileKeyword compiles an instruction that starts with a keyword. // CompileKeyword compiles an instruction that starts with a keyword.
func (f *Function) CompileKeyword(line token.List) error { func (f *Function) CompileKeyword(tokens token.List) error {
switch line[0].Text() { switch tokens[0].Text() {
case "return": case "return":
if len(line) > 1 { return f.CompileReturn(tokens)
value := expression.Parse(line[1:])
defer value.Close()
// TODO: Set the return value
}
f.Assembler.Return()
case "loop": case "loop":
blockStart := line.IndexKind(token.BlockStart) + 1 return f.CompileLoop(tokens)
blockEnd := line.LastIndexKind(token.BlockEnd)
if blockStart == -1 {
return errors.New(errors.MissingBlockStart, f.File, line[0].End())
}
if blockEnd == -1 {
return errors.New(errors.MissingBlockEnd, f.File, line[len(line)-1].End())
}
loop := fmt.Sprintf("%s_loop_%d", f.Name, f.count.loop)
f.Assembler.Label(loop)
defer f.Assembler.Jump(loop)
f.count.loop++
return f.CompileTokens(line[blockStart:blockEnd])
default: default:
return errors.New(&errors.KeywordNotImplemented{Keyword: line[0].Text()}, f.File, line[0].Position) return errors.New(&errors.KeywordNotImplemented{Keyword: tokens[0].Text()}, f.File, tokens[0].Position)
} }
return nil
} }

28
src/build/Loop.go Normal file
View File

@ -0,0 +1,28 @@
package build
import (
"fmt"
"git.akyoto.dev/cli/q/src/build/token"
"git.akyoto.dev/cli/q/src/errors"
)
// CompileLoop compiles a loop instruction.
func (f *Function) CompileLoop(tokens token.List) error {
blockStart := tokens.IndexKind(token.BlockStart) + 1
blockEnd := tokens.LastIndexKind(token.BlockEnd)
if blockStart == -1 {
return errors.New(errors.MissingBlockStart, f.File, tokens[0].End())
}
if blockEnd == -1 {
return errors.New(errors.MissingBlockEnd, f.File, tokens[len(tokens)-1].End())
}
loop := fmt.Sprintf("%s_loop_%d", f.Name, f.count.loop)
f.assembler.Label(loop)
defer f.assembler.Jump(loop)
f.count.loop++
return f.CompileTokens(tokens[blockStart:blockEnd])
}

View File

@ -31,7 +31,7 @@ func (r *Result) Finalize() ([]byte, []byte) {
// This will place the main function immediately after the entry point // This will place the main function immediately after the entry point
// and also add everything the main function calls recursively. // and also add everything the main function calls recursively.
r.EachFunction(r.Main, map[*Function]bool{}, func(f *Function) { r.EachFunction(r.Main, map[*Function]bool{}, func(f *Function) {
final.Merge(f.Assembler) final.Merge(f.assembler)
}) })
code, data := final.Finalize() code, data := final.Finalize()
@ -44,7 +44,7 @@ func (r *Result) EachFunction(caller *Function, traversed map[*Function]bool, ca
call(caller) call(caller)
traversed[caller] = true traversed[caller] = true
for _, x := range caller.Assembler.Instructions { for _, x := range caller.assembler.Instructions {
if x.Mnemonic != asm.CALL { if x.Mnemonic != asm.CALL {
continue continue
} }

18
src/build/Return.go Normal file
View File

@ -0,0 +1,18 @@
package build
import (
"git.akyoto.dev/cli/q/src/build/expression"
"git.akyoto.dev/cli/q/src/build/token"
)
// CompileReturn compiles a return instruction.
func (f *Function) CompileReturn(tokens token.List) error {
if len(tokens) > 1 {
value := expression.Parse(tokens[1:])
defer value.Close()
// TODO: Set the return value
}
f.assembler.Return()
return nil
}

View File

@ -18,7 +18,7 @@ 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)
} }
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")
@ -42,8 +42,8 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error
func (f *Function) addVariable(variable *Variable) { func (f *Function) addVariable(variable *Variable) {
variable.UsesRemaining = countIdentifier(f.Body, variable.Name) variable.UsesRemaining = countIdentifier(f.Body, variable.Name)
f.Variables[variable.Name] = variable f.variables[variable.Name] = variable
f.CPU.Use(variable.Register) f.cpu.Use(variable.Register)
} }
func (f *Function) useVariable(variable *Variable) { func (f *Function) useVariable(variable *Variable) {
@ -54,7 +54,7 @@ func (f *Function) useVariable(variable *Variable) {
} }
if variable.UsesRemaining == 0 { if variable.UsesRemaining == 0 {
f.CPU.Free(variable.Register) f.cpu.Free(variable.Register)
} }
} }

View File

@ -34,11 +34,11 @@ func compile(functions <-chan *Function, errs <-chan error) (Result, error) {
compileFunctions(allFunctions) compileFunctions(allFunctions)
for _, function := range allFunctions { for _, function := range allFunctions {
if function.Error != nil { if function.err != nil {
return result, function.Error return result, function.err
} }
result.InstructionCount += len(function.Assembler.Instructions) result.InstructionCount += len(function.assembler.Instructions)
} }
main, exists := allFunctions["main"] main, exists := allFunctions["main"]

77
src/build/compiler.go Normal file
View File

@ -0,0 +1,77 @@
package build
import (
"fmt"
"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/go/color/ansi"
)
// compiler is the data structure we embed in each function to preserve compilation state.
type compiler struct {
assembler asm.Assembler
count counter
cpu cpu.CPU
debug []debug
err error
variables map[string]*Variable
}
// counter stores how often a certain statement appeared so we can generate a unique label from it.
type counter struct {
loop int
}
// debug is used to look up the source code at the given position.
type debug struct {
position int
source token.List
}
// PrintInstructions shows the assembly instructions.
func (c *compiler) PrintInstructions() {
ansi.Dim.Println("╭──────────────────────────────────────╮")
for i, x := range c.assembler.Instructions {
instruction := c.sourceAt(i)
if instruction != nil {
ansi.Dim.Println("├──────────────────────────────────────┤")
}
ansi.Dim.Print("│ ")
if x.Mnemonic == asm.LABEL {
ansi.Yellow.Printf("%-36s", x.Data.String()+":")
} else {
ansi.Green.Printf("%-8s", x.Mnemonic.String())
if x.Data != nil {
fmt.Printf("%-28s", x.Data.String())
} else {
fmt.Printf("%-28s", "")
}
}
ansi.Dim.Print(" │\n")
}
ansi.Dim.Println("╰──────────────────────────────────────╯")
}
// sourceAt retrieves the source code at the given position or `nil`.
func (c *compiler) sourceAt(position int) token.List {
for _, record := range c.debug {
if record.position == position {
return record.source
}
if record.position > position {
return nil
}
}
return nil
}

View File

@ -1,24 +0,0 @@
package build
import "git.akyoto.dev/cli/q/src/build/token"
// debug is used to look up instructions at a certain index.
type debug struct {
position int
instruction token.List
}
// instructionAt retrieves the instruction at the given index.
func (f *Function) instructionAt(index int) token.List {
for _, record := range f.debug {
if record.position == index {
return record.instruction
}
if record.position > index {
return nil
}
}
return nil
}

View File

@ -240,15 +240,17 @@ func scanFile(path string, functions chan<- *Function) error {
Name: tokens[nameStart].Text(), Name: tokens[nameStart].Text(),
File: file, File: file,
Body: tokens[bodyStart:i], Body: tokens[bodyStart:i],
Variables: map[string]*Variable{}, compiler: compiler{
CPU: cpu.CPU{ assembler: asm.Assembler{
Instructions: make([]asm.Instruction, 0, 32),
},
cpu: cpu.CPU{
Call: x64.CallRegisters, Call: x64.CallRegisters,
General: x64.GeneralRegisters, General: x64.GeneralRegisters,
Syscall: x64.SyscallRegisters, Syscall: x64.SyscallRegisters,
Return: x64.ReturnValueRegisters, Return: x64.ReturnValueRegisters,
}, },
Assembler: asm.Assembler{ variables: map[string]*Variable{},
Instructions: make([]asm.Instruction, 0, 32),
}, },
} }
@ -257,7 +259,7 @@ func scanFile(path string, functions chan<- *Function) error {
err := expression.EachParameter(parameters, func(tokens token.List) error { err := expression.EachParameter(parameters, func(tokens token.List) error {
if len(tokens) == 1 { if len(tokens) == 1 {
name := tokens[0].Text() name := tokens[0].Text()
register := x64.CallRegisters[len(function.Variables)] register := x64.CallRegisters[len(function.variables)]
variable := &Variable{Name: name, Register: register} variable := &Variable{Name: name, Register: register}
function.addVariable(variable) function.addVariable(variable)
return nil return nil

View File

@ -45,7 +45,7 @@ func Build(args []string) int {
if config.Verbose { if config.Verbose {
result.EachFunction(result.Main, map[*build.Function]bool{}, func(f *build.Function) { result.EachFunction(result.Main, map[*build.Function]bool{}, func(f *build.Function) {
f.PrintAsm() f.PrintInstructions()
}) })
} }