commit 7bb479f4cbf2b85686abcf3af4d12f007cfb8546
parent d3fb782a8cb9cd9774b6a442c3ff4af0a21201b0
Author: lash <dev@holbrook.no>
Date: Tue, 4 Apr 2023 20:32:40 +0100
Add parser for sized arg
Diffstat:
2 files changed, 115 insertions(+), 12 deletions(-)
diff --git a/go/asm/asm.go b/go/asm/asm.go
@@ -1,8 +1,11 @@
package asm
import (
+ "bytes"
+ "encoding/binary"
"fmt"
"io"
+ "math"
"strings"
"github.com/alecthomas/participle/v2"
@@ -25,15 +28,15 @@ func(d Display) String() string {
return fmt.Sprintf("Display: %v %v", d.Sym, d.Val)
}
-type Sig struct {
- Sym string `@Sym Whitespace`
- Size uint32 `@Size Whitespace`
- Val uint32 `@Size Whitespace`
-}
-
-func(s Sig) String() string {
- return fmt.Sprintf("Sig: %v %v %v", s.Sym, s.Size, s.Val)
-}
+//type Sig struct {
+// Sym string `@Sym Whitespace`
+// Size uint32 `@Size Whitespace`
+// Val uint32 `@Size Whitespace`
+//}
+//
+//func(s Sig) String() string {
+// return fmt.Sprintf("Sig: %v %v %v", s.Sym, s.Size, s.Val)
+//}
type Single struct {
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) {
rd := strings.NewReader(s)
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]
- 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
}
diff --git a/go/asm/asm_test.go b/go/asm/asm_test.go
@@ -1,6 +1,7 @@
package asm
import (
+ "bytes"
"log"
"testing"
@@ -16,6 +17,7 @@ func TestParserInit(t *testing.T) {
b = vm.NewLine(b, vm.MOUT, []string{"bar", "barbarbaz"}, nil, nil)
s, err := vm.ToString(b)
log.Printf("parsing:\n%s\n", s)
+
n, err := Parse(s, nil)
if err != nil {
t.Fatal(err)
@@ -24,3 +26,23 @@ func TestParserInit(t *testing.T) {
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)
+ }
+}