Last active
April 2, 2020 01:58
-
-
Save p7g/bd61e0531d1b89e77cae8a88a6960a1b to your computer and use it in GitHub Desktop.
BF interpreter in bash
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/bash | |
tape=(0) | |
tape_index=0 | |
tape_get() { | |
echo ${tape[$tape_index]} | |
} | |
tape_inc() { | |
local -i amount=$1 | |
local -i value=tape[$tape_index] | |
((value+=amount)) | |
tape[$tape_index]=$value | |
} | |
tape_move() { | |
local -i amount=$1 | |
((tape_index+=amount)) | |
while [ $tape_index -ge ${#tape[@]} ]; do | |
tape+=(0) | |
((tape_length++)) | |
done | |
} | |
OP_INC=0 | |
OP_MOVE=1 | |
OP_LOOP=2 | |
OP_PRINT=3 | |
declare -i loop_var_count=0 | |
declare -i string_index=0 | |
filename=$1 | |
contents=$(cat "$filename") | |
parse() { | |
local ops_name=$1 | |
local op_values_name=$1_values | |
declare -ga $ops_name | |
declare -ga $op_values_name | |
local -n __ops=$ops_name | |
local -n __op_values=$op_values_name | |
for ((; string_index < ${#contents}; string_index++)); do | |
local char=${contents:string_index:1} | |
case $char in | |
+) | |
__ops+=($OP_INC) | |
__op_values+=(1) | |
;; | |
-) | |
__ops+=($OP_INC) | |
__op_values+=(-1) | |
;; | |
\>) | |
__ops+=($OP_MOVE) | |
__op_values+=(1) | |
;; | |
\<) | |
__ops+=($OP_MOVE) | |
__op_values+=(-1) | |
;; | |
.) | |
__ops+=($OP_PRINT) | |
__op_values+=(0) | |
;; | |
\[) | |
__ops+=($OP_LOOP) | |
loop_var_name="__loop_ops_$((loop_var_count++))" | |
__op_values+=($loop_var_name) | |
((string_index++)) | |
parse $loop_var_name | |
;; | |
\]) | |
break | |
;; | |
esac | |
done | |
} | |
run() { | |
local -n __ops=$1 | |
local -n __op_values=$1_values | |
local ops=("${__ops[@]}") | |
local op_values=("${__op_values[@]}") | |
local value= | |
for op in ${ops[@]}; do | |
value="${op_values[0]}" | |
op_values=("${op_values[@]:1}") | |
case $op in | |
$OP_INC) | |
tape_inc $value | |
;; | |
$OP_MOVE) | |
tape_move $value | |
;; | |
$OP_PRINT) | |
printf "\x$(printf %x $(tape_get))" | |
;; | |
$OP_LOOP) | |
while [ $(tape_get) -ne 0 ]; do | |
run $value | |
done | |
;; | |
esac | |
done | |
} | |
parse ops | |
run ops |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment