Add brainfuck script in go

This commit is contained in:
Melon 2020-10-20 19:46:07 +01:00
commit 62398ca2ed
3 changed files with 231 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
brainfuck

227
brainfuck.go Normal file
View File

@ -0,0 +1,227 @@
package main
import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/fatih/color"
"github.com/forestgiant/sliceutil"
flag "github.com/spf13/pflag"
)
func main() {
bf := BrainfuckEmulator{}
var err error
err = bf.New()
if err != nil {
if strings.HasSuffix(err.Error(), "::ignore") {
return
}
panic(err)
}
err = bf.Run()
if err != nil {
if strings.HasSuffix(err.Error(), "::ignore") {
return
}
panic(err)
}
}
// BrainfuckEmulator is used to emulate brainfuck.
type BrainfuckEmulator struct {
code string
pairs [][]int
memory []int
execution int
pointer int
debug bool
filename string
}
// New instance of BrainfuckEmulator.
func (bf *BrainfuckEmulator) New() error {
var err error
err = bf.args()
if err != nil {
return err
}
err = bf.readScript(bf.filename)
if err != nil {
return err
}
err = bf.getBracketPairs()
if err != nil {
return err
}
return nil
}
func (bf *BrainfuckEmulator) args() error {
debugptr := flag.BoolP("debug", "d", false, "Enable debug mode")
flag.Parse()
args := flag.Args()
if len(args) == 1 {
bf.filename = args[0]
bf.debug = *debugptr
} else {
fmt.Fprintln(os.Stdout, "Brainfuck help")
fmt.Fprintln(os.Stdout, "usage: brainfuck <filename>")
flag.PrintDefaults()
return errors.New("bf: invalid arguments ::ignore")
}
return nil
}
func (bf *BrainfuckEmulator) fancyoutput() {
for i := 0; i < len(bf.memory); i++ {
if bf.pointer == i {
color.Set(color.FgRed)
fmt.Fprintf(os.Stdout, fmt.Sprint(bf.memory[i]))
color.Unset()
} else {
fmt.Fprintf(os.Stdout, fmt.Sprint(bf.memory[i]))
}
if i < len(bf.memory)-1 {
fmt.Fprintf(os.Stdout, ",")
}
}
fmt.Fprintln(os.Stdout, "")
for i := 0; i < len(bf.code); i++ {
if bf.execution == i {
color.Set(color.FgRed)
fmt.Fprintf(os.Stdout, string(bf.code[i]))
color.Unset()
} else {
fmt.Fprintf(os.Stdout, string(bf.code[i]))
}
}
fmt.Fprintln(os.Stdout, "")
}
// Run the brainfuck program.
func (bf *BrainfuckEmulator) Run() error {
bf.pointer = 0
bf.execution = 0
bf.memory = []int{0}
for true {
if bf.debug {
bf.fancyoutput()
}
if bf.execution >= len(bf.code) {
break
}
switch bf.code[bf.execution] {
case '+':
bf.memory[bf.pointer]++
if bf.memory[bf.pointer] == 256 {
bf.memory[bf.pointer] = 0
}
case '-':
bf.memory[bf.pointer]--
if bf.memory[bf.pointer] == -1 {
bf.memory[bf.pointer] = 255
}
case '>':
bf.pointer++
if len(bf.memory) <= bf.pointer {
bf.memory = append(bf.memory, 0)
}
case '<':
bf.pointer--
if bf.pointer < 0 {
fmt.Fprintln(os.Stdout, "Memory underflow: pointer can't be less than 0")
return errors.New("bf: memory underflow ::ignore")
}
case '[':
if bf.memory[bf.pointer] == 0 {
for i := 0; i < len(bf.pairs[0]); i++ {
if bf.pairs[0][i] == bf.execution {
bf.execution = bf.pairs[1][i]
break
}
}
}
case ']':
if bf.memory[bf.pointer] != 0 {
for i := 0; i < len(bf.pairs[1]); i++ {
if bf.pairs[1][i] == bf.execution {
bf.execution = bf.pairs[0][i]
break
}
}
}
case '@':
bf.pointer = 0
case '$':
bf.fancyoutput()
case ',':
char := make([]byte, 1)
os.Stdin.Read(char)
bf.memory[bf.pointer] = int(char[0])
case '.':
b := byte(bf.memory[bf.pointer])
os.Stdout.Write([]byte{b})
}
bf.execution++
}
return nil
}
func (bf *BrainfuckEmulator) readScript(filename string) error {
filebuffer, err := ioutil.ReadFile(filename)
if err != nil {
if strings.HasSuffix(err.Error(), "no such file or directory") {
fmt.Fprintln(os.Stdout, "IO Error: no such file or directory")
return errors.New("bf: file missing ::ignore")
}
return err
}
inputdata := string(filebuffer)
data := bufio.NewScanner(strings.NewReader(inputdata))
data.Split(bufio.ScanRunes)
allowed := []string{"+", "-", "<", ">", "[", "]", ",", ".", "@"}
final := ""
for data.Scan() {
if sliceutil.Contains(allowed, data.Text()) {
final += data.Text()
}
}
bf.code = final
return nil
}
func (bf *BrainfuckEmulator) getBracketPairs() error {
pairs := [][]int{{}, {}}
temp := []int{}
var err error
for i := 0; i < len(bf.code); i++ {
if bf.code[i] == '[' {
temp = append(temp, i)
} else if bf.code[i] == ']' {
if len(temp) > 0 {
pairs[0] = append(pairs[0], temp[len(temp)-1])
pairs[1] = append(pairs[1], i)
temp = temp[:len(temp)-1]
} else {
fmt.Fprintln(os.Stdout, "Syntax error: missing opening bracket")
return errors.New("bf: missing opening bracket ::ignore")
}
}
}
if len(temp) != 0 {
fmt.Fprintln(os.Stdout, "Syntax error: spare opening bracket")
return errors.New("bf: sqare opening brackets ::ignore")
}
bf.pairs = pairs
return err
}

3
build Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
go build -o brainfuck
sudo cp ./brainfuck /usr/bin/brainfuck