Add disasembler-ish - bytecode to instruction debug output

This commit is contained in:
lash 2023-04-02 15:00:56 +01:00
parent aec0564cea
commit ac4a2bac00
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
7 changed files with 258 additions and 5 deletions

View File

@ -163,6 +163,15 @@ If `data_directory` is not set, current directory will be used.
if `root_symbol` is not set, the symbol `root` will be used.
### Disassembler
`go run ./dev/testdata/ <binary_file>`
The output from this tool is to be considered debugging output, as the assembly language isn't formalized yet.
In the meantime, it will at least list all the instructions, and thus validate the file.
### Assembler
**TBD**

27
go/dev/disasm/main.go Normal file
View File

@ -0,0 +1,27 @@
package main
import (
"fmt"
"os"
"io/ioutil"
"git.defalsify.org/festive/vm"
)
func main() {
if (len(os.Args) < 2) {
os.Exit(1)
}
fp := os.Args[1]
v, err := ioutil.ReadFile(fp)
if err != nil {
fmt.Fprintf(os.Stderr, "read error: %v", err)
os.Exit(1)
}
r, err := vm.ToString(v)
if err != nil {
fmt.Fprintf(os.Stderr, "parse error: %v", err)
os.Exit(1)
}
fmt.Printf(r)
}

93
go/vm/debug.go Normal file
View File

@ -0,0 +1,93 @@
package vm
import (
"fmt"
)
func ToString(b []byte) (string, error) {
var s string
running := true
for running {
op, bb, err := opSplit(b)
b = bb
if err != nil {
return "", err
}
opString := OpcodeString[op]
if opString == "" {
return "", fmt.Errorf("unknown opcode: %v", op)
}
s += opString
switch op {
case CATCH:
r, n, m, bb, err := ParseCatch(b)
b = bb
if err != nil {
return "", err
}
vv := 0
if m {
vv = 1
}
s = fmt.Sprintf("%s %s %v %v # invertmatch=%v", s, r, n, vv, m)
case CROAK:
n, m, bb, err := ParseCroak(b)
b = bb
if err != nil {
return "", err
}
vv := 0
if m {
vv = 1
}
s = fmt.Sprintf("%s %v %v # invertmatch=%v", s, n, vv, m)
case LOAD:
r, n, bb, err := ParseLoad(b)
b = bb
if err != nil {
return "", err
}
s = fmt.Sprintf("%s %s %v", s, r, n)
case RELOAD:
r, bb, err := ParseReload(b)
b = bb
if err != nil {
return "", err
}
s = fmt.Sprintf("%s %s", s, r)
case MAP:
r, bb, err := ParseMap(b)
b = bb
if err != nil {
return "", err
}
s = fmt.Sprintf("%s %s", s, r)
case MOVE:
r, bb, err := ParseMove(b)
b = bb
if err != nil {
return "", err
}
s = fmt.Sprintf("%s %s", s, r)
case INCMP:
r, v, bb, err := ParseInCmp(b)
b = bb
if err != nil {
return "", err
}
s = fmt.Sprintf("%s %s %s", s, r, v)
case HALT:
b, err = ParseHalt(b)
if err != nil {
return "", err
}
}
s += "\n"
if len(b) == 0 {
running = false
}
}
return s, nil
}

114
go/vm/debug_test.go Normal file
View File

@ -0,0 +1,114 @@
package vm
import (
"testing"
)
func TestToString(t *testing.T) {
var b []byte
var r string
var expect string
var err error
b = NewLine(nil, CATCH, []string{"xyzzy"}, []byte{0x0d}, []uint8{1})
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "CATCH xyzzy 13 1 # invertmatch=true\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, CROAK, nil, []byte{0x0d}, []uint8{1})
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "CROAK 13 1 # invertmatch=true\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, LOAD, []string{"foo"}, []byte{0x0a}, nil)
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "LOAD foo 10\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, RELOAD, []string{"bar"}, nil, nil)
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "RELOAD bar\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, MAP, []string{"inky_pinky"}, nil, nil)
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "MAP inky_pinky\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, MOVE, []string{"blinky_clyde"}, nil, nil)
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "MOVE blinky_clyde\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, HALT, nil, nil, nil)
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "HALT\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
b = NewLine(nil, INCMP, []string{"13", "baz"}, nil, nil)
r, err = ToString(b)
if err != nil {
t.Fatal(err)
}
expect = "INCMP 13 baz\n"
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
}
func TestToStringMultiple(t *testing.T) {
b := NewLine(nil, INCMP, []string{"1", "foo"}, nil, nil)
b = NewLine(b, INCMP, []string{"2", "bar"}, nil, nil)
b = NewLine(b, CATCH, []string{"aiee"}, []byte{0x02, 0x9a}, []uint8{0})
b = NewLine(b, LOAD, []string{"inky"}, []byte{0x2a}, nil)
b = NewLine(b, HALT, nil, nil, nil)
r, err := ToString(b)
if err != nil {
t.Fatal(err)
}
expect := `INCMP 1 foo
INCMP 2 bar
CATCH aiee 666 0 # invertmatch=false
LOAD inky 42
HALT
`
if r != expect {
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
}
}

View File

@ -17,3 +17,17 @@ const (
INCMP = 8
_MAX = 8
)
var (
OpcodeString = map[Opcode]string{
NOOP: "NOOP",
CATCH: "CATCH",
CROAK: "CROAK",
LOAD: "LOAD",
RELOAD: "RELOAD",
MAP: "MAP",
MOVE: "MOVE",
HALT: "HALT",
INCMP: "INCMP",
}
)

View File

@ -19,13 +19,11 @@ import (
func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
running := true
for running {
log.Printf("code before 0x%x", b)
op, bb, err := opSplit(b)
if err != nil {
return b, err
}
b = bb
log.Printf("code after 0x%x", b)
switch op {
case CATCH:
b, err = RunCatch(b, st, rs, ctx)
@ -41,7 +39,6 @@ func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) (
b, err = RunMove(b, st, rs, ctx)
case INCMP:
b, err = RunInCmp(b, st, rs, ctx)
log.Printf("bb %v", b)
case HALT:
b, err = RunHalt(b, st, rs, ctx)
return b, err
@ -51,7 +48,6 @@ func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) (
if err != nil {
return b, err
}
log.Printf("aa %v", b)
if len(b) == 0 {
return []byte{}, nil
}

View File

@ -7,7 +7,7 @@ import (
"git.defalsify.org/festive/state"
)
func Parse(b []byte) (Opcode, []byte, error) {
func ParseOp(b []byte) (Opcode, []byte, error) {
op, b, err := opSplit(b)
if err != nil {
return NOOP, b, err