-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enhancement: Implement tis100 assembly parser with participle (#1)
Signed-off-by: Oğuzhan Durgun <oguzhandurgun95@gmail.com>
- Loading branch information
1 parent
5f046b3
commit b858476
Showing
28 changed files
with
603 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# TIS100 | ||
|
||
A tool and package to parse TIS100 assembly programs. | ||
|
||
## CLI Usage | ||
|
||
### Command `tis100 parse <path>` | ||
|
||
Parses the TIS100 assembly program in the given `<path>`, and prints the AST result into standard output. | ||
|
||
``` | ||
MOV 10, ACC | ||
MOV ACC, DOWN | ||
``` | ||
|
||
```bash | ||
-> tis100 parse ~/program.asm | ||
``` | ||
|
||
The result for the above execution looks like this; | ||
|
||
```yaml | ||
instructions: | ||
- mov: | ||
source: | ||
literal: 10 | ||
destination: | ||
register: ACC | ||
- mov: | ||
source: | ||
register: ACC | ||
destination: | ||
register: DOWN | ||
``` | ||
## Package Usage | ||
```bash | ||
go get github.com/oguzhand95/tis100 | ||
``` | ||
|
||
```go | ||
import "github.com/oguzhand95/tis100/parser" | ||
|
||
func main() { | ||
b, err := os.ReadFile(c.Path) | ||
if err != nil { | ||
return fmt.Errorf("failed to open the file in path %s: %w", c.Path, err) | ||
} | ||
|
||
ast, err := parser.Parse(bytes.NewReader(b), filepath.Base(c.Path)) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse the program: %w", err) | ||
} | ||
|
||
// Use ast struct to some stuff | ||
} | ||
``` | ||
|
||
# Thanks | ||
|
||
- Thanks [Zachtronics](https://www.zachtronics.com/) for developing this awesome [puzzle game](https://store.steampowered.com/app/370360/TIS100/)! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,18 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"github.com/alecthomas/kong" | ||
|
||
"github.com/oguzhand95/tis100/cmd/root" | ||
) | ||
|
||
func main() { | ||
log.Println("hello") | ||
cli := &root.Cli{} | ||
ctx := kong.Parse(cli, | ||
kong.Name("tis100"), | ||
kong.Description("A command line interface to do TIS100 related jobs"), | ||
kong.UsageOnError(), | ||
) | ||
|
||
ctx.FatalIfErrorf(ctx.Run()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package parse | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/alecthomas/kong" | ||
"gopkg.in/yaml.v3" | ||
|
||
"github.com/oguzhand95/tis100/parser" | ||
) | ||
|
||
const help = `Parse TIS100 assembly program and output the AST tree` | ||
|
||
type Cmd struct { | ||
Path string `arg:"" name:"path" help:"path to tis100 assembly program"` | ||
} | ||
|
||
func (c *Cmd) Run(k *kong.Kong) error { | ||
b, err := os.ReadFile(c.Path) | ||
if err != nil { | ||
return fmt.Errorf("failed to open the file in path %s: %w", c.Path, err) | ||
} | ||
|
||
ast, err := parser.Parse(bytes.NewReader(b), filepath.Base(c.Path)) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse the program: %w", err) | ||
} | ||
|
||
y, err := yaml.Marshal(ast) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal AST of the parsed TIS100 program: %w", err) | ||
} | ||
|
||
_, err = fmt.Fprint(k.Stdout, string(y)) | ||
if err != nil { | ||
return fmt.Errorf("failed to print the AST to the stdout: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *Cmd) Help() string { | ||
return help | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package root | ||
|
||
import "github.com/oguzhand95/tis100/cmd/parse" | ||
|
||
type Cli struct { | ||
Parse parse.Cmd `cmd:"" name:"parse"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,15 @@ | ||
module github.com/oguzhand95/tis100 | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/alecthomas/kong v0.6.1 | ||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 | ||
github.com/stretchr/testify v1.8.0 | ||
gopkg.in/yaml.v3 v3.0.1 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg= | ||
github.com/alecthomas/kong v0.6.1 h1:1kNhcFepkR+HmasQpbiKDLylIL8yh5B5y1zPp5bJimA= | ||
github.com/alecthomas/kong v0.6.1/go.mod h1:JfHWDzLmbh/puW6I3V7uWenoh56YNVONW+w8eKeUr9I= | ||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo= | ||
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM= | ||
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= | ||
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= | ||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package parser | ||
|
||
type Program struct { | ||
Instructions []*Instruction `yaml:"instructions" parser:"@@*"` | ||
} | ||
|
||
type Instruction struct { | ||
SimpleOp *SimpleOp `yaml:"simpleOp,omitempty" parser:"( @('NOP'|'SWP'|'SAV'|'NEG')"` | ||
Add *Add `yaml:"add,omitempty" parser:"| 'ADD' @@"` | ||
Mov *Mov `yaml:"mov,omitempty" parser:"| 'MOV' @@"` | ||
Jmp *Jmp `yaml:"jmp,omitempty" parser:"| 'JMP' @@"` | ||
Jez *Jez `yaml:"jez,omitempty" parser:"| 'JEZ' @@"` | ||
Jnz *Jnz `yaml:"jnz,omitempty" parser:"| 'JNZ' @@"` | ||
Jgz *Jgz `yaml:"jgz,omitempty" parser:"| 'JGZ' @@"` | ||
Jlz *Jlz `yaml:"jlz,omitempty" parser:"| 'JLZ' @@"` | ||
Jro *Jro `yaml:"jro,omitempty" parser:"| 'JRO' @@"` | ||
Sub *Sub `yaml:"sub,omitempty" parser:"| 'SUB' @@"` | ||
Label string `yaml:"label,omitempty" parser:"| @(Ident) Colon)"` | ||
} | ||
|
||
type Mov struct { | ||
Source *Param `yaml:"source" parser:"@@ ParamSep"` | ||
Destination *Param `yaml:"destination" parser:"@@"` | ||
} | ||
|
||
type Add struct { | ||
Source *Param `yaml:"source" parser:"@@"` | ||
} | ||
|
||
type Sub struct { | ||
Source *Param `yaml:"source" parser:"@@"` | ||
} | ||
|
||
type Jmp struct { | ||
Label string `yaml:"label" parser:"@Ident"` | ||
} | ||
|
||
type Jez struct { | ||
Label string `yaml:"label" parser:"@Ident"` | ||
} | ||
|
||
type Jnz struct { | ||
Label string `yaml:"label" parser:"@Ident"` | ||
} | ||
|
||
type Jgz struct { | ||
Label string `yaml:"label" parser:"@Ident"` | ||
} | ||
|
||
type Jlz struct { | ||
Label string `yaml:"label" parser:"@Ident"` | ||
} | ||
|
||
type Jro struct { | ||
Source *Param `yaml:"source" parser:"@@"` | ||
} | ||
|
||
type Param struct { | ||
Register *Register `yaml:"register,omitempty" parser:"( @('ACC'|'BAK'|'NIL'|'LEFT'|'UP'|'RIGHT'|'DOWN'|'ANY'|'LAST') |"` | ||
Literal *int `yaml:"literal,omitempty" parser:"@Literal |"` | ||
Label *string `yaml:"label,omitempty" parser:"@Ident )"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package parser | ||
|
||
type SimpleOp string | ||
|
||
const ( | ||
OpNop SimpleOp = "NOP" | ||
OpSwp SimpleOp = "SWP" | ||
OpSav SimpleOp = "SAV" | ||
OpNeg SimpleOp = "NEG" | ||
) | ||
|
||
type Register string | ||
|
||
const ( | ||
RegisterAcc Register = "ACC" | ||
RegisterBak Register = "BAK" | ||
RegisterNil Register = "NIL" | ||
RegisterLeft Register = "LEFT" | ||
RegisterUp Register = "UP" | ||
RegisterRight Register = "RIGHT" | ||
RegisterDown Register = "DOWN" | ||
RegisterAny Register = "ANY" | ||
RegisterLast Register = "LAST" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package parser | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
|
||
"github.com/alecthomas/participle/v2" | ||
"github.com/alecthomas/participle/v2/lexer" | ||
) | ||
|
||
const lookahead = 2 | ||
|
||
var l = lexer.MustSimple([]lexer.SimpleRule{ | ||
{Name: "Ident", Pattern: `[A-Z]+`}, | ||
{Name: "Colon", Pattern: `:`}, | ||
{Name: "Literal", Pattern: `([-]?[0-9]+)`}, | ||
{Name: "ParamSep", Pattern: `,([ ]+)?`}, | ||
{Name: "Whitespace", Pattern: `[ \t]+`}, | ||
{Name: "EOL", Pattern: `[\n\r]+`}, | ||
}) | ||
|
||
func Parse(r io.Reader, name string) (*Program, error) { | ||
p, err := participle.Build[Program]( | ||
participle.Lexer(l), | ||
participle.UseLookahead(lookahead), | ||
participle.Elide("EOL", "Whitespace"), | ||
) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create a parser: %w", err) | ||
} | ||
|
||
b, err := io.ReadAll(r) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read all bytes from the given reader: %w", err) | ||
} | ||
|
||
ast, err := p.ParseBytes(name, b) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse from bytes: %w", err) | ||
} | ||
|
||
return ast, nil | ||
} |
Oops, something went wrong.