diff --git a/go/asm/asm.go b/go/asm/asm.go index 6f5f6d4..f175661 100644 --- a/go/asm/asm.go +++ b/go/asm/asm.go @@ -5,7 +5,9 @@ import ( "encoding/binary" "fmt" "io" + "log" "math" +// "strconv" "strings" "github.com/alecthomas/participle/v2" @@ -22,25 +24,48 @@ type Asm struct { type Display struct { Sym string `@Sym Whitespace` //Val string `Quote (@Desc @Whitespace?)+ Quote Whitespace` - Val string `Quote (@Sym @Whitespace?)+ Quote Whitespace` + Val string `Quote (@Sym @Whitespace?)+ Quote Whitespace? EOL` } 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` -//} +type Sig struct { + Sym string `@Sym Whitespace` + Size uint32 `@Size Whitespace` + Val uint8 `@Size Whitespace? EOL` +} // -//func(s Sig) String() string { -// return fmt.Sprintf("Sig: %v %v %v", s.Sym, s.Size, s.Val) +//func(s Sig) Capture(v []string) error { +// log.Printf("considering capture %v %v", v[0], len(v)) +// if len(v) < 3 { +// return nil +// } +// s.Sym = v[0] +// r, err := strconv.Atoi(v[1]) +// if err != nil { +// return err +// } +// s.Size = uint32(r) +// r, err = strconv.Atoi(v[2]) +// if err != nil { +// return err +// } +// if r != 0 { +// r = 1 +// } +// s.Val = uint8(r) +// log.Printf("after considering capture: %v", s) +// return nil //} +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` + One string `@Sym Whitespace? EOL` } func(s Single) String() string { @@ -49,7 +74,7 @@ func(s Single) String() string { type Double struct { One string `@Sym Whitespace` - Two string `@Sym Whitespace` + Two string `@Sym Whitespace? EOL` } func(d Double) String() string { @@ -58,8 +83,12 @@ func(d Double) String() string { type Sized struct { Sym string `@Sym Whitespace` - Size uint32 `@Size Whitespace` - X uint32 `(@Size Whitespace)?` + Size uint32 `@Size Whitespace? EOL` +} + +func(s Sized) Capture(v []Sized) error { + log.Printf("foofofofofo") + return fmt.Errorf("foo foo foo") } func(s Sized) String() string { @@ -67,9 +96,10 @@ func(s Sized) String() string { } type Arg struct { - ArgNone string "Whitespace?" + ArgNone string "Discard?" ArgDisplay *Display `@@?` ArgSized *Sized `@@?` + ArgSig *Sig `@@?` ArgDouble *Double `@@?` ArgSingle *Single `@@?` } @@ -78,6 +108,9 @@ func (a Arg) String() string { if a.ArgDisplay != nil { return fmt.Sprintf("%s", a.ArgDisplay) } + if a.ArgSig != nil { + return fmt.Sprintf("%s", a.ArgSig) + } if a.ArgSized != nil { return fmt.Sprintf("%s", a.ArgSized) } @@ -104,9 +137,12 @@ var ( asmLexer = lexer.MustSimple([]lexer.SimpleRule{ {"Comment", `(?:#)[^\n]*\n?`}, {"Ident", `^[A-Z]+`}, - {"Sym", `[a-zA-Z0-9_]+`}, + {"SizeSig", `[0-9]+\s+{?:[0-9]}`}, {"Size", `[0-9]+`}, - {"Whitespace", `[ \t\n\r]+`}, + {"Sym", `[a-zA-Z_][a-zA-Z0-9_]+`}, + {"Whitespace", `[ \t]+`}, + {"Discard", `^\s+[\n\r]+$`}, + {"EOL", `[\n\r]+`}, {"Quote", `["']`}, }) asmParser = participle.MustBuild[Asm]( @@ -155,7 +191,7 @@ func writeSize(n uint32, w *bytes.Buffer) (int, error) { w.Write([]byte{byte(sz)}) binary.BigEndian.PutUint32(bn[:], n) c := 4-sz - return w.Write(bn[c:]) + return w.Write(bn[c:]) } func parseSingle(op vm.Opcode, arg Arg, w io.Writer) (int, error) { @@ -294,6 +330,53 @@ func parseSized(op vm.Opcode, arg Arg, w io.Writer) (int, error) { return rn, err } +func parseSig(op vm.Opcode, arg Arg, w io.Writer) (int, error) { + var rn int + + v := arg.ArgSig + 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 v.Val == 0 { + n, err = b.Write([]byte{0x00}) + } else { + n, err = b.Write([]byte{0x01}) + } + rn += n + if err != nil { + return rn, err + } + + + if w != nil { + rn, err = w.Write(b.Bytes()) + } else { + rn = 0 + } + return rn, err +} + func parseNoarg(op vm.Opcode, arg Arg, w io.Writer) (int, error) { var rn int @@ -321,6 +404,7 @@ func Parse(s string, w io.Writer) (int, error) { var rn int for _, v := range ast.Instructions { + log.Printf("parsing line %v: %v", v.OpCode, v.OpArg) op := vm.OpcodeIndex[v.OpCode] n, err := parseSized(op, v.OpArg, w) if err != nil { @@ -330,7 +414,6 @@ func Parse(s string, w io.Writer) (int, error) { rn += n continue } - n, err = parseDisplay(op, v.OpArg, w) if err != nil { return n, err @@ -339,6 +422,14 @@ func Parse(s string, w io.Writer) (int, error) { rn += n continue } + n, err = parseSig(op, v.OpArg, w) + if err != nil { + return n, err + } + if n > 0 { + rn += n + continue + } n, err = parseDouble(op, v.OpArg, w) if err != nil { return n, err diff --git a/go/asm/asm_test.go b/go/asm/asm_test.go index 0380624..78e2762 100644 --- a/go/asm/asm_test.go +++ b/go/asm/asm_test.go @@ -2,6 +2,7 @@ package asm import ( "bytes" + "encoding/hex" "log" "testing" @@ -111,6 +112,31 @@ func TestParseSingle(t *testing.T) { } } +func TestParseSig(t *testing.T) { + var b []byte + b = vm.NewLine(b, vm.CATCH, []string{"plugh"}, []byte{0x02, 0x9a}, []uint8{0x2a}) + 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 != 12 { + t.Fatalf("expected 12 byte write count, got %v", n) + } + rb := r.Bytes() + expect_hex := "000105706c75676802029a01" + expect, err := hex.DecodeString(expect_hex) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(rb, expect) { + t.Fatalf("expected %v, got %x", expect_hex, rb) + } +} + func TestParseNoarg(t *testing.T) { var b []byte b = vm.NewLine(b, vm.HALT, nil, nil, nil) @@ -138,7 +164,7 @@ func TestParserWriteMultiple(t *testing.T) { b = vm.NewLine(b, vm.CATCH, []string{"xyzzy"}, []byte{0x02, 0x9a}, []uint8{1}) b = vm.NewLine(b, vm.INCMP, []string{"inky", "pinky"}, nil, nil) b = vm.NewLine(b, vm.LOAD, []string{"foo"}, []byte{42}, nil) - b = vm.NewLine(b, vm.MOUT, []string{"bar", "barbarbaz"}, nil, nil) + b = vm.NewLine(b, vm.MOUT, []string{"bar", "bar barb az"}, nil, nil) s, err := vm.ToString(b) log.Printf("parsing:\n%s\n", s) @@ -148,11 +174,20 @@ func TestParserWriteMultiple(t *testing.T) { t.Fatal(err) } n_expect := 2 // halt - n_expect += 2 + 6 + 2 + 1 // catch + n_expect += 2 + 6 + 3 + 1 // catch n_expect += 2 + 5 + 6 // incmp n_expect += 2 + 4 + 2 // load - n_expect += 2 + 4 + 10 // mout + n_expect += 2 + 4 + 12 // mout + log.Printf("result %x", r.Bytes()) if n != n_expect { t.Fatalf("expected total %v bytes output, got %v", n_expect, n) } + r_expect_hex := "000700010578797a7a7902029a000804696e6b790570696e6b79000303666f6f023432000a036261720b626172206261726220617a" + r_expect, err := hex.DecodeString(r_expect_hex) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(r.Bytes(), r_expect) { + t.Fatalf("expected result %v, got %x", r_expect_hex, r.Bytes()) + } }