Move panics to errors
This commit is contained in:
parent
3f83afe287
commit
e7a1e23dde
49
brainfuck.go
49
brainfuck.go
|
@ -9,14 +9,26 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MEM_MAX = 3000000
|
|
||||||
MEM_STD = 30000
|
MEM_STD = 30000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ErrMemoryOverflow struct {}
|
||||||
|
func (e ErrMemoryOverflow) Error() string { return "Memory Overflow" }
|
||||||
|
type ErrMemoryUnderflow struct {}
|
||||||
|
func (e ErrMemoryUnderflow) Error() string { return "Memory Underflow" }
|
||||||
|
type ErrInstructionLimit struct {}
|
||||||
|
func (e ErrInstructionLimit) Error() string { return "Instruction Limit Reached" }
|
||||||
|
|
||||||
type Machine struct {
|
type Machine struct {
|
||||||
array []byte
|
array []byte
|
||||||
ptr int
|
ptr int
|
||||||
reader *bufio.Reader
|
reader *bufio.Reader
|
||||||
|
|
||||||
|
// InstructionLimit prevents a runaway execution if running under a controlled environment
|
||||||
|
InstructionLimit int
|
||||||
|
|
||||||
|
// MemMax is the limit of how large memory can expand
|
||||||
|
MemMax int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a new machine with standard memory size
|
// Returns a new machine with standard memory size
|
||||||
|
@ -30,33 +42,34 @@ func New(in io.Reader) *Machine {
|
||||||
array: bytes,
|
array: bytes,
|
||||||
ptr: 0,
|
ptr: 0,
|
||||||
reader: bufio.NewReader(in),
|
reader: bufio.NewReader(in),
|
||||||
|
InstructionLimit: 0,
|
||||||
|
MemMax: 3000000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements '>'
|
// Implements '>'
|
||||||
func (m *Machine) PtrIncr() {
|
func (m *Machine) PtrIncr() error {
|
||||||
if m.ptr >= len(m.array)-1 {
|
if m.ptr >= len(m.array)-1 {
|
||||||
m.array = append(m.array, 0)
|
m.array = append(m.array, 0)
|
||||||
}
|
}
|
||||||
m.ptr += 1
|
m.ptr += 1
|
||||||
if m.ptr > MEM_MAX {
|
if m.ptr > m.MemMax {
|
||||||
panic("Memory overflow")
|
return ErrMemoryOverflow{}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements '<'
|
// Implements '<'
|
||||||
func (m *Machine) PtrDecr() {
|
func (m *Machine) PtrDecr() error {
|
||||||
if m.ptr == 0 {
|
if m.ptr == 0 {
|
||||||
panic("Memory underflow")
|
return ErrMemoryUnderflow{}
|
||||||
}
|
}
|
||||||
m.ptr -= 1
|
m.ptr -= 1
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements '+'
|
// Implements '+'
|
||||||
func (m *Machine) ByteIncr() {
|
func (m *Machine) ByteIncr() {
|
||||||
if m.ptr > len(m.array)-1 {
|
|
||||||
fmt.Printf("Memory overflow, ptr=%d\n", m.ptr)
|
|
||||||
}
|
|
||||||
m.array[m.ptr] += 1
|
m.array[m.ptr] += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,9 +98,13 @@ func (m *Machine) value() byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the whole program specified by input
|
// Run the whole program specified by input
|
||||||
func (m *Machine) Run(input []byte) {
|
func (m *Machine) Run(input []byte) error {
|
||||||
// execute the program
|
instrCount := 0
|
||||||
for ip := 0; ip < len(input); ip++ {
|
for ip := 0; ip < len(input); ip++ {
|
||||||
|
instrCount++
|
||||||
|
if m.InstructionLimit > 0 && instrCount > m.InstructionLimit {
|
||||||
|
return ErrInstructionLimit{}
|
||||||
|
}
|
||||||
instr := input[ip]
|
instr := input[ip]
|
||||||
// if *ptr == 0, jump to ]
|
// if *ptr == 0, jump to ]
|
||||||
if instr == '[' && m.value() == 0 {
|
if instr == '[' && m.value() == 0 {
|
||||||
|
@ -110,9 +127,13 @@ func (m *Machine) Run(input []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if instr == '>' {
|
} else if instr == '>' {
|
||||||
m.PtrIncr()
|
if err := m.PtrIncr(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else if instr == '<' {
|
} else if instr == '<' {
|
||||||
m.PtrDecr()
|
if err := m.PtrDecr(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else if instr == '+' {
|
} else if instr == '+' {
|
||||||
m.ByteIncr()
|
m.ByteIncr()
|
||||||
} else if instr == '-' {
|
} else if instr == '-' {
|
||||||
|
@ -124,4 +145,6 @@ func (m *Machine) Run(input []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -14,15 +15,19 @@ func main() {
|
||||||
|
|
||||||
// read in the instructions
|
// read in the instructions
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
panic("No input given")
|
fmt.Printf("No input given")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.Open(os.Args[1])
|
file, err := os.Open(os.Args[1])
|
||||||
reader := bufio.NewReader(file)
|
reader := bufio.NewReader(file)
|
||||||
instructions, err = ioutil.ReadAll(reader)
|
instructions, err = ioutil.ReadAll(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
fmt.Printf("Error: %s\n", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Run(instructions)
|
if err := m.Run(instructions); err != nil {
|
||||||
|
fmt.Printf("Error: %s\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue