Add parser for sized arg
This commit is contained in:
parent
d3fb782a8c
commit
7bb479f4cb
105
go/asm/asm.go
105
go/asm/asm.go
@ -1,8 +1,11 @@
|
|||||||
package asm
|
package asm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/participle/v2"
|
"github.com/alecthomas/participle/v2"
|
||||||
@ -25,15 +28,15 @@ func(d Display) String() string {
|
|||||||
return fmt.Sprintf("Display: %v %v", d.Sym, d.Val)
|
return fmt.Sprintf("Display: %v %v", d.Sym, d.Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Sig struct {
|
//type Sig struct {
|
||||||
Sym string `@Sym Whitespace`
|
// Sym string `@Sym Whitespace`
|
||||||
Size uint32 `@Size Whitespace`
|
// Size uint32 `@Size Whitespace`
|
||||||
Val uint32 `@Size Whitespace`
|
// Val uint32 `@Size Whitespace`
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func(s Sig) String() string {
|
//func(s Sig) String() string {
|
||||||
return fmt.Sprintf("Sig: %v %v %v", s.Sym, s.Size, s.Val)
|
// return fmt.Sprintf("Sig: %v %v %v", s.Sym, s.Size, s.Val)
|
||||||
}
|
//}
|
||||||
|
|
||||||
type Single struct {
|
type Single struct {
|
||||||
One string `@Sym Whitespace`
|
One string `@Sym Whitespace`
|
||||||
@ -111,12 +114,90 @@ var (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func numSize(n uint32) int {
|
||||||
|
v := math.Log2(float64(n))
|
||||||
|
return int(((v - 1) / 8) + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeOpcode(op vm.Opcode, w *bytes.Buffer) (int, error) {
|
||||||
|
bn := [2]byte{}
|
||||||
|
binary.BigEndian.PutUint16(bn[:], uint16(op))
|
||||||
|
n, err := w.Write(bn[:])
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeSym(s string, w *bytes.Buffer) (int, error) {
|
||||||
|
sz := len(s)
|
||||||
|
if sz > 255 {
|
||||||
|
return 0, fmt.Errorf("string size %v too big", sz)
|
||||||
|
}
|
||||||
|
w.Write([]byte{byte(sz)})
|
||||||
|
return w.WriteString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeSize(n uint32, w *bytes.Buffer) (int, error) {
|
||||||
|
bn := [4]byte{}
|
||||||
|
sz := numSize(n)
|
||||||
|
if sz > 4 {
|
||||||
|
return 0, fmt.Errorf("number size %v too big", sz)
|
||||||
|
}
|
||||||
|
w.Write([]byte{byte(sz)})
|
||||||
|
binary.BigEndian.PutUint32(bn[:], n)
|
||||||
|
c := 4-sz
|
||||||
|
return w.Write(bn[c:])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func parseSized(op vm.Opcode, arg Arg, w io.Writer) (int, error) {
|
||||||
|
var rn int
|
||||||
|
|
||||||
|
v := arg.ArgSized
|
||||||
|
if v == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
n, err := writeOpcode(op, b)
|
||||||
|
rn += n
|
||||||
|
if err != nil {
|
||||||
|
return rn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = writeSym(v.Sym, b)
|
||||||
|
rn += n
|
||||||
|
if err != nil {
|
||||||
|
return rn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = writeSize(v.Size, b)
|
||||||
|
rn += n
|
||||||
|
if err != nil {
|
||||||
|
return rn, err
|
||||||
|
}
|
||||||
|
if w != nil {
|
||||||
|
rn, err = w.Write(b.Bytes())
|
||||||
|
} else {
|
||||||
|
rn = 0
|
||||||
|
}
|
||||||
|
return rn, err
|
||||||
|
}
|
||||||
|
|
||||||
func Parse(s string, w io.Writer) (int, error) {
|
func Parse(s string, w io.Writer) (int, error) {
|
||||||
rd := strings.NewReader(s)
|
rd := strings.NewReader(s)
|
||||||
ast, err := asmParser.Parse("file", rd)
|
ast, err := asmParser.Parse("file", rd)
|
||||||
for i, v := range ast.Instructions {
|
var rn int
|
||||||
|
|
||||||
|
for _, v := range ast.Instructions {
|
||||||
op := vm.OpcodeIndex[v.OpCode]
|
op := vm.OpcodeIndex[v.OpCode]
|
||||||
fmt.Printf("%v (%v) %v\n", i, op, v)
|
n, err := parseSized(op, v.OpArg, w)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
rn += n
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0, err
|
return rn, err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package asm
|
package asm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ func TestParserInit(t *testing.T) {
|
|||||||
b = vm.NewLine(b, vm.MOUT, []string{"bar", "barbarbaz"}, nil, nil)
|
b = vm.NewLine(b, vm.MOUT, []string{"bar", "barbarbaz"}, nil, nil)
|
||||||
s, err := vm.ToString(b)
|
s, err := vm.ToString(b)
|
||||||
log.Printf("parsing:\n%s\n", s)
|
log.Printf("parsing:\n%s\n", s)
|
||||||
|
|
||||||
n, err := Parse(s, nil)
|
n, err := Parse(s, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -24,3 +26,23 @@ func TestParserInit(t *testing.T) {
|
|||||||
t.Fatalf("expected 0 byte write count, got %v", n)
|
t.Fatalf("expected 0 byte write count, got %v", n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParserSized(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
b = vm.NewLine(b, vm.LOAD, []string{"foo"}, []byte{42}, nil)
|
||||||
|
s, err := vm.ToString(b)
|
||||||
|
log.Printf("parsing:\n%s\n", s)
|
||||||
|
|
||||||
|
r := bytes.NewBuffer(nil)
|
||||||
|
n, err := Parse(s, r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if n != 8 {
|
||||||
|
t.Fatalf("expected 0 byte write count, got %v", n)
|
||||||
|
}
|
||||||
|
rb := r.Bytes()
|
||||||
|
if !bytes.Equal(rb, []byte{0x00, vm.LOAD, 0x03, 0x66, 0x6f, 0x6f, 0x01, 0x2a}) {
|
||||||
|
t.Fatalf("expected 0x00%x012a, got %v", vm.LOAD, rb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user