Added label type

This commit is contained in:
2025-03-13 16:57:13 +01:00
parent d96c351b4b
commit c1913d99d0
32 changed files with 102 additions and 63 deletions

View File

@ -2,12 +2,12 @@ package asm
// Comment adds a comment at the current position.
func (a *Assembler) Comment(text string) {
a.Label(COMMENT, text)
a.Label(COMMENT, Label{Name: text, Type: CommentLabel})
}
// DLLCall calls a function in a DLL file.
func (a *Assembler) DLLCall(name string) {
a.Label(DLLCALL, name)
a.Label(DLLCALL, Label{Name: name, Type: ExternLabel})
}
// Return returns back to the caller.

View File

@ -3,6 +3,7 @@ package asm
// Label represents a jump label.
type Label struct {
Name string
Type LabelType
}
// String returns a human readable version.
@ -11,14 +12,12 @@ func (data *Label) String() string {
}
// Label adds an instruction using a label.
func (a *Assembler) Label(mnemonic Mnemonic, name string) {
func (a *Assembler) Label(mnemonic Mnemonic, label Label) {
a.Instructions = append(a.Instructions, Instruction{
Mnemonic: mnemonic,
Type: TypeLabel,
Index: Index(len(a.Param.Label)),
})
a.Param.Label = append(a.Param.Label, Label{
Name: name,
})
a.Param.Label = append(a.Param.Label, label)
}

13
src/asm/LabelType.go Normal file
View File

@ -0,0 +1,13 @@
package asm
// LabelType shows what the label was used for.
type LabelType uint8
const (
UnknownLabel LabelType = iota
CommentLabel
ControlLabel
DataLabel
FunctionLabel
ExternLabel
)

View File

@ -2,17 +2,17 @@ package asm
// MemoryLabel operates with a memory address and a number.
type MemoryLabel struct {
Label string
Label Label
Address Memory
}
// String returns a human readable version.
func (data *MemoryLabel) String() string {
return data.Address.Format(data.Label)
return data.Address.Format(data.Label.Name)
}
// MemoryLabel adds an instruction with a memory address and a label.
func (a *Assembler) MemoryLabel(mnemonic Mnemonic, address Memory, label string) {
func (a *Assembler) MemoryLabel(mnemonic Mnemonic, address Memory, label Label) {
a.Instructions = append(a.Instructions, Instruction{
Mnemonic: mnemonic,
Type: TypeMemoryLabel,

View File

@ -8,17 +8,17 @@ import (
// RegisterLabel operates with a register and a label.
type RegisterLabel struct {
Label string
Label Label
Register cpu.Register
}
// String returns a human readable version.
func (data *RegisterLabel) String() string {
return fmt.Sprintf("%s, %s", data.Register, data.Label)
return fmt.Sprintf("%s, %s", data.Register, data.Label.Name)
}
// RegisterLabel adds an instruction with a register and a label.
func (a *Assembler) RegisterLabel(mnemonic Mnemonic, register cpu.Register, label string) {
func (a *Assembler) RegisterLabel(mnemonic Mnemonic, register cpu.Register, label Label) {
a.Instructions = append(a.Instructions, Instruction{
Mnemonic: mnemonic,
Type: TypeRegisterLabel,

View File

@ -3,7 +3,6 @@ package asmc
import (
"encoding/binary"
"fmt"
"strings"
"git.urbach.dev/cli/q/src/arm"
"git.urbach.dev/cli/q/src/asm"
@ -44,8 +43,11 @@ func (c *compiler) compileARM(x asm.Instruction) {
case asm.LABEL:
label := c.assembler.Param.Label[x.Index]
c.codeLabels[label.Name] = Address(len(c.code))
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
if label.Type == asm.FunctionLabel {
c.append(arm.StorePair(arm.FP, arm.LR, arm.SP, -16))
c.append(arm.MoveRegisterRegister(arm.FP, arm.SP))
}
case asm.LOAD:
switch x.Type {
@ -140,13 +142,13 @@ func (c *compiler) compileARM(x asm.Instruction) {
position := Address(len(c.code))
c.append(arm.LoadAddress(operands.Register, 0))
if strings.HasPrefix(operands.Label, "data ") {
if operands.Label.Type == asm.DataLabel {
c.dataPointers = append(c.dataPointers, &pointer{
Position: position,
OpSize: 0,
Size: 4,
Resolve: func() Address {
destination, exists := c.dataLabels[operands.Label]
destination, exists := c.dataLabels[operands.Label.Name]
if !exists {
panic("unknown label")

View File

@ -1,8 +1,6 @@
package asmc
import (
"strings"
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/x86"
)
@ -25,13 +23,13 @@ func (c *compiler) move(x asm.Instruction) {
position := end - 4
opSize := position - start
if strings.HasPrefix(operands.Label, "data ") {
if operands.Label.Type == asm.DataLabel {
c.dataPointers = append(c.dataPointers, &pointer{
Position: position,
OpSize: uint8(opSize),
Size: uint8(4),
Resolve: func() Address {
destination, exists := c.dataLabels[operands.Label]
destination, exists := c.dataLabels[operands.Label.Name]
if !exists {
panic("unknown label")
@ -48,7 +46,7 @@ func (c *compiler) move(x asm.Instruction) {
OpSize: uint8(opSize),
Size: uint8(4),
Resolve: func() Address {
destination, exists := c.codeLabels[operands.Label]
destination, exists := c.codeLabels[operands.Label.Name]
if !exists {
panic("unknown label")

View File

@ -34,7 +34,7 @@ func (c *compiler) store(x asm.Instruction) {
OpSize: uint8(opSize),
Size: uint8(size),
Resolve: func() Address {
destination, exists := c.codeLabels[operands.Label]
destination, exists := c.codeLabels[operands.Label.Name]
if !exists {
panic("unknown label")

View File

@ -45,7 +45,10 @@ func (r *Result) finalize() {
}
})
final.Label(asm.LABEL, "_crash")
final.Label(asm.LABEL, asm.Label{
Name: "_crash",
Type: asm.ControlLabel,
})
switch config.TargetOS {
case config.Linux:

View File

@ -1,9 +1,11 @@
package core
import "git.urbach.dev/cli/q/src/asm"
// AddBytes adds a sequence of bytes and returns its address as a label.
func (f *Function) AddBytes(value []byte) string {
func (f *Function) AddBytes(value []byte) asm.Label {
f.count.data++
label := f.CreateLabel("data", f.count.data)
f.Assembler.SetData(label, value)
label := f.CreateLabel("data", f.count.data, asm.DataLabel)
f.Assembler.SetData(label.Name, value)
return label
}

View File

@ -1,8 +1,14 @@
package core
import "git.urbach.dev/cli/q/src/asm"
// Compile turns a function into machine code.
func (f *Function) Compile() {
f.AddLabel(f.UniqueName)
f.AddLabel(asm.Label{
Name: f.UniqueName,
Type: asm.FunctionLabel,
})
f.Err = f.CompileTokens(f.Body)
f.Return()

View File

@ -8,8 +8,8 @@ import (
// CompileAssert compiles an assertion.
func (f *Function) CompileAssert(assert *ast.Assert) error {
f.count.assert++
success := f.CreateLabel("assert true", f.count.assert)
fail := f.CreateLabel("assert false", f.count.assert)
success := f.CreateLabel("assert true", f.count.assert, asm.ControlLabel)
fail := f.CreateLabel("assert false", f.count.assert, asm.ControlLabel)
err := f.CompileCondition(assert.Condition, success, fail)
if err != nil {
@ -20,7 +20,7 @@ func (f *Function) CompileAssert(assert *ast.Assert) error {
f.Defer(func() {
f.AddLabel(fail)
f.Jump(asm.JUMP, "_crash")
f.Jump(asm.JUMP, asm.Label{Name: "_crash", Type: asm.ControlLabel})
})
return err

View File

@ -58,7 +58,7 @@ func (f *Function) CompileCall(root *expression.Expression) ([]*Parameter, error
switch value := value.(type) {
case *eval.Label:
fn := f.All.Functions[value.Label]
fn := f.All.Functions[value.Label.Name]
if len(parameters) != len(fn.Input) {
return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, root.Children[0].Token.End())

View File

@ -12,11 +12,11 @@ import (
)
// CompileCondition inserts code to jump to the start label or end label depending on the truth of the condition.
func (f *Function) CompileCondition(condition *expression.Expression, successLabel string, failLabel string) error {
func (f *Function) CompileCondition(condition *expression.Expression, successLabel asm.Label, failLabel asm.Label) error {
switch condition.Token.Kind {
case token.LogicalOr:
f.count.subBranch++
leftFailLabel := f.CreateLabel("false", f.count.subBranch)
leftFailLabel := f.CreateLabel("false", f.count.subBranch, asm.ControlLabel)
// Left
left := condition.Children[0]
@ -43,7 +43,7 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab
case token.LogicalAnd:
f.count.subBranch++
leftSuccessLabel := f.CreateLabel("true", f.count.subBranch)
leftSuccessLabel := f.CreateLabel("true", f.count.subBranch, asm.ControlLabel)
// Left
left := condition.Children[0]

View File

@ -24,7 +24,7 @@ func (f *Function) CompileDelete(root *expression.Expression) error {
f.RegisterNumber(asm.MOVE, f.CPU.Input[1], variable.Value.Typ.(*types.Pointer).To.Size())
free := f.All.Functions["mem.free"]
f.BeforeCall()
f.Label(asm.CALL, "mem.free")
f.Label(asm.CALL, asm.Label{Name: "mem.free", Type: asm.FunctionLabel})
f.AfterCall(f.CPU.Input[:2])
f.Dependencies = append(f.Dependencies, free)
return nil

View File

@ -23,8 +23,8 @@ func (f *Function) CompileFor(loop *ast.For) error {
f.count.loop++
var (
label = f.CreateLabel("for", f.count.loop)
labelEnd = f.CreateLabel("for end", f.count.loop)
label = f.CreateLabel("for", f.count.loop, asm.ControlLabel)
labelEnd = f.CreateLabel("for end", f.count.loop, asm.ControlLabel)
counter cpu.Register
from *expression.Expression
to *expression.Expression

View File

@ -14,9 +14,9 @@ func (f *Function) CompileIf(branch *ast.If) error {
f.count.branch++
var (
end string
success = f.CreateLabel("if true", f.count.branch)
fail = f.CreateLabel("if false", f.count.branch)
end asm.Label
success = f.CreateLabel("if true", f.count.branch, asm.ControlLabel)
fail = f.CreateLabel("if false", f.count.branch, asm.ControlLabel)
err = f.CompileCondition(branch.Condition, success, fail)
)
@ -33,7 +33,7 @@ func (f *Function) CompileIf(branch *ast.If) error {
}
if branch.Else != nil {
end = f.CreateLabel("if end", f.count.branch)
end = f.CreateLabel("if end", f.count.branch, asm.ControlLabel)
f.Jump(asm.JUMP, end)
}

View File

@ -12,7 +12,7 @@ func (f *Function) CompileLoop(loop *ast.Loop) error {
}
f.count.loop++
label := f.CreateLabel("loop", f.count.loop)
label := f.CreateLabel("loop", f.count.loop, asm.ControlLabel)
f.AddLabel(label)
scope := f.PushScope(loop.Body, f.File.Bytes)
scope.InLoop = true

View File

@ -47,7 +47,7 @@ func (f *Function) CompileNew(root *expression.Expression) (types.Type, error) {
f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size())
alloc := f.All.Functions["mem.alloc"]
f.BeforeCall()
f.Label(asm.CALL, "mem.alloc")
f.Label(asm.CALL, asm.Label{Name: "mem.alloc", Type: asm.FunctionLabel})
f.AfterCall(f.CPU.Input[:1])
f.Dependencies = append(f.Dependencies, alloc)
return &types.Pointer{To: typ}, nil

View File

@ -8,7 +8,7 @@ import (
// CompileSwitch compiles a multi-branch instruction.
func (f *Function) CompileSwitch(s *ast.Switch) error {
f.count.multiBranch++
end := f.CreateLabel("switch end", f.count.multiBranch)
end := f.CreateLabel("switch end", f.count.multiBranch, asm.ControlLabel)
for _, branch := range s.Cases {
if branch.Condition == nil {
@ -26,8 +26,8 @@ func (f *Function) CompileSwitch(s *ast.Switch) error {
f.count.branch++
var (
success = f.CreateLabel("case true", f.count.branch)
fail = f.CreateLabel("case false", f.count.branch)
success = f.CreateLabel("case true", f.count.branch, asm.ControlLabel)
fail = f.CreateLabel("case false", f.count.branch, asm.ControlLabel)
err = f.CompileCondition(branch.Condition, success, fail)
)

View File

@ -3,10 +3,12 @@ package core
import (
"strconv"
"strings"
"git.urbach.dev/cli/q/src/asm"
)
// CreateLabel creates a label that is tied to this function by using a suffix.
func (f *Function) CreateLabel(prefix string, count counter) string {
func (f *Function) CreateLabel(prefix string, count counter, typ asm.LabelType) asm.Label {
tmp := strings.Builder{}
tmp.WriteString(prefix)
tmp.WriteString(" ")
@ -14,5 +16,9 @@ func (f *Function) CreateLabel(prefix string, count counter) string {
tmp.WriteString(" [")
tmp.WriteString(f.UniqueName)
tmp.WriteString("]")
return tmp.String()
return asm.Label{
Name: tmp.String(),
Type: typ,
}
}

View File

@ -79,8 +79,11 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error)
f.Dependencies = append(f.Dependencies, function)
value := &eval.Label{
Typ: types.AnyPointer,
Label: label,
Typ: types.AnyPointer,
Label: asm.Label{
Name: label,
Type: asm.FunctionLabel,
},
}
return value, nil

View File

@ -4,6 +4,7 @@ import (
"encoding/binary"
"fmt"
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/errors"
"git.urbach.dev/cli/q/src/eval"
"git.urbach.dev/cli/q/src/token"
@ -48,8 +49,11 @@ func (f *Function) EvaluateToken(t token.Token) (eval.Value, error) {
f.Dependencies = append(f.Dependencies, function)
value := &eval.Label{
Typ: types.AnyPointer,
Label: function.UniqueName,
Typ: types.AnyPointer,
Label: asm.Label{
Name: function.UniqueName,
Type: asm.FunctionLabel,
},
}
return value, nil

View File

@ -6,7 +6,7 @@ import (
)
// JumpIfFalse jumps to the label if the previous comparison was false.
func (f *Function) JumpIfFalse(operator token.Kind, label string) {
func (f *Function) JumpIfFalse(operator token.Kind, label asm.Label) {
switch operator {
case token.Equal:
f.Jump(asm.JNE, label)

View File

@ -6,7 +6,7 @@ import (
)
// JumpIfTrue jumps to the label if the previous comparison was true.
func (f *Function) JumpIfTrue(operator token.Kind, label string) {
func (f *Function) JumpIfTrue(operator token.Kind, label asm.Label) {
switch operator {
case token.Equal:
f.Jump(asm.JE, label)

View File

@ -1,11 +1,14 @@
package eval
import "git.urbach.dev/cli/q/src/types"
import (
"git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/types"
)
// Label is a named pointer to a code or data section.
type Label struct {
Typ types.Type
Label string
Label asm.Label
}
func (v *Label) String() string {

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) AddLabel(label string) {
func (f *Machine) AddLabel(label asm.Label) {
f.Assembler.Label(asm.LABEL, label)
f.postInstruction()
}

View File

@ -3,7 +3,7 @@ package register
import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) DLLCall(label string) {
f.Assembler.Label(asm.DLLCALL, label)
f.Assembler.Label(asm.DLLCALL, asm.Label{Name: label, Type: asm.UnknownLabel})
f.UseRegister(f.CPU.Output[0])
f.postInstruction()
}

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) Jump(mnemonic asm.Mnemonic, label string) {
func (f *Machine) Jump(mnemonic asm.Mnemonic, label asm.Label) {
f.Assembler.Label(mnemonic, label)
f.postInstruction()
}

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) Label(mnemonic asm.Mnemonic, label string) {
func (f *Machine) Label(mnemonic asm.Mnemonic, label asm.Label) {
f.Assembler.Label(mnemonic, label)
f.postInstruction()
}

View File

@ -2,7 +2,7 @@ package register
import "git.urbach.dev/cli/q/src/asm"
func (f *Machine) MemoryLabel(mnemonic asm.Mnemonic, a asm.Memory, b string) {
func (f *Machine) MemoryLabel(mnemonic asm.Mnemonic, a asm.Memory, b asm.Label) {
f.Assembler.MemoryLabel(mnemonic, a, b)
f.postInstruction()
}

View File

@ -5,7 +5,7 @@ import (
"git.urbach.dev/cli/q/src/cpu"
)
func (f *Machine) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label string) {
func (f *Machine) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label asm.Label) {
f.Assembler.RegisterLabel(mnemonic, register, label)
if mnemonic == asm.MOVE {