go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit 664eab98d97deacd1d299994275bcca74be7ca3e
parent d95d27f8fe5fe87954278c604b0451a9553d7896
Author: lash <dev@holbrook.no>
Date:   Tue,  4 Apr 2023 10:32:39 +0100

Add asm parser

Diffstat:
Ago/asm/asm.go | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ago/asm/asm_test.go | 26++++++++++++++++++++++++++
Ago/asm/menu.go | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ago/asm/menu_test.go | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mgo/go.mod | 5++++-
Mgo/vm/debug.go | 8+++++---
Dgo/vm/interpreter.go | 79-------------------------------------------------------------------------------
Dgo/vm/interpreter_test.go | 46----------------------------------------------
8 files changed, 284 insertions(+), 129 deletions(-)

diff --git a/go/asm/asm.go b/go/asm/asm.go @@ -0,0 +1,118 @@ +package asm + +import ( + "fmt" + "io" + "strings" + + "github.com/alecthomas/participle/v2" + "github.com/alecthomas/participle/v2/lexer" +) + +type Asm struct { + Instructions []*Instruction `@@*` +} + +type Display struct { + Sym string `@Sym Whitespace` + Val string `@Quote @Sym @Quote Whitespace` +} + +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 Single struct { + One string `@Sym Whitespace` +} + +func(s Single) String() string { + return fmt.Sprintf("Single: %v", s.One) +} + +type Double struct { + One string `@Sym Whitespace` + Two string `@Sym Whitespace` +} + +func(d Double) String() string { + return fmt.Sprintf("Double: %v %v", d.One, d.Two) +} + +type Sized struct { + Sym string `@Sym Whitespace` + Size uint32 `@Size Whitespace` + X uint32 `(@Size Whitespace)?` +} + +func(s Sized) String() string { + return fmt.Sprintf("Sized: %v %v", s.Sym, s.Size) +} + +type Arg struct { + ArgNone string "Whitespace?" + ArgDisplay *Display `@@?` + ArgSized *Sized `@@?` + ArgSingle *Single `@@?` + ArgDouble *Double `@@?` +} + +func (a Arg) String() string { + if a.ArgDisplay != nil { + return fmt.Sprintf("%s", a.ArgDisplay) + } + if a.ArgSized != nil { + return fmt.Sprintf("%s", a.ArgSized) + } + if a.ArgSingle != nil { + return fmt.Sprintf("%s", a.ArgSingle) + } + if a.ArgDouble != nil { + return fmt.Sprintf("%s", a.ArgDouble) + } + return "" +} + +type Instruction struct { + OpCode string `@Ident` + OpArg Arg `@@` + Comment string `Comment?` +} + +func (i Instruction) String() string { + return fmt.Sprintf("%s %s", i.OpCode, i.OpArg) +} + +var ( + asmLexer = lexer.MustSimple([]lexer.SimpleRule{ + {"Comment", `(?:#)[^\n]*\n?`}, + {"Ident", `^[A-Z]+`}, + {"Sym", `[a-zA-Z]+`}, + {"Size", `[0-9]+`}, + {"Whitespace", `[ \t\n\r]+`}, + {"Quote", `["']`}, + }) + asmParser = participle.MustBuild[Asm]( + participle.Lexer(asmLexer), + participle.Elide("Comment", "Whitespace"), + ) +) + +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 { + fmt.Printf("%v %v\n", i, v) + } + return 0, err +} diff --git a/go/asm/asm_test.go b/go/asm/asm_test.go @@ -0,0 +1,26 @@ +package asm + +import ( + "log" + "testing" + + "git.defalsify.org/festive/vm" +) + + +func TestParserInit(t *testing.T) { + var b []byte + b = vm.NewLine(b, vm.HALT, nil, nil, nil) + b = vm.NewLine(b, vm.CATCH, []string{"xyzzy"}, []byte{0x02, 0x9a}, []uint8{1}) + b = vm.NewLine(b, vm.LOAD, []string{"foo"}, []byte{42}, nil) + 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) + } + if n != 0 { + t.Fatalf("expected 0 byte write count, got %v", n) + } +} diff --git a/go/asm/menu.go b/go/asm/menu.go @@ -0,0 +1,83 @@ +package asm + +import ( + "fmt" + + "git.defalsify.org/festive/vm" +) + +type BatchCode uint16 + +const ( + _MENU_OFFSET = 256 + MENU_DOWN = _MENU_OFFSET + MENU_UP = _MENU_OFFSET + 1 + MENU_NEXT = _MENU_OFFSET + 2 + MENU_PREVIOUS = _MENU_OFFSET + 3 + //MENU_BROWSE = _MENU_OFFSET + 4 +) + +var ( + batchCode = map[string]BatchCode{ + "DOWN": MENU_DOWN, + "UP": MENU_UP, + "NEXT": MENU_NEXT, + "PREVIOUS": MENU_PREVIOUS, + //"BROWSE": MENU_BROWSE, + } +) + +type menuItem struct { + code BatchCode + choice string + display string + target string +} + +type MenuProcessor struct { + items []menuItem + size uint32 +} + +func NewMenuProcessor() MenuProcessor { + return MenuProcessor{} +} + +func(mp *MenuProcessor) Add(bop string, choice string, display string, target string) error { + bopCode := batchCode[bop] + if bopCode == 0 { + return fmt.Errorf("unknown menu instruction: %v", bop) + } + m := menuItem{ + code: bopCode, + choice: choice, + display: display, + target: target, + } + mp.items = append(mp.items, m) + return nil +} + +func (mp *MenuProcessor) ToLines() []byte { + preLines := []byte{} + postLines := []byte{} + + for _, v := range mp.items { + preLines = vm.NewLine(preLines, vm.MOUT, []string{v.choice, v.display}, nil, nil) + switch v.code { + case MENU_UP: + postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, "_"}, nil, nil) + case MENU_NEXT: + _ = postLines + case MENU_PREVIOUS: + _ = postLines + default: + postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, v.target}, nil, nil) + } + } + + preLines = vm.NewLine(preLines, vm.HALT, nil, nil, nil) + return append(preLines, postLines...) +} + + diff --git a/go/asm/menu_test.go b/go/asm/menu_test.go @@ -0,0 +1,48 @@ +package asm + +import ( + "testing" + + "git.defalsify.org/festive/vm" +) + + +func TestMenuInterpreter(t *testing.T) { + m := NewMenuProcessor() + err := m.Add("DOWN", "0", "inky", "foo") + if err != nil { + t.Fatal(err) + } + err = m.Add("NEXT", "1", "pinky", "bar") + if err != nil { + t.Fatal(err) + } + err = m.Add("PREVIOUS", "2", "blinky clyde", "baz") + if err != nil { + t.Fatal(err) + } + err = m.Add("UP", "99", "tinky-winky", "xyzzy") + if err != nil { + t.Fatal(err) + } + err = m.Add("BOGUS", "42", "lala poo", "plugh") + if err == nil { + t.Errorf("expected error on invalid menu item 'BOGUS'") + } + b := m.ToLines() + r, err := vm.ToString(b) + if err != nil { + t.Fatal(err) + } + expect := `MOUT 0 "inky" +MOUT 1 "pinky" +MOUT 2 "blinky clyde" +MOUT 99 "tinky-winky" +HALT +INCMP 0 foo +INCMP 99 _ +` + if r != expect { + t.Errorf("expected:\n\t%v\ngot:\n\t%v\n", expect, r) + } +} diff --git a/go/go.mod b/go/go.mod @@ -2,4 +2,7 @@ module git.defalsify.org/festive go 1.20 -require github.com/peteole/testdata-loader v0.3.0 +require ( + github.com/alecthomas/participle/v2 v2.0.0 + github.com/peteole/testdata-loader v0.3.0 +) diff --git a/go/vm/debug.go b/go/vm/debug.go @@ -52,7 +52,8 @@ func ParseAll(b []byte, w io.Writer) (int, error) { vv = 1 } if w != nil { - rs = fmt.Sprintf("%s %s %v %v # invertmatch=%v\n", s, r, n, vv, m) + //rs = fmt.Sprintf("%s %s %v %v # invertmatch=%v\n", s, r, n, vv, m) + rs = fmt.Sprintf("%s %s %v %v\n", s, r, n, vv) } } } @@ -65,7 +66,8 @@ func ParseAll(b []byte, w io.Writer) (int, error) { if m { vv = 1 } - rs = fmt.Sprintf("%s %v %v # invertmatch=%v\n", s, n, vv, m) + //rs = fmt.Sprintf("%s %v %v # invertmatch=%v\n", s, n, vv, m) + rs = fmt.Sprintf("%s %v %v\n", s, n, vv) } } case LOAD: @@ -153,7 +155,7 @@ func ParseAll(b []byte, w io.Writer) (int, error) { return rn, err } rn += n - log.Printf("wrote %v bytes from instruction %v", n, s) + log.Printf("wrote %v bytes for instruction %v", n, s) } //rs += "\n" diff --git a/go/vm/interpreter.go b/go/vm/interpreter.go @@ -1,79 +0,0 @@ -package vm - -import ( - "fmt" -) - -type BatchCode uint16 - -const ( - _MENU_OFFSET = 256 - MENU_DOWN = _MENU_OFFSET - MENU_UP = _MENU_OFFSET + 1 - MENU_NEXT = _MENU_OFFSET + 2 - MENU_PREVIOUS = _MENU_OFFSET + 3 - //MENU_BROWSE = _MENU_OFFSET + 4 -) - -var ( - batchCode = map[string]BatchCode{ - "DOWN": MENU_DOWN, - "UP": MENU_UP, - "NEXT": MENU_NEXT, - "PREVIOUS": MENU_PREVIOUS, - //"BROWSE": MENU_BROWSE, - } -) - -type menuItem struct { - code BatchCode - choice string - display string - target string -} - -type MenuProcessor struct { - items []menuItem - size uint32 -} - -func NewMenuProcessor() MenuProcessor { - return MenuProcessor{} -} - -func(mp *MenuProcessor) Add(bop string, choice string, display string, target string) error { - bopCode := batchCode[bop] - if bopCode == 0 { - return fmt.Errorf("unknown menu instruction: %v", bop) - } - m := menuItem{ - code: bopCode, - choice: choice, - display: display, - target: target, - } - mp.items = append(mp.items, m) - return nil -} - -func (mp *MenuProcessor) ToLines() []byte { - preLines := []byte{} - postLines := []byte{} - - for _, v := range mp.items { - preLines = NewLine(preLines, MOUT, []string{v.choice, v.display}, nil, nil) - switch v.code { - case MENU_UP: - postLines = NewLine(postLines, INCMP, []string{v.choice, "_"}, nil, nil) - case MENU_NEXT: - _ = postLines - case MENU_PREVIOUS: - _ = postLines - default: - postLines = NewLine(postLines, INCMP, []string{v.choice, v.target}, nil, nil) - } - } - - preLines = NewLine(preLines, HALT, nil, nil, nil) - return append(preLines, postLines...) -} diff --git a/go/vm/interpreter_test.go b/go/vm/interpreter_test.go @@ -1,46 +0,0 @@ -package vm - -import ( - "testing" -) - - -func TestMenuInterpreter(t *testing.T) { - m := NewMenuProcessor() - err := m.Add("DOWN", "0", "inky", "foo") - if err != nil { - t.Fatal(err) - } - err = m.Add("NEXT", "1", "pinky", "bar") - if err != nil { - t.Fatal(err) - } - err = m.Add("PREVIOUS", "2", "blinky clyde", "baz") - if err != nil { - t.Fatal(err) - } - err = m.Add("UP", "99", "tinky-winky", "xyzzy") - if err != nil { - t.Fatal(err) - } - err = m.Add("BOGUS", "42", "lala poo", "plugh") - if err == nil { - t.Errorf("expected error on invalid menu item 'BOGUS'") - } - b := m.ToLines() - r, err := ToString(b) - if err != nil { - t.Fatal(err) - } - expect := `MOUT 0 "inky" -MOUT 1 "pinky" -MOUT 2 "blinky clyde" -MOUT 99 "tinky-winky" -HALT -INCMP 0 foo -INCMP 99 _ -` - if r != expect { - t.Errorf("expected:\n\t%v\ngot:\n\t%v\n", expect, r) - } -}