commit 28c1e49c0224de7ae71fcce230995bd612a1b5b0
parent 573382e878c41f7684b2544e9862b69b89071aae
Author: david cochran <about.trout@gmail.com>
Date: Mon, 11 Dec 2023 15:16:34 -0800
fixes #4 - execute commands from unix pipes
Diffstat:
| M | cmd/gbfy/main.go | | | 124 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
1 file changed, 79 insertions(+), 45 deletions(-)
diff --git a/cmd/gbfy/main.go b/cmd/gbfy/main.go
@@ -13,71 +13,59 @@ import (
)
var (
- codeFile = flag.String("f", "", "Path to Brainfuck file to interpret")
- inputFile = flag.String("i", "", "Path to file containing input data for program")
- launchREPL = flag.Bool("repl", false, "Launch interactive interpreter before exit")
+ codeFile = flag.String("f", "", "Path to Brainfuck program to execute")
+ dataFile = flag.String("d", "", "Path to file containing input data for program")
+ endInteractive = flag.Bool("i", false, "Launch interactive interpreter before exit")
)
func main() {
flag.Parse()
var (
- err error
- cmds []byte
- input []byte
+ input []byte
+ output bytes.Buffer
)
- if *codeFile != "" {
- cmds, err = os.ReadFile(*codeFile)
- if err != nil {
- log.Fatalf("Failed to read code file: %v", err)
- }
- }
- if *inputFile != "" {
- input, err = os.ReadFile(*inputFile)
- if err != nil {
+ if *dataFile != "" {
+ var err error
+ if input, err = os.ReadFile(*dataFile); err != nil {
log.Fatalf("Failed to read input file: %v", err)
}
}
- var output bytes.Buffer
bf := gbfy.New(bytes.NewBuffer(input), &output)
- if err != nil {
- log.Fatalf("Failed to initialize interpreter: %v", err)
- }
-
- if len(cmds) > 0 {
- for _, cmd := range cmds {
- if err := bf.Eval(cmd); err != nil {
- log.Fatalf("Failed to Eval command %q: %v", cmd, err)
- }
+ if *codeFile != "" {
+ if err := runCodeFile(bf); err != nil {
+ log.Fatalf("Execution failed: %v", err)
}
- log.Printf("Output from execution: %v\n", output.Bytes())
+ } else if err := runPiped(bf); err != nil {
+ log.Fatalf("Execution failed: %v", err)
}
- if *launchREPL {
- log.Println("Starting interactive REPL")
+ if *endInteractive {
+ log.Println("Starting interactive REPL ...")
repl(bf)
}
}
-const (
- welcomeMsg = `Go Brainfuck Yourself!
+const welcomeMsg = `Go Brainfuck Yourself!
:q[uit] to exit REPL loop
:d[ump] to dump interpreter state
:f[uck] to reset interpreter state`
- prompt = "gbfy> "
-)
-
func repl(bf *gbfy.Brainfuck) {
fmt.Println(welcomeMsg)
- in := bufio.NewReader(os.Stdin)
+
+ f, err := os.Open("/dev/tty")
+ if err != nil {
+ log.Fatalf("Failed to open TTY: %v", err)
+ }
+ in := bufio.NewReader(f)
+
for {
- fmt.Print(prompt)
+ fmt.Print("gbfy> ")
line, err := in.ReadString('\n')
if err == io.EOF {
- fmt.Println("")
- return
+ break
} else if err != nil {
log.Fatalf("Error! %v", err)
}
@@ -85,25 +73,71 @@ func repl(bf *gbfy.Brainfuck) {
if len(line) > 0 && line[0] == ':' {
switch line[1] {
case 'd':
- replDump(bf)
+ formatDump(bf.Dump())
case 'f':
bf.Reset()
fmt.Println("Reset interpreter!")
case 'q':
- return
+ break
}
} else {
- for _, cmd := range []byte(line) {
- if err := bf.Eval(cmd); err != nil {
- log.Fatalf("Failed to Eval command %q: %v", cmd, err)
- }
+ r := bufio.NewReader(bytes.NewReader([]byte(line)))
+ if err := runCommands(bf, r); err != nil {
+ log.Fatalf("Execution failed: %v", err)
}
}
}
}
-func replDump(bf *gbfy.Brainfuck) {
- d, cells, i, cmds, out := bf.Dump()
+func runCodeFile(bf *gbfy.Brainfuck) error {
+ f, err := os.Open(*codeFile)
+ if err != nil {
+ return err
+ }
+ in := bufio.NewReader(f)
+ if err := runCommands(bf, in); err != nil {
+ return err
+ }
+ logOutput(bf)
+ return nil
+}
+
+func runPiped(bf *gbfy.Brainfuck) error {
+ stat, err := os.Stdin.Stat()
+ if err != nil {
+ return err
+ }
+ if (stat.Mode() & os.ModeCharDevice) == 0 {
+ in := bufio.NewReader(os.Stdin)
+ if err := runCommands(bf, in); err != nil {
+ return err
+ }
+ }
+ logOutput(bf)
+ return nil
+}
+
+func runCommands(bf *gbfy.Brainfuck, r *bufio.Reader) error {
+ for {
+ cmd, err := r.ReadByte()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return fmt.Errorf("failed to ReadByte: %v", err)
+ }
+ if err := bf.Eval(cmd); err != nil {
+ return fmt.Errorf("failed to Eval %q: %v", cmd, err)
+ }
+ }
+ return nil
+}
+
+func logOutput(bf *gbfy.Brainfuck) {
+ _, _, _, _, out := bf.Dump()
+ log.Printf("Output from execution: %v\n", out)
+}
+
+func formatDump(d int, cells []byte, i int, cmds []byte, out []byte) {
fmt.Printf("Cells; d: %d, current cell value: %x\n", d, cells[d])
fmt.Printf("Cmds: i: %d, current command: %q\n", i, cmds[i-1])
fmt.Printf("Out: %v\n", out)