Add asm parser
This commit is contained in:
parent
d95d27f8fe
commit
664eab98d9
118
go/asm/asm.go
Normal file
118
go/asm/asm.go
Normal 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
26
go/asm/asm_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
@ -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
|
||||||
|
)
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user