Added label type
This commit is contained in:
@ -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.
|
||||
|
@ -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
13
src/asm/LabelType.go
Normal 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
|
||||
)
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
)
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user