Add brainfuck script in go
This commit is contained in:
commit
62398ca2ed
|
@ -0,0 +1 @@
|
||||||
|
brainfuck
|
|
@ -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
|
||||||
|
}
|
Reference in New Issue