os/micro-scheme/nano-scheme.sh
2019-03-10 06:25:58 +01:00

196 lines
4.3 KiB
Bash
Executable File

#!/bin/sh
# Scheme syntax:
#
# ()lrwqicntfexyz
#
# ( start list
# ) end list
# l lambda
# r read byte
# w write byte
# b quote next byte in the source
# q quotes its argument
# i byte to int
# c cons
# n null
# t true
# f false
# e eq?
# x user variable (shadowing not allowed)
# y user variable (shadowing not allowed)
# z user variable (shadowing not allowed)
# TODO: free, GC roots, alloc, function pointers, …
#
# sh variables:
#
# a answer
# c lexer current char
# h heap_max
# t$i heap_type[$i]
# v$i heap_value[$i]
# d$i heap_cdr[$i]
#
# heap types:
#
# type v d
# P pair ptr ptr
# N null "_"
# F free cell ptr
# I integer int
# Y symbol octal
#
# Note: octal strings must not contain any spaces.
h=0
s=0
heap_sbrk() { h=$(($h+1)); }
heap_get_type() { eval a=\$t$1; }
heap_get_val() { eval a=\$v$1; }
heap_get_cdr() { eval a=\$d$1; }
heap_set() { eval t$1=$2; eval v$1=$3; }
heap_set_pair() { eval t$1=$2; eval v$1=$3; eval d$1=$4; }
heap_debug() { for heap_debug_i in `seq $h`; do
printf %s" " $heap_debug_i
heap_get_type $heap_debug_i; printf %s" " $a
heap_get_val $heap_debug_i; printf %s" " $a
heap_get_cdr $heap_debug_i; printf %s\\n $a
done }
stack_debug() { for stack_debug_i in `seq $s`; do
printf "<%s " $stack_debug_i
eval a=\$s$stack_debug_i
printf "%s>" $a
done
printf \\n; }
rlist() {
heap_sbrk; heap_set $h N _
rlist_cdr=$h
eval a=\$s$s
while test "$a" != M && test $s -ge 0; do
heap_sbrk; heap_set_pair $h P $a $rlist_cdr
rlist_cdr=$h
s=$(($s-1))
eval a=\$s$s
done
if test $s -lt 0; then
printf 'Parse error: unbalanced parenthesis'\\n
exit 1
fi
eval s$s=$rlist_cdr
}
debug_print() {
heap_get_type $1
if test $a = P; then
if $2; then printf %s ' '; else printf %s '('; fi
heap_get_val $1
debug_print $a false
heap_get_cdr $1
debug_print $a true
if $2; then :; else printf %s ')'; fi
elif test $a = N; then
if $2; then :; else printf %s '()'; fi
elif test $a = Y; then
if $2; then printf %s '.'; fi
heap_get_val $1
printf \\$a
if $2; then printf %s ')'; fi
else
if $2; then printf %s '.'; fi
printf %s $a
heap_get_val $1
printf %s $a
heap_get_cdr $1
printf %s $a
if $2; then printf %s ')'; fi
fi
}
eval_scheme() {
local callee ptr result
heap_get_type $1
if test $a = P; then
heap_get_val $1
# TDODO: use a stack
echo h=$h
heap_sbrk; heap_set_pair $h P $a $h;
echo h=$h
callee=$a
echo -n callee=
debug_print $callee false
echo
# compute the arguments
a=P
heap_get_cdr $1
ptr=$a
heap_get_type $ptr
echo cdr1=$ptr type=$a
while test "$a" != N; do
heap_get_val $ptr
echo val=$a
eval_scheme $a
# TODO: push on a stack
echo h=$h
heap_sbrk; heap_set_pair $h P $a $h;
echo h=$h
result=$a
echo result=$result
heap_get_cdr $ptr
ptr=$a
heap_get_type $ptr
echo cdr=$ptr type=$a
a=N
done
# TODO: this assumes that the callee is a symbol.
heap_get_val $callee
echo callee====$callee
echo callee----$a
case $a in
# octal for "r"
162) echo READ
# fake read (always returns "h", soon to be "hello"!)
a=150;; # TODO: should be some-input | od -v -A n -t x1 | read -n 1 a
# octal for "w"
167) echo WRITE: $result
printf \\$result >> output;; # TODO: should use octal, \x is not portable.
*) echo TODO_OR_ERROR
a=42;;
esac
else
echo TODO_OR_ERROR
a=42
fi
}
main() {
# printf '(w((lxx)r))' \
# printf '(r)' \
printf '(w(r))' \
| od -v -A n -t o1 \
| sed -e 's/^ //' \
| tr ' ' \\n \
| (while read c; do
echo lex:$c
case "$c" in
# octal for "("
050) s=$(($s+1)); eval s$s=M ;;
# octal for ")"
051) stack_debug; rlist; stack_debug ;;
*) heap_sbrk; heap_set $h Y $c; s=$(($s+1)); eval s$s=$h ;;
esac
done
heap_debug
echo
to_eval=$h
heap_sbrk; heap_set $h N _
eval_scheme $to_eval
echo
debug_print $to_eval false)
}
if true; then main; exit $?; fi