diff --git a/examples/hello/hello.q b/examples/hello/hello.q index 6c3365a..8754a01 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -1,7 +1,7 @@ main() { write := 1 - exit := 60 stdout := 1 + exit := 60 syscall(write, stdout, 4194305, 3) syscall(exit, 0) diff --git a/src/build/Function.go b/src/build/Function.go index 83367de..5fb3f25 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -33,7 +33,8 @@ func (f *Function) Compile() { } if config.Verbose { - fmt.Println("[line]", line) + ansi.Dim.Print("[ ] ") + fmt.Println(line) } err := f.compileInstruction(line) @@ -45,6 +46,19 @@ func (f *Function) Compile() { } f.Assembler.Return() + + if config.Verbose { + for _, x := range f.Assembler.Instructions { + ansi.Dim.Print("[asm] ") + fmt.Print(x.Mnemonic.String()) + + if x.Data != nil { + fmt.Print(" " + x.Data.String()) + } + + fmt.Print("\n") + } + } } // compileInstruction compiles a single instruction. @@ -57,12 +71,13 @@ func (f *Function) compileInstruction(line token.List) error { } case token.Identifier: - if len(line) >= 2 && line[1].Kind == token.Operator && line[1].Text() == ":=" { + if len(line) >= 2 && line[1].Kind == token.Define { name := line[0].Text() value := line[2:] if config.Verbose { - fmt.Println("[variable]", name, value) + ansi.Dim.Printf("[var] ") + fmt.Println(name, value) } f.Variables[name] = &Variable{ diff --git a/src/build/asm/Assembler.go b/src/build/asm/Assembler.go index 01379f9..d0186e7 100644 --- a/src/build/asm/Assembler.go +++ b/src/build/asm/Assembler.go @@ -2,7 +2,6 @@ package asm import ( "encoding/binary" - "fmt" "git.akyoto.dev/cli/q/src/build/arch/x64" "git.akyoto.dev/cli/q/src/build/config" @@ -29,12 +28,12 @@ func (a *Assembler) Finalize() ([]byte, []byte) { for _, x := range a.Instructions { switch x.Mnemonic { case MOVE: - code = x64.MoveRegNum32(code, uint8(x.Data.(RegisterNumber).Register), uint32(x.Data.(RegisterNumber).Number)) + code = x64.MoveRegNum32(code, uint8(x.Data.(*RegisterNumber).Register), uint32(x.Data.(*RegisterNumber).Number)) - if x.Data.(RegisterNumber).IsPointer { + if x.Data.(*RegisterNumber).IsPointer { pointers = append(pointers, Pointer{ Position: Address(len(code) - 4), - Address: Address(x.Data.(RegisterNumber).Number), + Address: Address(x.Data.(*RegisterNumber).Number), }) } @@ -49,12 +48,6 @@ func (a *Assembler) Finalize() ([]byte, []byte) { } } - if config.Verbose { - for _, x := range a.Instructions { - fmt.Println("[asm]", x.String()) - } - } - dataStart := config.BaseAddress + config.CodeOffset + Address(len(code)) for _, pointer := range pointers { diff --git a/src/build/asm/Instruction.go b/src/build/asm/Instruction.go index 966ce75..5b2bbce 100644 --- a/src/build/asm/Instruction.go +++ b/src/build/asm/Instruction.go @@ -5,15 +5,5 @@ import "fmt" // Instruction represents a single instruction which can be converted to machine code. type Instruction struct { Mnemonic Mnemonic - Data interface{} -} - -// String returns a human readable version. -func (x *Instruction) String() string { - switch data := x.Data.(type) { - case RegisterNumber: - return fmt.Sprintf("%s %s, %x", x.Mnemonic, data.Register, data.Number) - default: - return x.Mnemonic.String() - } + Data fmt.Stringer } diff --git a/src/build/asm/Instructions.go b/src/build/asm/Instructions.go index f201af9..de5f5d8 100644 --- a/src/build/asm/Instructions.go +++ b/src/build/asm/Instructions.go @@ -6,7 +6,7 @@ import "git.akyoto.dev/cli/q/src/build/cpu" func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: MOVE, - Data: RegisterNumber{ + Data: &RegisterNumber{ Register: reg, Number: number, IsPointer: false, @@ -18,7 +18,7 @@ func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) { func (a *Assembler) MoveRegisterAddress(reg cpu.Register, address Address) { a.Instructions = append(a.Instructions, Instruction{ Mnemonic: MOVE, - Data: RegisterNumber{ + Data: &RegisterNumber{ Register: reg, Number: uint64(address), IsPointer: true, diff --git a/src/build/asm/RegisterNumber.go b/src/build/asm/RegisterNumber.go index 445acd1..bfd7321 100644 --- a/src/build/asm/RegisterNumber.go +++ b/src/build/asm/RegisterNumber.go @@ -1,6 +1,10 @@ package asm -import "git.akyoto.dev/cli/q/src/build/cpu" +import ( + "fmt" + + "git.akyoto.dev/cli/q/src/build/cpu" +) // RegisterNumber operates with a register and a number. type RegisterNumber struct { @@ -8,3 +12,8 @@ type RegisterNumber struct { Number uint64 IsPointer bool } + +// String returns a human readable version. +func (data *RegisterNumber) String() string { + return fmt.Sprintf("%s, %x", data.Register, data.Number) +} diff --git a/src/build/token/Kind.go b/src/build/token/Kind.go index b221442..f7b8e80 100644 --- a/src/build/token/Kind.go +++ b/src/build/token/Kind.go @@ -25,6 +25,9 @@ const ( // Number represents a series of numerical characters. Number + // Define represents the assignment operator `:=` for a new variable. + Define + // Operator represents a mathematical operator. Operator @@ -63,6 +66,7 @@ func (kind Kind) String() string { "Keyword", "String", "Number", + "Define", "Operator", "Separator", "Comment", diff --git a/src/build/token/List.go b/src/build/token/List.go index be3a1ff..30f344b 100644 --- a/src/build/token/List.go +++ b/src/build/token/List.go @@ -13,7 +13,7 @@ func (list List) String() string { var last Token for _, t := range list { - if last.Kind == Keyword || last.Kind == Separator || last.Kind == Operator || t.Kind == Operator { + if last.Kind == Keyword || last.Kind == Separator || last.Kind == Define || t.Kind == Define { builder.WriteByte(' ') } diff --git a/src/build/token/Tokenize.go b/src/build/token/Tokenize.go index ac5d8b0..c89ddba 100644 --- a/src/build/token/Tokenize.go +++ b/src/build/token/Tokenize.go @@ -1,5 +1,7 @@ package token +import "bytes" + // Pre-allocate these byte buffers so we can re-use them // instead of allocating a new buffer every time. var ( @@ -10,6 +12,7 @@ var ( arrayStartBytes = []byte{'['} arrayEndBytes = []byte{']'} separatorBytes = []byte{','} + defineBytes = []byte{':', '='} newLineBytes = []byte{'\n'} ) @@ -38,12 +41,7 @@ func Tokenize(buffer []byte) List { i++ } - tokens = append(tokens, Token{ - String, - start, - buffer[start:end], - }) - + tokens = append(tokens, Token{String, start, buffer[start:end]}) continue // Parentheses start @@ -88,11 +86,7 @@ func Tokenize(buffer []byte) List { i++ } - token := Token{ - Identifier, - position, - buffer[position:i], - } + token := Token{Identifier, position, buffer[position:i]} if Keywords[string(token.Bytes)] { token.Kind = Keyword @@ -111,12 +105,7 @@ func Tokenize(buffer []byte) List { i++ } - tokens = append(tokens, Token{ - Number, - position, - buffer[position:i], - }) - + tokens = append(tokens, Token{Number, position, buffer[position:i]}) continue } @@ -129,12 +118,12 @@ func Tokenize(buffer []byte) List { i++ } - tokens = append(tokens, Token{ - Operator, - position, - buffer[position:i], - }) + if bytes.Equal(buffer[position:i], defineBytes) { + tokens = append(tokens, Token{Define, position, defineBytes}) + continue + } + tokens = append(tokens, Token{Operator, position, buffer[position:i]}) continue } }