Added define operator

This commit is contained in:
Eduard Urbach 2024-06-15 11:36:57 +02:00
parent 65791ea5a1
commit cf696a6f10
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
9 changed files with 51 additions and 51 deletions

View File

@ -1,7 +1,7 @@
main() { main() {
write := 1 write := 1
exit := 60
stdout := 1 stdout := 1
exit := 60
syscall(write, stdout, 4194305, 3) syscall(write, stdout, 4194305, 3)
syscall(exit, 0) syscall(exit, 0)

View File

@ -33,7 +33,8 @@ func (f *Function) Compile() {
} }
if config.Verbose { if config.Verbose {
fmt.Println("[line]", line) ansi.Dim.Print("[ ] ")
fmt.Println(line)
} }
err := f.compileInstruction(line) err := f.compileInstruction(line)
@ -45,6 +46,19 @@ func (f *Function) Compile() {
} }
f.Assembler.Return() 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. // compileInstruction compiles a single instruction.
@ -57,12 +71,13 @@ func (f *Function) compileInstruction(line token.List) error {
} }
case token.Identifier: 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() name := line[0].Text()
value := line[2:] value := line[2:]
if config.Verbose { if config.Verbose {
fmt.Println("[variable]", name, value) ansi.Dim.Printf("[var] ")
fmt.Println(name, value)
} }
f.Variables[name] = &Variable{ f.Variables[name] = &Variable{

View File

@ -2,7 +2,6 @@ package asm
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"git.akyoto.dev/cli/q/src/build/arch/x64" "git.akyoto.dev/cli/q/src/build/arch/x64"
"git.akyoto.dev/cli/q/src/build/config" "git.akyoto.dev/cli/q/src/build/config"
@ -29,12 +28,12 @@ func (a *Assembler) Finalize() ([]byte, []byte) {
for _, x := range a.Instructions { for _, x := range a.Instructions {
switch x.Mnemonic { switch x.Mnemonic {
case MOVE: 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{ pointers = append(pointers, Pointer{
Position: Address(len(code) - 4), 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)) dataStart := config.BaseAddress + config.CodeOffset + Address(len(code))
for _, pointer := range pointers { for _, pointer := range pointers {

View File

@ -5,15 +5,5 @@ import "fmt"
// Instruction represents a single instruction which can be converted to machine code. // Instruction represents a single instruction which can be converted to machine code.
type Instruction struct { type Instruction struct {
Mnemonic Mnemonic Mnemonic Mnemonic
Data interface{} Data fmt.Stringer
}
// 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()
}
} }

View File

@ -6,7 +6,7 @@ import "git.akyoto.dev/cli/q/src/build/cpu"
func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) { func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) {
a.Instructions = append(a.Instructions, Instruction{ a.Instructions = append(a.Instructions, Instruction{
Mnemonic: MOVE, Mnemonic: MOVE,
Data: RegisterNumber{ Data: &RegisterNumber{
Register: reg, Register: reg,
Number: number, Number: number,
IsPointer: false, IsPointer: false,
@ -18,7 +18,7 @@ func (a *Assembler) MoveRegisterNumber(reg cpu.Register, number uint64) {
func (a *Assembler) MoveRegisterAddress(reg cpu.Register, address Address) { func (a *Assembler) MoveRegisterAddress(reg cpu.Register, address Address) {
a.Instructions = append(a.Instructions, Instruction{ a.Instructions = append(a.Instructions, Instruction{
Mnemonic: MOVE, Mnemonic: MOVE,
Data: RegisterNumber{ Data: &RegisterNumber{
Register: reg, Register: reg,
Number: uint64(address), Number: uint64(address),
IsPointer: true, IsPointer: true,

View File

@ -1,6 +1,10 @@
package asm 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. // RegisterNumber operates with a register and a number.
type RegisterNumber struct { type RegisterNumber struct {
@ -8,3 +12,8 @@ type RegisterNumber struct {
Number uint64 Number uint64
IsPointer bool IsPointer bool
} }
// String returns a human readable version.
func (data *RegisterNumber) String() string {
return fmt.Sprintf("%s, %x", data.Register, data.Number)
}

View File

@ -25,6 +25,9 @@ const (
// Number represents a series of numerical characters. // Number represents a series of numerical characters.
Number Number
// Define represents the assignment operator `:=` for a new variable.
Define
// Operator represents a mathematical operator. // Operator represents a mathematical operator.
Operator Operator
@ -63,6 +66,7 @@ func (kind Kind) String() string {
"Keyword", "Keyword",
"String", "String",
"Number", "Number",
"Define",
"Operator", "Operator",
"Separator", "Separator",
"Comment", "Comment",

View File

@ -13,7 +13,7 @@ func (list List) String() string {
var last Token var last Token
for _, t := range list { 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(' ') builder.WriteByte(' ')
} }

View File

@ -1,5 +1,7 @@
package token package token
import "bytes"
// Pre-allocate these byte buffers so we can re-use them // Pre-allocate these byte buffers so we can re-use them
// instead of allocating a new buffer every time. // instead of allocating a new buffer every time.
var ( var (
@ -10,6 +12,7 @@ var (
arrayStartBytes = []byte{'['} arrayStartBytes = []byte{'['}
arrayEndBytes = []byte{']'} arrayEndBytes = []byte{']'}
separatorBytes = []byte{','} separatorBytes = []byte{','}
defineBytes = []byte{':', '='}
newLineBytes = []byte{'\n'} newLineBytes = []byte{'\n'}
) )
@ -38,12 +41,7 @@ func Tokenize(buffer []byte) List {
i++ i++
} }
tokens = append(tokens, Token{ tokens = append(tokens, Token{String, start, buffer[start:end]})
String,
start,
buffer[start:end],
})
continue continue
// Parentheses start // Parentheses start
@ -88,11 +86,7 @@ func Tokenize(buffer []byte) List {
i++ i++
} }
token := Token{ token := Token{Identifier, position, buffer[position:i]}
Identifier,
position,
buffer[position:i],
}
if Keywords[string(token.Bytes)] { if Keywords[string(token.Bytes)] {
token.Kind = Keyword token.Kind = Keyword
@ -111,12 +105,7 @@ func Tokenize(buffer []byte) List {
i++ i++
} }
tokens = append(tokens, Token{ tokens = append(tokens, Token{Number, position, buffer[position:i]})
Number,
position,
buffer[position:i],
})
continue continue
} }
@ -129,12 +118,12 @@ func Tokenize(buffer []byte) List {
i++ i++
} }
tokens = append(tokens, Token{ if bytes.Equal(buffer[position:i], defineBytes) {
Operator, tokens = append(tokens, Token{Define, position, defineBytes})
position, continue
buffer[position:i], }
})
tokens = append(tokens, Token{Operator, position, buffer[position:i]})
continue continue
} }
} }