Compare commits
5 Commits
cfae69c0c2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7d948cdcd | ||
|
|
dcd8c56c0d | ||
|
|
a52e5d3426 | ||
|
|
b0068336cd | ||
|
|
3be08736b4 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/cmd/creature/creature
|
||||||
10
cmd/creature/examples/echo
Normal file
10
cmd/creature/examples/echo
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
0 0
|
||||||
|
F
|
||||||
|
|
||||||
|
0 1
|
||||||
|
F
|
||||||
|
|
||||||
|
0 1
|
||||||
|
0 0
|
||||||
|
E
|
||||||
BIN
cmd/creature/examples/echobin
Normal file
BIN
cmd/creature/examples/echobin
Normal file
Binary file not shown.
112
cmd/creature/main.go
Normal file
112
cmd/creature/main.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
import "os"
|
||||||
|
import "fmt"
|
||||||
|
import "bufio"
|
||||||
|
import "strconv"
|
||||||
|
import cre "git.tebibyte.media/sashakoshka/creature"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
logLine("ERR file unspecified")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
logLine("ERR could not open file: " + err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
program, block, err := readFile(file)
|
||||||
|
if err != nil {
|
||||||
|
logLine("ERR could not read file: " + err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
machine := cre.Machine[int]{}
|
||||||
|
|
||||||
|
machine.LoadProgram(program)
|
||||||
|
machine.LoadMemory(block)
|
||||||
|
|
||||||
|
machine.Register(0, read)
|
||||||
|
machine.Register(1, write)
|
||||||
|
|
||||||
|
err = machine.Execute(0)
|
||||||
|
if err != nil {
|
||||||
|
logLine("XXX machine failed: " + err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read implements a basic input function for the creature. It waits until it
|
||||||
|
// has recieved one byte of user input, and then pushes that byte onto the
|
||||||
|
// stack.
|
||||||
|
func read(machine *cre.Machine[int]) (stop bool) {
|
||||||
|
ch := []byte{0}
|
||||||
|
os.Stdin.Read(ch)
|
||||||
|
machine.Push(int(ch[0]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// write implements a basic output function for the creature. It pops one byte
|
||||||
|
// off of the stack, and writes it to stdout.
|
||||||
|
func write(machine *cre.Machine[int]) (stop bool) {
|
||||||
|
print(string(rune(machine.Pop())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// logLine prints a message to stderr.
|
||||||
|
func logLine(message ...any) {
|
||||||
|
fmt.Fprintln(os.Stderr, message...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readFile reads data from an io.Reader into a program slice and a block slice.
|
||||||
|
// Data in the file is represented by signed hexidecimal numbers, separated by
|
||||||
|
// whitespace. Three dashes (---) divide the block data from the program data.
|
||||||
|
// See examples/echo.
|
||||||
|
func readFile(reader io.Reader) (program []int, block []int, err error) {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
scanner.Split(bufio.ScanWords)
|
||||||
|
|
||||||
|
blockLen := 0
|
||||||
|
block = make([]int, 8)
|
||||||
|
for scanner.Scan() {
|
||||||
|
if scanner.Text() == "---" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if blockLen >= len(block) {
|
||||||
|
newSlice := make([]int, len(block)*2)
|
||||||
|
copy(newSlice, block)
|
||||||
|
block = newSlice
|
||||||
|
}
|
||||||
|
var number int64
|
||||||
|
number, err = strconv.ParseInt(scanner.Text(), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
block[blockLen] = int(number)
|
||||||
|
blockLen++
|
||||||
|
}
|
||||||
|
block = block[:blockLen]
|
||||||
|
|
||||||
|
programLen := 0
|
||||||
|
program = make([]int, 8)
|
||||||
|
for scanner.Scan() {
|
||||||
|
if programLen >= len(program) {
|
||||||
|
newSlice := make([]int, len(program)*2)
|
||||||
|
copy(newSlice, program)
|
||||||
|
program = newSlice
|
||||||
|
}
|
||||||
|
var number int64
|
||||||
|
number, err = strconv.ParseInt(scanner.Text(), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
program[programLen] = int(number)
|
||||||
|
programLen++
|
||||||
|
}
|
||||||
|
program = program[:programLen]
|
||||||
|
return
|
||||||
|
}
|
||||||
15
creature.go
15
creature.go
@@ -11,10 +11,7 @@ type Word interface {
|
|||||||
// data, and provides methods to run this program data, as well as interact with
|
// data, and provides methods to run this program data, as well as interact with
|
||||||
// it.
|
// it.
|
||||||
type Machine[WORD Word] struct {
|
type Machine[WORD Word] struct {
|
||||||
// Program is not modified by the machine, and can be freely set before
|
program []WORD
|
||||||
// the machine is started.
|
|
||||||
Program []WORD
|
|
||||||
|
|
||||||
stack []WORD
|
stack []WORD
|
||||||
block []WORD
|
block []WORD
|
||||||
counter WORD
|
counter WORD
|
||||||
@@ -87,7 +84,7 @@ func (machine *Machine[WORD]) Reset() {
|
|||||||
func (machine *Machine[WORD]) Execute(offset WORD) (err error) {
|
func (machine *Machine[WORD]) Execute(offset WORD) (err error) {
|
||||||
machine.counter = offset
|
machine.counter = offset
|
||||||
|
|
||||||
for int(machine.counter) < len(machine.Program) {
|
for int(machine.counter) < len(machine.program) {
|
||||||
switch machine.instruction() {
|
switch machine.instruction() {
|
||||||
case PUSH:
|
case PUSH:
|
||||||
machine.counter++
|
machine.counter++
|
||||||
@@ -202,7 +199,7 @@ func (machine *Machine[WORD]) Execute(offset WORD) (err error) {
|
|||||||
|
|
||||||
// Instruction returns the current instruction in program memory.
|
// Instruction returns the current instruction in program memory.
|
||||||
func (machine *Machine[WORD]) instruction() (instruction WORD) {
|
func (machine *Machine[WORD]) instruction() (instruction WORD) {
|
||||||
instruction = machine.Program[machine.counter]
|
instruction = machine.program[machine.counter]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +288,12 @@ func (machine *Machine[WORD]) Unregister(id WORD) {
|
|||||||
delete(machine.functions, id)
|
delete(machine.functions, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadProgram loads the contents of program into the machine's program memory.
|
||||||
|
func (machine *Machine[WORD]) LoadProgram(program []WORD) {
|
||||||
|
machine.program = make([]WORD, len(program))
|
||||||
|
copy(machine.program, program)
|
||||||
|
}
|
||||||
|
|
||||||
// LoadMemory loads the contents of block into the machine's memory.
|
// LoadMemory loads the contents of block into the machine's memory.
|
||||||
func (machine *Machine[WORD]) LoadMemory(block []WORD) {
|
func (machine *Machine[WORD]) LoadMemory(block []WORD) {
|
||||||
machine.block = make([]WORD, len(block))
|
machine.block = make([]WORD, len(block))
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ func runMachineTest (
|
|||||||
) (
|
) (
|
||||||
machine *Machine[int],
|
machine *Machine[int],
|
||||||
) {
|
) {
|
||||||
machine = &Machine[int] { Program: program }
|
machine = &Machine[int]{}
|
||||||
|
machine.LoadProgram(program)
|
||||||
if memory != nil {
|
if memory != nil {
|
||||||
machine.LoadMemory(memory)
|
machine.LoadMemory(memory)
|
||||||
}
|
}
|
||||||
@@ -117,7 +118,6 @@ func TestComparison(test *testing.T) {
|
|||||||
PUSH, 54,
|
PUSH, 54,
|
||||||
PUSH, 6,
|
PUSH, 6,
|
||||||
NEQ,
|
NEQ,
|
||||||
|
|
||||||
}, nil, test)
|
}, nil, test)
|
||||||
|
|
||||||
neqResult := machine.Pop()
|
neqResult := machine.Pop()
|
||||||
@@ -230,7 +230,8 @@ func TestJump(test *testing.T) {
|
|||||||
|
|
||||||
func TestRegister(test *testing.T) {
|
func TestRegister(test *testing.T) {
|
||||||
output := ""
|
output := ""
|
||||||
machine := &Machine[int] { Program: []int {
|
machine := &Machine[int]{}
|
||||||
|
machine.LoadProgram([]int{
|
||||||
PUSH, int('h'),
|
PUSH, int('h'),
|
||||||
PUSH, 4,
|
PUSH, 4,
|
||||||
CAL,
|
CAL,
|
||||||
@@ -258,7 +259,7 @@ func TestRegister(test *testing.T) {
|
|||||||
PUSH, int('!'),
|
PUSH, int('!'),
|
||||||
PUSH, 4,
|
PUSH, 4,
|
||||||
CAL,
|
CAL,
|
||||||
}}
|
})
|
||||||
machine.Register(4, func(machine *Machine[int]) (stop bool) {
|
machine.Register(4, func(machine *Machine[int]) (stop bool) {
|
||||||
output += string(rune(machine.Pop()))
|
output += string(rune(machine.Pop()))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//go:build ignore
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
@@ -9,7 +10,8 @@ func main () {
|
|||||||
// this is a simple echo program. it will take in input indefinetly and
|
// this is a simple echo program. it will take in input indefinetly and
|
||||||
// repeat it. due to line buffering in the terminal however, it will
|
// repeat it. due to line buffering in the terminal however, it will
|
||||||
// only print output once you have pressed enter.
|
// only print output once you have pressed enter.
|
||||||
machine := cre.Machine[int] { Program: []int {
|
machine := cre.Machine[int]{}
|
||||||
|
machine.LoadProgram([]int{
|
||||||
cre.PUSH, 0,
|
cre.PUSH, 0,
|
||||||
cre.CAL,
|
cre.CAL,
|
||||||
|
|
||||||
@@ -19,12 +21,14 @@ func main () {
|
|||||||
cre.PUSH, 1,
|
cre.PUSH, 1,
|
||||||
cre.PUSH, 0,
|
cre.PUSH, 0,
|
||||||
cre.JMP,
|
cre.JMP,
|
||||||
}}
|
})
|
||||||
|
|
||||||
machine.Register(0, read)
|
machine.Register(0, read)
|
||||||
machine.Register(1, write)
|
machine.Register(1, write)
|
||||||
err := machine.Execute(0)
|
err := machine.Execute(0)
|
||||||
if err != nil { panic(err.Error()) }
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func read(machine *cre.Machine[int]) (stop bool) {
|
func read(machine *cre.Machine[int]) (stop bool) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
//go:build ignore
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
@@ -20,7 +21,8 @@ func main () {
|
|||||||
responseStart := 71
|
responseStart := 71
|
||||||
responseLoopStart := 50
|
responseLoopStart := 50
|
||||||
|
|
||||||
machine := cre.Machine[int] { Program: []int {
|
machine := cre.Machine[int]{}
|
||||||
|
machine.LoadProgram([]int{
|
||||||
// reset x
|
// reset x
|
||||||
cre.PUSH, introStart,
|
cre.PUSH, introStart,
|
||||||
cre.PUSH, x,
|
cre.PUSH, x,
|
||||||
@@ -108,7 +110,7 @@ func main () {
|
|||||||
cre.PUSH, 1,
|
cre.PUSH, 1,
|
||||||
cre.PUSH, responseLoopStart,
|
cre.PUSH, responseLoopStart,
|
||||||
cre.JMP,
|
cre.JMP,
|
||||||
}}
|
})
|
||||||
|
|
||||||
stringData := []byte(
|
stringData := []byte(
|
||||||
"\x00" +
|
"\x00" +
|
||||||
@@ -126,7 +128,9 @@ func main () {
|
|||||||
machine.Register(1, write)
|
machine.Register(1, write)
|
||||||
|
|
||||||
err := machine.Execute(0)
|
err := machine.Execute(0)
|
||||||
if err != nil { panic(err.Error()) }
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func read(machine *cre.Machine[int]) (stop bool) {
|
func read(machine *cre.Machine[int]) (stop bool) {
|
||||||
|
|||||||
Reference in New Issue
Block a user