Created
April 22, 2016 01:27
-
-
Save marcan/347faf7fa09802016d0c253699132539 to your computer and use it in GitHub Desktop.
Brainfuck interpreter in POSIX sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# Brainfuck interpreter implemented in pure POSIX sh builtins only (except I/O) | |
# Tested in bash and busybox ash (getchar uses a bash-specific read) | |
# === I/O === | |
getchar() { | |
# bashism | |
IFS= read -rN 1 a | |
if [ -z "$a" ]; then | |
echo $th | |
else | |
printf %d "'$a" | |
fi | |
} | |
putchar() { | |
printf "\x$(printf %x $1)" | |
} | |
# === Core BF interpreter: pure POSIX shell with builtins only from here on === | |
pl="" | |
pr="" | |
while read -r line; do | |
pl="$pl$line" | |
done <"$1" | |
th="0" | |
tl="" | |
tr="" | |
while :; do | |
case "$pl" in | |
'+'*) | |
th=$((th+1));; | |
'-'*) | |
th=$((th-1));; | |
'.'*) | |
putchar $th;; | |
','*) | |
th=$(getchar);; | |
'>'*) | |
tl="$th $tl" | |
set -- $tr | |
th=${1:-0} | |
shift | |
tr="$*" | |
;; | |
'<'*) | |
tr="$th $tr" | |
set -- $tl | |
th=${1:-0} | |
shift | |
tl="$*" | |
;; | |
'['*) | |
case "$th" in 0) | |
i=1 | |
while :; do | |
tmp="${pl#?}" | |
pr="${pl%"$tmp"}$pr" | |
pl="$tmp" | |
case "$pl" in | |
'['*) i=$((i+1));; | |
']'*) i=$((i-1));; | |
esac | |
case $i in 0) break; esac | |
done | |
esac | |
;; | |
']'*) | |
case "$th" in 0);; *) | |
i=1 | |
while :; do | |
tmp="${pr#?}" | |
pl="${pr%"$tmp"}$pl" | |
pr="$tmp" | |
case "$pl" in | |
']'*) i=$((i+1));; | |
'['*) i=$((i-1));; | |
esac | |
case $i in 0) break; esac | |
done | |
esac | |
;; | |
'') | |
break | |
esac | |
tmp="${pl#?}" | |
pr="${pl%"$tmp"}$pr" | |
pl="$tmp" | |
done |
putchar(){ ( O="$(printf %o $1)"' case O in ?) O=00"$O";; ??) O=0"$O";; ????*) printf '%s' "$0: putchar: assertion failed: (length of O)<4" 1>&2 exit 10 ;; esac printf '\'"$O" ) }
This is shorter;
printf '\'"$(printf %03o "$1")"
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for giving me the good idea.
Now I've just found if
read
line is\n
-terminated orEOF
-terminated;That is, the
read
's exit status would be 0 if\n
-terminated, 1 otherwise.Also your code has:
but the fact is that the format
%x
and\xHH
(where HH is hexadecimal) are not in POSIX; octal is available instead.Thus, you could do this: