forsh/for.sh

233 lines
3.1 KiB
Bash
Raw Normal View History

#!/bin/sh
# Weird shell stack based forth "lookalike"
# recursion can be done by repeating the
# word. Words cannot have multiple defs
# in a dictionary.
# todo:
# implement conditionals in _execword :^)
ignore() :
alias :=_newword
alias ']=_execbody'
_stack="" # top is
_builtin_dictionary="swap dup rot over drop add sub div mod mul put not or and xor eq lt gt ne" # + - / * .
_newword() {
name="$1"
shift
[ "$_debug" ] && {
printf '_newword %s: %s\n' "$name" "$*"
read
}
eval "${name}_definition=\"$*\""
}
_execword() {
[ "$_debug" ] && {
printf '_execword %s\n' "$1"
read
}
eval "def=\"\$$1_definition\""
[ "$def" ] || {
printf '%s\n' "Error: no word $1"
return
}
_execbody $def
}
_execbody() {
while [ "$1" ]; do
word="$1"
[ "$_debug" ] && {
printf 'word %s\nstack %s\n' "$word" "$_stack"
read
}
case "$_builtin_dictionary" in
*"$word"*) "_$word" $_stack ;;
*) case "$word" in
then) ignore ;;
if)
[ "${_stack%% *}" = 0 ] && {
[ "$_debug" ] && {
printf 'failed if, jumping ahead\n'
read
}
_ifcnt=1
_thencnt=0
while [ "$_ifcnt" != "$_thencnt" ]; do
[ "$_debug" ] && {
printf '$1 %s\n' "$1"
printf '$* %s\n' "$*"
printf 'ifcnt: %s thencnt: %s\n' "$_ifcnt" "$_thencnt"
read
}
shift
case "$1" in
if) ignore $(( _ifcnt += 1 )) ;;
then) ignore $(( _thencnt += 1 )) ;;
"") printf 'Unmatched if\n'; return ;;
esac
done
}
_drop $_stack
shift
continue
;;
*[0-9]*) _stack="$word $_stack" ;;
*) _execword "$word" ;;
esac
;;
esac
shift
done
}
_swap() {
one="$1"
two="$2"
shift 2
_stack="$two $one $*"
}
_dup() {
_stack="$1 $*"
}
_rot() {
one="$1"
two="$2"
thr="$3"
shift 3
_stack="$thr $one $two $*"
}
_over() {
_stack="$2 $*"
}
_drop() {
shift
_stack="$*"
}
_add() {
one="$1"
two="$2"
shift 2
_stack="$(( one + two )) $*"
}
_sub() {
one="$1"
two="$2"
shift 2
_stack="$(( two - one )) $*"
}
_div() {
one="$1"
two="$2"
shift 2
_stack="$(( two / one )) $*"
}
_mod() {
one="$1"
two="$2"
shift 2
_stack="$(( two % one )) $*"
}
_mul() {
one="$1"
two="$2"
shift 2
_stack="$(( one * two )) $*"
}
_put() {
one="$1"
shift
printf '%s \n' "$one"
_stack="$*"
}
_not() {
one="$1"
shift
_stack="$(( ~ one )) $*"
}
_or() {
one="$1"
two="$2"
shift 2
_stack="$(( one | two )) $*"
}
_and() {
one="$1"
two="$2"
shift 2
_stack="$(( one & two )) $*"
}
_xor() {
one="$1"
two="$2"
shift 2
_stack="$(( one ^ two )) $*"
}
_eq() {
one="$1"
two="$2"
shift 2
if [ "$one" -eq "$two" ]; then
_stack="$(( ~ 0 )) $*"
else
_stack="$(( 0 )) $*"
fi
}
_lt() {
one="$1"
two="$2"
shift 2
if [ "$two" -lt "$one" ]; then
_stack="$(( ~ 0 )) $*"
else
_stack="$(( 0 )) $*"
fi
}
_gt() {
one="$1"
two="$2"
shift 2
if [ "$two" -gt "$one" ]; then
_stack="$(( ~ 0 )) $*"
else
_stack="$(( 0 )) $*"
fi
}
_ne() {
one="$1"
two="$2"
shift 2
if [ "$two" -ne "$one" ]; then
_stack="$(( ~ 0 )) $*"
else
_stack="$(( 0 )) $*"
fi
}
# definitions in forsh
: true not false ;
: false 0 ;