BrainForth
Jump to navigation
Jump to search
BrainForth is an esoteric programing language created by User:Binarycat in 2020 that combines the tape and minimal instruction set of brainfuck with Forth's word system.
There are 11 predefined words, the eight original brainfuck instructions, ':' and ';' (used for defining words), and '?' (skip next instr if current cell is 0 (I'm not super sure about this one, it may get removed from the language at some point)). The file extention is ".bfth".
Go Implementation
package main
import (
"strings"
"bufio"
"os"
)
var (
inDefMode bool
inCondMode bool
newWordName string
newWordBody []string
tape [200]byte
ptr int = 100
words map[string]func()
src = make([]string,0,100)
srcPos int
stdin = bufio.NewReader(os.Stdin)
stdout = bufio.NewWriter(os.Stdout)
)
func init() {
words = map[string]func(){
"+": inc,
"-": dec,
"<": shiftl,
">": shiftr,
",": readc,
".": writec,
"[": lbracket,
"]": rbracket,
"?": enterCondMode,
":": startNewWord,
";": endNewWord,
}
}
func main() {
srcRdr := openSrcFile()
for ln, _, err := srcRdr.ReadLine();err == nil;ln, _, err = srcRdr.ReadLine() {
wds := strings.Fields(string(ln))
for _, wd := range wds {
src = append(src,string(wd))
}
}
run(src)
stdout.Flush()
}
func run(src []string) {
for srcPos < len(src) {
runWord(src[srcPos])
srcPos++
}
}
func runWord(wd string) {
if inDefMode && wd != ";" {
if newWordName == "" {
newWordName = wd
} else {
newWordBody = append(newWordBody,wd)
}
} else if inCondMode && tape[ptr] != 0 {
return
} else {
f, ok := words[wd]
if !ok {panic("unknow word "+wd)}
f()
}
}
func lbracket() {
if tape[ptr] == 0 {
jumpr()
}
}
func rbracket() {
if tape[ptr] != 0 {
jumpl()
}
}
func jump(dir int) {
srcPos += dir
bDepth := dir
for bDepth != 0 {
switch src[srcPos] {
case "]":
bDepth--
case "[":
bDepth++
}
srcPos += dir
}
}
func jumpr() {
jump(1)
}
func jumpl() {
jump(-1)
}
func inc() {
tape[ptr]++
}
func dec() {
tape[ptr]--
}
func shiftl() {
ptr--
}
func shiftr() {
ptr++
}
func readc() {
c, err := stdin.ReadByte()
if err != nil {
panic(err)
}
tape[ptr] = c
}
func writec() {
err := stdout.WriteByte(tape[ptr])
if err != nil {
panic(err)
}
}
func startNewWord() {
enterDefMode()
newWordBody = newWordBody[:0]
newWordName = ""
}
func endNewWord() {
exitDefMode()
words[newWordName] = comWord(newWordBody)
}
func enterDefMode() {
inDefMode = true
}
func exitDefMode() {
inDefMode = false
}
func comWord(wds []string) func() {
wdsCp := make([]string,len(wds))
copy(wdsCp,wds)
return func() {
oldPos := srcPos
oldSrc := src
src = wdsCp
srcPos = 0
run(wdsCp)
srcPos = oldPos
src = oldSrc
}
}
func enterCondMode() {
inCondMode = true
}
func openSrcFile() *bufio.Reader {
if len(os.Args) == 0 || os.Args[0] == "-" {
return bufio.NewReader(os.Stdin)
}
f, err := os.Open(os.Args[1])
if err != nil {panic(err)}
return bufio.NewReader(f)
}
Example Programs
hello.bfth:
: PRINT [ . > ] ; : +8 + + + + + + + + ; : +16 +8 +8 ; : +32 +16 +16 ; : +64 +32 +32 ; : a +64 +32 + ; : h a +8 - ; : e a + + + + ; : l h + + + + ; : o l + + + ; h > e > l > l > o [ < ] > PRINT