Add asm parser

This commit is contained in:
lash 2023-04-04 10:32:39 +01:00
parent d95d27f8fe
commit 664eab98d9
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 166 additions and 11 deletions

118
go/asm/asm.go Normal file
View File

@ -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
}

26
go/asm/asm_test.go Normal file
View File

@ -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)
}
}

View File

@ -1,7 +1,9 @@
package vm package asm
import ( import (
"fmt" "fmt"
"git.defalsify.org/festive/vm"
) )
type BatchCode uint16 type BatchCode uint16
@ -61,19 +63,21 @@ func (mp *MenuProcessor) ToLines() []byte {
postLines := []byte{} postLines := []byte{}
for _, v := range mp.items { for _, v := range mp.items {
preLines = NewLine(preLines, MOUT, []string{v.choice, v.display}, nil, nil) preLines = vm.NewLine(preLines, vm.MOUT, []string{v.choice, v.display}, nil, nil)
switch v.code { switch v.code {
case MENU_UP: case MENU_UP:
postLines = NewLine(postLines, INCMP, []string{v.choice, "_"}, nil, nil) postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, "_"}, nil, nil)
case MENU_NEXT: case MENU_NEXT:
_ = postLines _ = postLines
case MENU_PREVIOUS: case MENU_PREVIOUS:
_ = postLines _ = postLines
default: default:
postLines = NewLine(postLines, INCMP, []string{v.choice, v.target}, nil, nil) postLines = vm.NewLine(postLines, vm.INCMP, []string{v.choice, v.target}, nil, nil)
} }
} }
preLines = NewLine(preLines, HALT, nil, nil, nil) preLines = vm.NewLine(preLines, vm.HALT, nil, nil, nil)
return append(preLines, postLines...) return append(preLines, postLines...)
} }

View File

@ -1,7 +1,9 @@
package vm package asm
import ( import (
"testing" "testing"
"git.defalsify.org/festive/vm"
) )
@ -28,7 +30,7 @@ func TestMenuInterpreter(t *testing.T) {
t.Errorf("expected error on invalid menu item 'BOGUS'") t.Errorf("expected error on invalid menu item 'BOGUS'")
} }
b := m.ToLines() b := m.ToLines()
r, err := ToString(b) r, err := vm.ToString(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -2,4 +2,7 @@ module git.defalsify.org/festive
go 1.20 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
)

View File

@ -52,7 +52,8 @@ func ParseAll(b []byte, w io.Writer) (int, error) {
vv = 1 vv = 1
} }
if w != nil { 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 { if m {
vv = 1 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: case LOAD:
@ -153,7 +155,7 @@ func ParseAll(b []byte, w io.Writer) (int, error) {
return rn, err return rn, err
} }
rn += n rn += n
log.Printf("wrote %v bytes from instruction %v", n, s) log.Printf("wrote %v bytes for instruction %v", n, s)
} }
//rs += "\n" //rs += "\n"