113 lines
2.5 KiB
Go
113 lines
2.5 KiB
Go
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
|
|
}
|