Created
May 25, 2012 04:47
-
-
Save cander/2785819 to your computer and use it in GitHub Desktop.
Bourne Basic - a BASIC interpreter implemented (painfully) in pure Bourne shell
This file contains 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 | |
# | |
# | |
# From: allbery@ncoast.UUCP (allbery@ncoast.UUCP) | |
# Subject: bournebasic | |
# Newsgroups: comp.sources.misc | |
# Date: 1987-08-18 18:54:12 PST | |
# | |
# Here's a useful BASIC interpreter written in Bourne shell. | |
# There's no manual but this demo shows the most salient features: | |
# | |
# 10 print "Enter any number and I will double it for you "; | |
# 20 input x | |
# 30 y = 2*x | |
# 40 print "The answer is "; | |
# 50 print y | |
# 60 print "Enter -1 if you want to continue." | |
# 70 input c | |
# 80 if c = -1 then 10 | |
# 90 print "Bye" | |
# | |
# Also, the commands 'load', 'save', 'list', 'run', and 'new' | |
# work as expected. Enjoy! | |
# | |
tfiles=/tmp/bas$$ | |
export tfiles | |
trap "rm ${tfiles?Bug}*; exit" 2 | |
> ${tfiles} | |
echo 'Hi there!' | |
while true | |
do | |
echo -n '>' | |
read com com2 || exit | |
case $com in | |
list) | |
cat ${tfiles} | |
;; | |
run) | |
echo 0 > ${tfiles}.ln | |
while true | |
do | |
while true | |
do | |
case `cat ${tfiles}.ln` in | |
0) | |
read lineno line || exit | |
;; | |
*) | |
while true | |
do | |
read lineno line || exit | |
match=`cat ${tfiles}.ln` | |
case $lineno in | |
$match) | |
break | |
;; | |
*) | |
;; | |
esac | |
done | |
esac | |
while true | |
do | |
case $line in | |
print*) | |
expr=`echo $line | sed 's/print\ *//'` | |
case $expr in | |
\"*) | |
echo -n `echo "$expr" | sed 's/^\"// | |
s/\".*$//'` | |
case $line in | |
*\;) | |
;; | |
*) | |
echo | |
;; | |
esac | |
;; | |
*) | |
> ${tfiles}.ex | |
files=`echo ${tfiles}.?` | |
case $files in | |
${tfiles}.\?) | |
;; | |
*) | |
for i in $files | |
do | |
cat $i >> ${tfiles}.ex | |
done | |
;; | |
esac | |
echo $expr >> ${tfiles}.ex | |
bc < ${tfiles}.ex > ${tfiles}.res | |
cat ${tfiles}.res | |
;; | |
esac | |
;; | |
if*) | |
expr=`echo $line | sed '{ | |
s/if\ */\(/ | |
s/[#=]/\)-\(/ | |
s/\ *then.*/\)/ | |
}'` | |
target=`echo $line | sed 's/.*then\ *//'` | |
> ${tfiles}.ex | |
files=`echo ${tfiles}.?` | |
case $files in | |
${tfiles}.\?) | |
;; | |
*) | |
for i in $files | |
do | |
cat $i >> ${tfiles}.ex | |
done | |
;; | |
esac | |
echo $expr >>${tfiles}.ex | |
res=`bc < ${tfiles}.ex` | |
case $res in | |
0*) | |
case $line in | |
*=*) | |
echo $target > ${tfiles}.ln | |
exit | |
;; | |
*) | |
;; | |
esac | |
;; | |
*) | |
case $line in | |
*#*) | |
echo $target > ${tfiles}.ln | |
exit | |
;; | |
*) | |
;; | |
esac | |
;; | |
esac | |
;; | |
end*) | |
echo 0 > ${tfiles}.ln | |
exit | |
;; | |
goto*) | |
expr=`echo $line | sed 's/goto\ *//'` | |
echo $expr > ${tfiles}.ln | |
exit | |
;; | |
input*) | |
var=`echo $line | sed 's/input\ *//'` | |
echo -n "?" | |
echo -n "$var=" > ${tfiles}.$var | |
while true | |
do | |
read val | |
echo $val | |
break | |
done < /dev/tty >> ${tfiles}.$var | |
;; | |
*) | |
> ${tfiles}.ex | |
files=`echo ${tfiles}.?` | |
case $files in | |
${tfiles}.\?) | |
;; | |
*) | |
for i in $files | |
do | |
cat $i >> ${tfiles}.ex | |
done | |
;; | |
esac | |
echo $line >>${tfiles}.ex | |
var=`echo $line | sed 's/\ *=.*//'` | |
echo $var >> ${tfiles}.ex | |
bc < ${tfiles}.ex > ${tfiles}.res | |
echo -n $var= > ${tfiles}.$var | |
cat ${tfiles}.res >> ${tfiles}.$var | |
;; | |
esac | |
read lineno line || exit | |
done | |
done < ${tfiles} | |
case `cat ${tfiles}.ln` in | |
0*) | |
break | |
;; | |
*) | |
;; | |
esac | |
done | |
;; | |
new) | |
>${tfiles} | |
;; | |
quit) | |
echo 'Thank you for your patience.' | |
rm ${tfiles?Bug}* | |
exit | |
;; | |
load) | |
cp $com2 ${tfiles} | |
;; | |
save) | |
cp ${tfiles} $com2 | |
;; | |
[0-9]*) | |
echo $com $com2 > ${tfiles}.nl | |
grep -v "^$com" ${tfiles} >> ${tfiles}.nl | |
sort -n ${tfiles}.nl > ${tfiles} | |
;; | |
"") | |
;; | |
*) | |
echo 'Illegal command' | |
esac | |
done |
10 print "hello"
20 goto 10
does not seem to work, i.e. I think there is some issue with "goto".
Hey @KedalionDaimon - this script is 35 years old. I put it up here to save it because I thought it was an awesome abuse of the shell.
At this point, I'd be surprised if it did work. I'll bet the problem is related to the original Bourne shell vs. modern shells like Bash.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I pulled this down off of Usenet back in the day - i.e., long before the Internet was open to commercial riff-raff. Because this script is so painful and slow, I was inspired to design a BASIC interpreter in NAWK (New AWK), which I never implemented. But, I did implement it in Perl - it was my first major Perl program. I'll see if I can find that, too.