home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Programme_zum_Heft / Programmieren / Kurztests / ACE / archive / ACEPRGS.LHA / lang / TinyBasic.lha / TinyBASIC.b next >
Text File  |  1994-01-21  |  15KB  |  872 lines

  1. { ** Tiny BASIC Interpreter ** 
  2.  
  3.   Author: David Benn
  4.     Date: 21st,22nd March 1992,
  5.         26th-29th January 1993,
  6.       25th March 1993,
  7.       10th June 1993 }
  8.  
  9. version$="$VER: TinyBASIC 1.1 10 06 1993"
  10.  
  11. library exec
  12.  
  13. declare function AllocMem& library exec
  14. declare function FreeMem library exec
  15.  
  16. '..memory constants
  17. const MEMF_PUBLIC=1&
  18. const MEMF_CLEAR=65536
  19. const NULL=0&
  20.  
  21. '..boolean constants
  22. const true=-1&
  23. const false=0&
  24.  
  25. '..stack 
  26. const maxstack=100
  27. dim stack(maxstack)
  28. shortint stacktop
  29.  
  30. '..intrinsic functions
  31. const maxfunc=8
  32. dim funcs$(maxfunc)
  33.  
  34. for i%=1 to maxfunc
  35.   read funcs$(i%)
  36. next
  37.  
  38. data "SIN","COS","TAN","LOG","SQR","FIX","INT","RND"
  39.  
  40. { * tokens * }
  41. const maxsym=34
  42.  
  43. '..special symbols
  44. const alpha=1
  45. const number=2
  46. const stringliteral=3
  47. const plus=4
  48. const minus=5
  49. const mult=6
  50. const div=7
  51. const pow=8
  52. const lparen=9
  53. const rparen=10
  54. const eq=11
  55. const lt=12
  56. const gt=13
  57. const ltoreq=14
  58. const gtoreq=15
  59. const noteq=16
  60. const comma=17
  61. const colon=18
  62. const eos=19
  63.  
  64. '..reserved words
  65. const clssym=20
  66. const elsesym=21
  67. const gotosym=22
  68. const ifsym=23
  69. const inputsym=24
  70. const letsym=25
  71. const listsym=26
  72. const loadsym=27
  73. const newsym=28
  74. const printsym=29
  75. const runsym=30
  76. const savesym=31
  77. const stopsym=32
  78. const thensym=33
  79.  
  80. const undef=maxsym
  81.  
  82. '..token strings
  83. dim sym.name$(maxsym)
  84. {for i%=1 to maxsym
  85.  read sym.name$(i%)
  86. next
  87. data alpha,number,stringliteral
  88. data "+","-","*","/","^"
  89. data "(",")","=","<",">","<=",">=","<>",",",":",eos
  90. data "cls","else","goto","if","input","let","list","load"
  91. data "new","print ","run","save","stop","then"
  92. data undef}
  93.  
  94. '..reserved words
  95. const maxword=14
  96. dim word$(maxword)
  97.  
  98. for i%=1 to maxword
  99.   read word$(i%)
  100. next
  101.  
  102. data "CLS","ELSE","GOTO","IF","INPUT","LET","LIST"
  103. data "LOAD","NEW","PRINT","RUN","SAVE","STOP","THEN"
  104.  
  105. '..errors
  106. longint bad
  107. const DIVBYZERO=1
  108. const SYNTAX=2
  109. const STKOVFL=3
  110. const STKUFL=4
  111. const LINEOUTOFRANGE=5
  112. const NOSUCHLINE=6
  113. const OUTOFMEMORY=7
  114. const CANNOTOPENFILE=8
  115. const FILENOTFOUND=9
  116.  
  117. '..program lines
  118. const maxlines=1000
  119. dim code_ptr&(maxlines)
  120.  
  121. for i%=0 to maxlines
  122.   code_ptr&(i%)=NULL
  123. next
  124. shortint topline
  125.  
  126. '..program counter
  127. shortint pc,old_pc
  128.  
  129. '..miscellaneous globals
  130. shortint n,length
  131. longint halt_requested
  132. ch$=""
  133. ut_ch$=""
  134. buf$=""
  135. ut_buf$=""
  136. obj$=""
  137. sym=undef
  138.  
  139. '..variables
  140. dim var(25)
  141. for i%=0 to 25
  142.  var(i%)=0
  143. next
  144.     
  145. '..forward references
  146. declare SUB expr
  147. declare SUB statement
  148. declare SUB parse_line
  149.  
  150. '..enable CTRL-C breaks
  151. ON BREAK GOTO start
  152. BREAK ON
  153.  
  154. {SUB show.sym(n)
  155. shared sym.name$
  156.   print sym.name$(n)
  157. END SUB}
  158.  
  159. SUB er(n)
  160. shared bad,pc,old_pc
  161.   if bad then exit sub    '..report only 1 error per line
  162.   case
  163.     n=DIVBYZERO     : print "DIVISION BY ZERO";
  164.     n=SYNTAX        : print "SYNTAX ERROR";
  165.     n=STKOVFL        : print "STACK OVERFLOW";
  166.     n=STKUFL        : print "STACK UNDERFLOW";
  167.     n=LINEOUTOFRANGE    : print "LINE OUT OF RANGE 1 TO";str$(maxlines); 
  168.     n=NOSUCHLINE    : print "LINE DOES NOT EXIST";
  169.     n=OUTOFMEMORY    : print "OUT OF MEMORY";
  170.     n=CANNOTOPENFILE    : print "CAN'T OPEN FILE FOR WRITING";
  171.     n=FILENOTFOUND    : print "FILE NOT FOUND";
  172.   end case
  173.   if pc<>0 then print " IN LINE";old_pc else print
  174.   bad=true
  175. END SUB
  176.  
  177. SUB nextch
  178. shared ch$,ut_ch$,buf$,ut_buf$,n,length
  179.  
  180.   if n<=length then
  181.     ch$=mid$(buf$,n,1)
  182.     ut_ch$=mid$(ut_buf$,n,1)
  183.     ++n
  184.   else
  185.     ch$=""
  186.   end if 
  187. END SUB
  188.  
  189. SUB rsvd.wd%(x$)
  190. shared word$
  191. shortint i,num
  192.  
  193.   i=1
  194.   while i<=maxword and num=0
  195.     if x$ = word$(i) then num=i
  196.     ++i
  197.   wend
  198.  
  199.   if num=0 then rsvd.wd%=alpha else rsvd.wd%=num+eos
  200. END SUB
  201.  
  202. SUB insymbol
  203. shared ch$,ut_ch$,sym,obj$
  204. shortint periods
  205.  
  206.  obj$=""
  207.  sym=undef
  208.  
  209.  '...skip whitespace
  210.  if ch$<=" " and ch$<>"" then
  211.    repeat
  212.      nextch
  213.    until ch$>" " or ch$=""
  214.  end if
  215.  
  216.  '..end of string?
  217.  if ch$="" then sym=eos:exit sub
  218.  
  219.  '...characters
  220.  if ch$>="A" and ch$<="Z" then
  221.    while ch$>="A" and ch$<="Z"
  222.      obj$=obj$+ch$   
  223.      nextch 
  224.    wend
  225.    sym=rsvd.wd%(obj$)
  226.  else  
  227.    '...unsigned numeric constant
  228.    if (ch$>="0" and ch$<="9") or ch$="." then
  229.      sym=number
  230.      while (ch$>="0" and ch$<="9") or ch$="."
  231.        if ch$="." then ++periods
  232.        obj$=obj$+ch$
  233.        nextch
  234.      wend
  235.      if periods > 1 then 
  236.        sym=undef
  237.        er(SYNTAX)
  238.      end if
  239.    else
  240.      '..string literal
  241.      if ch$=chr$(34) then
  242.        sym=stringliteral
  243.        nextch
  244.        while ch$<>chr$(34) and ch$<>""
  245.      obj$=obj$+ut_ch$
  246.          nextch
  247.        wend
  248.        if ch$<>chr$(34) then call er(SYNTAX):sym=undef:exit sub
  249.        nextch    
  250.      else
  251.        '...single character
  252.        obj$=ch$
  253.        case
  254.          obj$="+" : sym=plus
  255.          obj$="-" : sym=minus
  256.          obj$="*" : sym=mult
  257.          obj$="/" : sym=div
  258.          obj$="^" : sym=pow
  259.          obj$="(" : sym=lparen
  260.          obj$=")" : sym=rparen
  261.          obj$="=" : sym=eq
  262.          obj$="<" : sym=lt
  263.          obj$=">" : sym=gt
  264.      obj$="," : sym=comma
  265.      obj$=":" : sym=colon
  266.        end case
  267.  
  268.        nextch
  269.     
  270.        '..<= <> >= ?
  271.        if sym=lt and ch$="=" then 
  272.          sym=ltoreq:nextch
  273.        else
  274.          if sym=lt and ch$=">" then 
  275.            sym=noteq:nextch
  276.          else
  277.            if sym=gt and ch$="=" then 
  278.              sym=gtoreq:nextch
  279.            end if
  280.          end if
  281.        end if
  282.  
  283.        if sym=undef then call er(SYNTAX)
  284.      end if
  285.    end if
  286.  end if
  287.  
  288.  'show.sym(sym)
  289. END SUB
  290.  
  291. SUB push(x)
  292. shared stacktop,stack
  293.  
  294.   if stacktop>maxstack then 
  295.     er(STKOVFL)
  296.   else
  297.     stack(stacktop)=x
  298.     ++stacktop
  299.   end if
  300. END SUB
  301.  
  302. SUB pop
  303. shared stacktop,stack
  304.  
  305.   --stacktop
  306.   if stacktop<0 then 
  307.     er(STKUFL) 
  308.   else
  309.     pop=stack(stacktop)
  310.   end if
  311. END SUB
  312.  
  313. SUB func
  314. shared funcs$,obj$,sym,bad
  315. longint found
  316. shortint funct
  317.  
  318.   '..search for the function.
  319.   found=false
  320.   i=1
  321.   while i<=maxfunc and not found
  322.     if funcs$(i) = obj$ then funct=i:found=true else ++i
  323.   wend
  324.  
  325.   if funct then 
  326.     '..function
  327.     fun$=funcs$(funct)
  328.   else
  329.     '..variable
  330.     func=0
  331.     exit sub
  332.   end if
  333.  
  334.   '...push the argument
  335.   if funct<8 then
  336.     insymbol
  337.     if sym<>lparen then 
  338.       er(SYNTAX)
  339.       funct=0
  340.     else
  341.       insymbol
  342.       expr
  343.       if bad then func=0:exit sub
  344.       if sym<>rparen then call er(SYNTAX):funct=0
  345.     end if
  346.   end if
  347.  
  348.   '...execute function
  349.   case
  350.     funct=1 : push(sin(pop))
  351.     funct=2 : push(cos(pop))
  352.     funct=3 : push(tan(pop))
  353.     funct=4 : push(log(pop))
  354.     funct=5 : push(sqr(pop))
  355.     funct=6 : push(fix(pop))
  356.     funct=7 : push(clng(pop))
  357.     funct=8 : push(rnd)
  358.   end case
  359.  
  360.   func=-1
  361. END SUB
  362.  
  363. SUB var_index%(x$)
  364.   var_index% = asc(x$)-asc("A")  
  365. END SUB
  366.  
  367. SUB factor
  368. shared sym,obj$,bad,var
  369.  
  370.   if sym=number then 
  371.     '..numeric literal
  372.     push(val(obj$))
  373.   else
  374.     '..parenthesised expression?
  375.     if sym=lparen then
  376.       insymbol
  377.       if sym=eos then call er(SYNTAX):exit sub
  378.       expr
  379.       if bad then exit sub
  380.       if sym<>rparen then call er(SYNTAX):exit sub
  381.     else  
  382.       '..function or variable?
  383.       if not func then 
  384.         if sym=alpha then 
  385.           push(var(var_index%(obj$)))
  386.         else
  387.           '..unknown
  388.           er(SYNTAX)
  389.     end if
  390.       end if
  391.     end if
  392.   end if
  393.  
  394.   insymbol
  395. END SUB
  396.  
  397. SUB expterm
  398. shared sym,bad
  399.   factor
  400.   while sym=pow
  401.     insymbol
  402.     factor
  403.     if bad then exit sub
  404.     op2=pop
  405.     op1=pop
  406.     push(op1^op2)
  407.   wend
  408. END SUB
  409.  
  410. SUB negterm
  411. shared sym,bad
  412. longint negate
  413.   negate=false
  414.   if sym=minus then 
  415.     negate=true
  416.     insymbol
  417.   else
  418.     if sym=plus then 
  419.       insymbol
  420.     end if
  421.   end if
  422.   expterm
  423.   if bad then exit sub
  424.   if negate then call push(-pop)  
  425. END SUB
  426.  
  427. SUB term
  428. shared sym,bad
  429. shortint op
  430.   negterm
  431.   while sym=mult or sym=div
  432.     op=sym
  433.     insymbol
  434.     negterm
  435.     if bad then exit sub
  436.     op2=pop
  437.     op1=pop
  438.     if op=mult then
  439.       push(op1*op2)
  440.     else
  441.       if op2<>0 then 
  442.         push(op1/op2) 
  443.       else 
  444.         er(DIVBYZERO)
  445.       end if
  446.     end if
  447.   wend
  448. END SUB
  449.  
  450. SUB simple_expr
  451. shared sym,bad
  452. shortint op
  453.   term
  454.   while sym=plus or sym=minus
  455.     op=sym
  456.     insymbol
  457.     term
  458.     if bad then exit sub
  459.     op2=pop
  460.     op1=pop
  461.     if op=plus then
  462.       push(op1+op2)
  463.     else
  464.       push(op1-op2) 
  465.     end if
  466.   wend  
  467. END SUB
  468.  
  469. SUB expr
  470. shared sym,bad
  471. shortint op
  472.   simple_expr
  473.   while sym=eq or sym=lt or sym=gt or sym=ltoreq or sym=gtoreq or sym=noteq
  474.     op=sym
  475.     insymbol
  476.     simple_expr
  477.     if bad then exit sub
  478.     op2=pop
  479.     op1=pop
  480.     case
  481.       op=eq     : push(op1=op2)
  482.       op=lt     : push(op1<op2)
  483.       op=gt     : push(op1>op2)
  484.       op=ltoreq : push(op1<=op2)
  485.       op=gtoreq : push(op1>=op2)
  486.       op=noteq  : push(op1<>op2)
  487.     end case
  488.   wend  
  489. END SUB
  490.  
  491. SUB assign_to_variable
  492. shared sym,bad,obj$,var
  493.  
  494.  '..variable assignment
  495.  insymbol
  496.  if sym<>alpha then 
  497.    er(SYNTAX)
  498.    exit sub
  499.  end if
  500.  variable$=obj$
  501.  insymbol
  502.  if sym=eq then
  503.    insymbol
  504.    if sym=eos then call er(SYNTAX):exit sub
  505.    expr
  506.    if bad then exit sub else var(var_index%(variable$))=pop
  507.  end if
  508. END SUB
  509.  
  510. SUB if_statement
  511. shared sym,bad
  512.  
  513.   '..IF-THEN-ELSE
  514.   insymbol
  515.   expr
  516.   if bad then exit sub 
  517.   '..THEN
  518.   if sym=thensym then
  519.     if pop=-1 then
  520.       insymbol
  521.       statement
  522.       while sym<>eos:insymbol:wend
  523.     else
  524.       while sym<>elsesym and sym<>eos
  525.         insymbol
  526.       wend
  527.       '..ELSE (optional)
  528.       if sym=elsesym then
  529.         insymbol
  530.      statement
  531.       end if         
  532.     end if
  533.   else
  534.     er(SYNTAX)
  535.   end if
  536. END SUB
  537.  
  538. SUB modify_program(num%)
  539. shared sym,buf$,ut_buf$,code_ptr&
  540. shared n,length,topline
  541. longint strptr
  542.  
  543.  { kill or modify a program line }
  544.  
  545.  '..free memory associated with line num%?
  546.  '..(have to do this whether we are 
  547.  '...killing OR replacing a line). 
  548.  
  549.  if num%<1 or num%>maxlines then call er(LINEOUTOFRANGE):exit sub
  550.  
  551.  strptr=code_ptr&(num%)
  552.  if strptr then
  553.    FreeMem(strptr,len(cstr(strptr))+1&)
  554.    code_ptr&(num%)=NULL
  555.  end if  
  556.    
  557.  if n<=length then
  558.    '..** replace line num% if in range **
  559.    if num%>=1 and num%<=maxlines then
  560.      x$=mid$(ut_buf$,n)
  561.      '..check for string literals and don't
  562.      '..change the case of their characters.
  563.      y$=""
  564.      i%=1
  565.      ln%=len(x$)
  566.      while i%<=ln%
  567.        c$=mid$(x$,i%,1)
  568.        if c$=chr$(34) then
  569.          y$=y$+c$
  570.          repeat
  571.            ++i%
  572.            c$=mid$(x$,i%,1)
  573.            if c$<>chr$(34) then y$=y$+c$
  574.          until c$=chr$(34) or i%=ln%
  575.          y$=y$+c$
  576.          ++i%
  577.        else
  578.          y$=y$+ucase$(c$)
  579.          ++i%
  580.        end if
  581.      wend 
  582.      x$=y$
  583.  
  584.      '..allocate memory for line and store it.     
  585.      strptr=AllocMem(len(x$)+1&,MEMF_PUBLIC or MEMF_CLEAR)
  586.      if strptr=NULL then call er(OUTOFMEMORY):exit sub
  587.      string basic_line address strptr
  588.      basic_line=x$
  589.      code_ptr&(num%)=strptr 
  590.      if num%>topline then topline=num%
  591.    else
  592.      er(LINEOUTOFRANGE)  
  593.    end if      
  594.  else
  595.    '..find next lowest non-null line 
  596.    '..after removal of highest line.
  597.    if num%=topline then
  598.      repeat
  599.        --num%
  600.      until code_ptr&(num%)<>NULL or num%<1
  601.      topline=num%  '..code_ptr&(0) is sentinel.
  602.    end if
  603.  end if   
  604. END SUB
  605.  
  606. SUB list_program
  607. shared code_ptr&,topline
  608. longint strptr
  609.  
  610.   { list current program }
  611.  
  612.   i%=1
  613.   while i%<=topline
  614.     num$=str$(i%)
  615.     num$=right$(num$,len(num$)-1&)
  616.     strptr=code_ptr&(i%)
  617.     if strptr then print num$;" ";cstr(strptr) 
  618.     ++i%     
  619.   wend  
  620. END SUB
  621.  
  622. SUB clear_program
  623. shared code_ptr&,topline
  624. longint strptr
  625.  
  626.   { clear program memory }
  627.  
  628.   for i%=0 to maxlines
  629.     strptr=code_ptr&(i%)
  630.     if strptr then
  631.       FreeMem(strptr,len(cstr(strptr))+1&)
  632.       code_ptr&(i%)=NULL
  633.     end if
  634.   next
  635.  
  636.   topline=0
  637. END SUB
  638.  
  639. SUB run_program
  640. shared code_ptr&,pc,old_pc,buf$,ut_buf$
  641. shared bad,topline,halt_requested
  642. longint strptr
  643.  
  644.  { execute current program }
  645.  
  646.  if topline<1 then exit sub
  647.  
  648.  pc=1
  649.  repeat
  650.    strptr=code_ptr&(pc)
  651.    old_pc=pc
  652.    ++pc
  653.    if strptr then
  654.      buf$=cstr(strptr)
  655.      ut_buf$=buf$
  656.      parse_line
  657.    end if
  658.  until bad or halt_requested or pc>topline
  659. END SUB
  660.  
  661. SUB load_program
  662. shared sym,obj$,code_ptr&
  663. shared topline
  664. longint strptr
  665.  
  666.  { load program from file }
  667.  
  668.  insymbol
  669.  if sym=stringliteral then
  670.    open "I",#2,obj$
  671.    if handle(2)<>NULL then 
  672.      clear_program
  673.      print "LOADING ";obj$;".. ";
  674.      while not eof(2)
  675.        input #2,num%
  676.        line input #2,x$
  677.        strptr=AllocMem(len(x$)+1&,MEMF_PUBLIC or MEMF_CLEAR)
  678.        if strptr=NULL then call er(OUTOFMEMORY):close #2:exit sub
  679.        string basic_line address strptr
  680.        basic_line=x$
  681.        code_ptr&(num%)=strptr 
  682.        if num%>topline then topline=num%    
  683.      wend        
  684.      close #2
  685.      print "PROGRAM LOADED."
  686.    else
  687.      er(FILENOTFOUND)
  688.    end if
  689.  else
  690.    er(SYNTAX)
  691.  end if    
  692. END SUB
  693.  
  694. SUB save_program
  695. shared sym,obj$,code_ptr&
  696. shared topline
  697. longint strptr
  698.  
  699.  { store current program in file }
  700.  
  701.  if topline<1 then exit sub
  702.  
  703.  insymbol
  704.  if sym=stringliteral then
  705.    open "O",#3,obj$
  706.    if handle(3)<>NULL then 
  707.      print "SAVING ";obj$;".. ";
  708.      for i%=1 to topline
  709.        strptr=code_ptr&(i%)
  710.        if strptr then print #3,i%;cstr(strptr)
  711.      next
  712.      print "PROGRAM SAVED."
  713.      close #3
  714.    else
  715.      er(CANNOTOPENFILE)
  716.    end if
  717.  else
  718.    er(SYNTAX)
  719.  end if    
  720. END SUB
  721.  
  722. SUB statement
  723. shared sym,bad,obj$,var,pc,code_ptr&
  724. shared halt_requested
  725.  
  726.  '..EMPTY STATEMENT
  727.  if sym=eos then exit sub
  728.  
  729.  '..NUMBER
  730.  if sym=number then 
  731.    modify_program(fix(val(obj$)))
  732.    exit sub
  733.  end if
  734.   
  735.  '..CLS
  736.  if sym=clssym then cls:exit sub
  737.  
  738.  '..GOTO
  739.  if sym=gotosym then 
  740.    insymbol
  741.    if sym=eos then call er(SYNTAX):exit sub
  742.    expr
  743.    if not bad then pc=pop else exit sub
  744.    if pc<1 or pc>maxlines then call er(LINEOUTOFRANGE)
  745.    if code_ptr&(pc)=NULL then call er(NOSUCHLINE)
  746.    exit sub
  747.  end if
  748.  
  749.  '..IF
  750.  if sym=ifsym then 
  751.    if_statement
  752.    exit sub
  753.  end if
  754.  
  755.  '..INPUT
  756.  if sym=inputsym then
  757.    insymbol
  758.    if sym=alpha then 
  759.      input var(var_index%(obj$)) 
  760.    else 
  761.      er(SYNTAX)
  762.    end if
  763.    exit sub
  764.  end if
  765.  
  766.  '..LET
  767.  if sym=letsym then
  768.    assign_to_variable
  769.    exit sub
  770.  end if
  771.  
  772.  '..LIST  
  773.  if sym=listsym then
  774.    list_program
  775.    exit sub
  776.  end if
  777.  
  778.  '..LOAD
  779.  if sym=loadsym then
  780.    load_program
  781.    exit sub
  782.  end if
  783.  
  784.  '..NEW
  785.  if sym=newsym then 
  786.    clear_program
  787.    exit sub
  788.  end if
  789.  
  790.  '..PRINT
  791.  if sym=printsym then
  792.    repeat
  793.      insymbol
  794.      if sym=eos then call er(SYNTAX):exit sub
  795.      if sym=stringliteral then 
  796.        print obj$;
  797.        insymbol
  798.      else
  799.        expr
  800.        if not bad then print pop;
  801.      end if
  802.    until sym<>comma
  803.    print
  804.    exit sub
  805.  end if
  806.  
  807.  '..RUN 
  808.  if sym=runsym then
  809.    run_program
  810.    exit sub
  811.  end if
  812.  
  813.  '..SAVE
  814.  if sym=savesym then
  815.    save_program
  816.    exit sub
  817.  end if
  818.  
  819.  '..STOP
  820.  if sym=stopsym then
  821.    halt_requested=true
  822.    exit sub    '..see run_program
  823.  end if
  824.  
  825.  '..UNKNOWN 
  826.  er(SYNTAX)
  827. END SUB
  828.  
  829. SUB parse_line
  830. shared sym,bad,buf$
  831. shared ch$,n,length,stacktop
  832. shared halt_requested
  833.   ch$=" " 
  834.   n=1
  835.   length=len(buf$)
  836.   bad=false
  837.   halt_requested=false    
  838.   stacktop=1
  839.   repeat
  840.     insymbol
  841.     statement
  842.     if sym<>colon and sym<>eos then call insymbol
  843.   until sym<>colon
  844. END SUB
  845.  
  846. SUB finished
  847. shared buf$
  848.  
  849.  '..Quit,Exit?
  850.  if instr(buf$,"QUIT") or instr(buf$,"EXIT") or instr(buf$,"SYSTEM") then 
  851.    finished=true
  852.  else
  853.    finished=false
  854.  end if
  855. END SUB
  856.  
  857. { ** MAIN ** }
  858. window 1,"** Tiny BASIC Interpreter © 1993 David Benn **",(0,0)-(640,200)
  859.  
  860. repeat
  861.  start:
  862.   pc=0
  863.   input ,ut_buf$
  864.   buf$=ucase$(ut_buf$)
  865.   if not finished then call parse_line
  866. until finished
  867.  
  868. window close 1
  869.  
  870. clear_program
  871. library close exec
  872.