home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / pascal2c / basic.p < prev    next >
Text File  |  1992-08-05  |  69KB  |  2,215 lines

  1.  
  2. $ sysprog, ucsd, heap_dispose, partial_eval $
  3.  
  4. {$ debug$}
  5.  
  6.  
  7. program basic(input, output);
  8.  
  9.  
  10. const
  11.  
  12.    checking = true;
  13.  
  14.    varnamelen = 20;
  15.    maxdims = 4;
  16.  
  17.  
  18.  
  19. type
  20.  
  21.    varnamestring = string[varnamelen];
  22.  
  23.    string255 = string[255];
  24.    string255ptr = ^string255;
  25.  
  26.    tokenkinds = (tokvar, toknum, tokstr, toksnerr,
  27.  
  28.                  tokplus, tokminus, toktimes, tokdiv, tokup, toklp, tokrp, 
  29.                  tokcomma, toksemi, tokcolon, tokeq, toklt, tokgt,
  30.                  tokle, tokge, tokne,
  31.  
  32.                  tokand, tokor, tokxor, tokmod, toknot, toksqr, toksqrt, toksin,
  33.                  tokcos, toktan, tokarctan, toklog, tokexp, tokabs, toksgn,
  34.                  tokstr_, tokval, tokchr_, tokasc, toklen, tokmid_, tokpeek,
  35.  
  36.                  tokrem, toklet, tokprint, tokinput, tokgoto, tokif, tokend, 
  37.                  tokstop, tokfor, toknext, tokwhile, tokwend, tokgosub,
  38.                  tokreturn, tokread, tokdata, tokrestore, tokgotoxy, tokon,
  39.                  tokdim, tokpoke,
  40.  
  41.                  toklist, tokrun, toknew, tokload, tokmerge, toksave, tokbye,
  42.                  tokdel, tokrenum,
  43.  
  44.                  tokthen, tokelse, tokto, tokstep);
  45.  
  46.    realptr = ^real;
  47.    basicstring = string255ptr;
  48.    stringptr = ^basicstring;
  49.    numarray = array[0..maxint] of real;
  50.    arrayptr = ^numarray;
  51.    strarray = array[0..maxint] of basicstring;
  52.    strarrayptr = ^strarray;
  53.  
  54.    tokenptr = ^tokenrec;
  55.    lineptr = ^linerec;
  56.    varptr = ^varrec;
  57.    loopptr = ^looprec;
  58.  
  59.    tokenrec =
  60.       record
  61.          next : tokenptr;
  62.          case kind : tokenkinds of
  63.             tokvar : (vp : varptr);
  64.             toknum : (num : real);
  65.             tokstr, tokrem : (sp : string255ptr);
  66.             toksnerr : (snch : char);
  67.       end;
  68.  
  69.    linerec =
  70.       record
  71.          num, num2 : integer;
  72.          txt : tokenptr;
  73.          next : lineptr;
  74.       end;
  75.  
  76.    varrec =
  77.       record
  78.          name : varnamestring;
  79.          next : varptr;
  80.          dims : array [1..maxdims] of integer;
  81.          numdims : 0..maxdims;
  82.          case stringvar : boolean of
  83.             false : (arr : arrayptr;  val : realptr;  rv : real);
  84.             true : (sarr : strarrayptr;  sval : stringptr;  sv : basicstring);
  85.       end;
  86.  
  87.    valrec =
  88.       record
  89.          case stringval : boolean of
  90.             false : (val : real);
  91.             true : (sval : basicstring);
  92.       end;
  93.  
  94.    loopkind = (forloop, whileloop, gosubloop);
  95.    looprec =
  96.       record
  97.          next : loopptr;
  98.          homeline : lineptr;
  99.          hometok : tokenptr;
  100.          case kind : loopkind of
  101.             forloop :
  102.                ( vp : varptr;
  103.                  max, step : real );
  104.       end;
  105.  
  106.  
  107.  
  108. var
  109.  
  110.    inbuf : string255ptr;
  111.  
  112.    linebase : lineptr;
  113.    varbase : varptr;
  114.    loopbase : loopptr;
  115.  
  116.    curline : integer;
  117.    stmtline, dataline : lineptr;
  118.    stmttok, datatok, buf : tokenptr;
  119.  
  120.    exitflag : boolean;
  121.  
  122.    excp_line ['EXCP_LINE'] : integer;
  123.  
  124.  
  125.  
  126. $if not checking$
  127.    $range off$
  128. $end$
  129.  
  130.  
  131.  
  132. procedure misc_getioerrmsg(var s : string; io : integer);
  133.    external;
  134.  
  135. procedure misc_printerror(er, io : integer);
  136.    external;
  137.  
  138. function asm_iand(a, b : integer) : integer;
  139.    external;
  140.  
  141. function asm_ior(a, b : integer) : integer;
  142.    external;
  143.  
  144. procedure hpm_new(var p : anyptr; size : integer);
  145.    external;
  146.  
  147. procedure hpm_dispose(var p : anyptr; size : integer);
  148.    external;
  149.  
  150.  
  151.  
  152. procedure restoredata;
  153.    begin
  154.       dataline := nil;
  155.       datatok := nil;
  156.    end;
  157.  
  158.  
  159.  
  160. procedure clearloops;
  161.    var
  162.       l : loopptr;
  163.    begin
  164.       while loopbase <> nil do
  165.          begin
  166.             l := loopbase^.next;
  167.             dispose(loopbase);
  168.             loopbase := l;
  169.          end;
  170.    end;
  171.  
  172.  
  173.  
  174. function arraysize(v : varptr) : integer;
  175.    var
  176.       i, j : integer;
  177.    begin
  178.       with v^ do
  179.          begin
  180.             if stringvar then
  181.                j := 4
  182.             else
  183.                j := 8;
  184.             for i := 1 to numdims do
  185.                j := j * dims[i];
  186.          end;
  187.       arraysize := j;
  188.    end;
  189.  
  190.  
  191. procedure clearvar(v : varptr);
  192.    begin
  193.       with v^ do
  194.          begin
  195.             if numdims <> 0 then
  196.                hpm_dispose(arr, arraysize(v))
  197.             else if stringvar and (sv <> nil) then
  198.                dispose(sv);
  199.             numdims := 0;
  200.             if stringvar then
  201.                begin
  202.                   sv := nil;
  203.                   sval := addr(sv);
  204.                end
  205.             else
  206.                begin
  207.                   rv := 0;
  208.                   val := addr(rv);
  209.                end;
  210.          end;
  211.    end;
  212.  
  213.  
  214. procedure clearvars;
  215.    var
  216.       v : varptr;
  217.    begin
  218.       v := varbase;
  219.       while v <> nil do
  220.          begin
  221.             clearvar(v);
  222.             v := v^.next;
  223.          end;
  224.    end;
  225.  
  226.  
  227.  
  228. function numtostr(n : real) : string255;
  229.    var
  230.       s : string255;
  231.       i : integer;
  232.    begin
  233.       setstrlen(s, 255);
  234.       if (n <> 0) and (abs(n) < 1e-2) or (abs(n) >= 1e12) then
  235.          begin
  236.             strwrite(s, 1, i, n);
  237.             setstrlen(s, i-1);
  238.             numtostr := s;
  239.          end
  240.       else
  241.          begin
  242.             strwrite(s, 1, i, n:30:10);
  243.             repeat
  244.                i := i - 1;
  245.             until s[i] <> '0';
  246.             if s[i] = '.' then
  247.                i := i - 1;
  248.             setstrlen(s, i);
  249.             numtostr := strltrim(s);
  250.          end;
  251.    end;
  252.  
  253.  
  254.  
  255. procedure parse(inbuf : string255ptr; var buf : tokenptr);
  256.  
  257.    const
  258.       toklength = 20;
  259.  
  260.    type
  261.       chset = set of char;
  262.  
  263.    const
  264.       idchars = chset ['A'..'Z','a'..'z','0'..'9','_','$'];
  265.  
  266.    var
  267.       i, j, k : integer;
  268.       token : string[toklength];
  269.       t, tptr : tokenptr;
  270.       v : varptr;
  271.       ch : char;
  272.       n, d, d1 : real;
  273.  
  274.    begin
  275.       tptr := nil;
  276.       buf := nil;
  277.       i := 1;
  278.       repeat
  279.          ch := ' ';
  280.          while (i <= strlen(inbuf^)) and (ch = ' ') do
  281.             begin
  282.                ch := inbuf^[i];
  283.                i := i + 1;
  284.             end;
  285.          if ch <> ' ' then
  286.             begin
  287.                new(t);
  288.                if tptr = nil then
  289.                   buf := t
  290.                else
  291.                   tptr^.next := t;
  292.                tptr := t;
  293.                t^.next := nil;
  294.                case ch of
  295.                   'A'..'Z', 'a'..'z' :
  296.                      begin
  297.                         i := i - 1;
  298.                         j := 0;
  299.                         setstrlen(token, strmax(token));
  300.                         while (i <= strlen(inbuf^)) and (inbuf^[i] in idchars) do
  301.                            begin
  302.                               if j < toklength then
  303.                                  begin
  304.                                     j := j + 1;
  305.                                     token[j] := inbuf^[i];
  306.                                  end;
  307.                               i := i + 1;
  308.                            end;
  309.                         setstrlen(token, j);
  310.                         if (token = 'and')     or (token = 'AND')     then t^.kind := tokand     
  311.                    else if (token = 'or')      or (token = 'OR')      then t^.kind := tokor      
  312.                    else if (token = 'xor')     or (token = 'XOR')     then t^.kind := tokxor     
  313.                    else if (token = 'not')     or (token = 'NOT')     then t^.kind := toknot     
  314.                    else if (token = 'mod')     or (token = 'MOD')     then t^.kind := tokmod     
  315.                    else if (token = 'sqr')     or (token = 'SQR')     then t^.kind := toksqr     
  316.                    else if (token = 'sqrt')    or (token = 'SQRT')    then t^.kind := toksqrt    
  317.                    else if (token = 'sin')     or (token = 'SIN')     then t^.kind := toksin     
  318.                    else if (token = 'cos')     or (token = 'COS')     then t^.kind := tokcos     
  319.                    else if (token = 'tan')     or (token = 'TAN')     then t^.kind := toktan     
  320.                    else if (token = 'arctan')  or (token = 'ARCTAN')  then t^.kind := tokarctan  
  321.                    else if (token = 'log')     or (token = 'LOG')     then t^.kind := toklog     
  322.                    else if (token = 'exp')     or (token = 'EXP')     then t^.kind := tokexp     
  323.                    else if (token = 'abs')     or (token = 'ABS')     then t^.kind := tokabs     
  324.                    else if (token = 'sgn')     or (token = 'SGN')     then t^.kind := toksgn     
  325.                    else if (token = 'str$')    or (token = 'STR$')    then t^.kind := tokstr_    
  326.                    else if (token = 'val')     or (token = 'VAL')     then t^.kind := tokval     
  327.                    else if (token = 'chr$')    or (token = 'CHR$')    then t^.kind := tokchr_    
  328.                    else if (token = 'asc')     or (token = 'ASC')     then t^.kind := tokasc     
  329.                    else if (token = 'len')     or (token = 'LEN')     then t^.kind := toklen     
  330.                    else if (token = 'mid$')    or (token = 'MID$')    then t^.kind := tokmid_    
  331.                    else if (token = 'peek')    or (token = 'PEEK')    then t^.kind := tokpeek    
  332.                    else if (token = 'let')     or (token = 'LET')     then t^.kind := toklet     
  333.                    else if (token = 'print')   or (token = 'PRINT')   then t^.kind := tokprint   
  334.                    else if (token = 'input')   or (token = 'INPUT')   then t^.kind := tokinput   
  335.                    else if (token = 'goto')    or (token = 'GOTO')    then t^.kind := tokgoto    
  336.                    else if (token = 'go to')   or (token = 'GO TO')   then t^.kind := tokgoto    
  337.                    else if (token = 'if')      or (token = 'IF')      then t^.kind := tokif      
  338.                    else if (token = 'end')     or (token = 'END')     then t^.kind := tokend     
  339.                    else if (token = 'stop')    or (token = 'STOP')    then t^.kind := tokstop    
  340.                    else if (token = 'for')     or (token = 'FOR')     then t^.kind := tokfor     
  341.                    else if (token = 'next')    or (token = 'NEXT')    then t^.kind := toknext    
  342.                    else if (token = 'while')   or (token = 'WHILE')   then t^.kind := tokwhile   
  343.                    else if (token = 'wend')    or (token = 'WEND')    then t^.kind := tokwend    
  344.                    else if (token = 'gosub')   or (token = 'GOSUB')   then t^.kind := tokgosub   
  345.                    else if (token = 'return')  or (token = 'RETURN')  then t^.kind := tokreturn  
  346.                    else if (token = 'read')    or (token = 'READ')    then t^.kind := tokread    
  347.                    else if (token = 'data')    or (token = 'DATA')    then t^.kind := tokdata    
  348.                    else if (token = 'restore') or (token = 'RESTORE') then t^.kind := tokrestore 
  349.                    else if (token = 'gotoxy')  or (token = 'GOTOXY')  then t^.kind := tokgotoxy  
  350.                    else if (token = 'on')      or (token = 'ON')      then t^.kind := tokon      
  351.                    else if (token = 'dim')     or (token = 'DIM')     then t^.kind := tokdim     
  352.                    else if (token = 'poke')    or (token = 'POKE')    then t^.kind := tokpoke    
  353.                    else if (token = 'list')    or (token = 'LIST')    then t^.kind := toklist    
  354.                    else if (token = 'run')     or (token = 'RUN')     then t^.kind := tokrun     
  355.                    else if (token = 'new')     or (token = 'NEW')     then t^.kind := toknew     
  356.                    else if (token = 'load')    or (token = 'LOAD')    then t^.kind := tokload    
  357.                    else if (token = 'merge')   or (token = 'MERGE')   then t^.kind := tokmerge   
  358.                    else if (token = 'save')    or (token = 'SAVE')    then t^.kind := toksave    
  359.                    else if (token = 'bye')     or (token = 'BYE')     then t^.kind := tokbye     
  360.                    else if (token = 'quit')    or (token = 'QUIT')    then t^.kind := tokbye     
  361.                    else if (token = 'del')     or (token = 'DEL')     then t^.kind := tokdel     
  362.                    else if (token = 'renum')   or (token = 'RENUM')   then t^.kind := tokrenum   
  363.                    else if (token = 'then')    or (token = 'THEN')    then t^.kind := tokthen    
  364.                    else if (token = 'else')    or (token = 'ELSE')    then t^.kind := tokelse    
  365.                    else if (token = 'to')      or (token = 'TO')      then t^.kind := tokto      
  366.                    else if (token = 'step')    or (token = 'STEP')    then t^.kind := tokstep    
  367.                    else if (token = 'rem')     or (token = 'REM')     then
  368.                            begin
  369.                               t^.kind := tokrem;
  370.                               new(t^.sp);
  371.                               t^.sp^ := str(inbuf^, i, strlen(inbuf^)-i+1);
  372.                               i := strlen(inbuf^)+1;
  373.                            end
  374.                         else
  375.                            begin
  376.                               t^.kind := tokvar;
  377.                               v := varbase;
  378.                               while (v <> nil) and (v^.name <> token) do
  379.                                  v := v^.next;
  380.                               if v = nil then
  381.                                  begin
  382.                                     new(v);
  383.                                     v^.next := varbase;
  384.                                     varbase := v;
  385.                                     v^.name := token;
  386.                                     v^.numdims := 0;
  387.                                     if token[strlen(token)] = '$' then
  388.                                        begin
  389.                                           v^.stringvar := true;
  390.                                           v^.sv := nil;
  391.                                           v^.sval := addr(v^.sv);
  392.                                        end
  393.                                     else
  394.                                        begin
  395.                                           v^.stringvar := false;
  396.                                           v^.rv := 0;
  397.                                           v^.val := addr(v^.rv);
  398.                                        end;
  399.                                  end;
  400.                               t^.vp := v;
  401.                            end;
  402.                      end;
  403.                   '"', '''' :
  404.                      begin
  405.                         t^.kind := tokstr;
  406.                         new(t^.sp);
  407.                         setstrlen(t^.sp^, 255);
  408.                         j := 0;
  409.                         while (i <= strlen(inbuf^)) and (inbuf^[i] <> ch) do
  410.                            begin
  411.                               j := j + 1;
  412.                               t^.sp^[j] := inbuf^[i];
  413.                               i := i + 1;
  414.                            end;
  415.                         setstrlen(t^.sp^, j);
  416.                         i := i + 1;
  417.                      end;
  418.                   '0'..'9', '.' :
  419.                      begin
  420.                         t^.kind := toknum;
  421.                         n := 0;
  422.                         d := 1;
  423.                         d1 := 1;
  424.                         i := i - 1;
  425.                         while (i <= strlen(inbuf^)) and ((inbuf^[i] in ['0'..'9'])
  426.                                     or ((inbuf^[i] = '.') and (d1 = 1))) do
  427.                            begin
  428.                               if inbuf^[i] = '.' then
  429.                                  d1 := 10
  430.                               else
  431.                                  begin
  432.                                     n := n * 10 + ord(inbuf^[i]) - 48;
  433.                                     d := d * d1;
  434.                                  end;
  435.                               i := i + 1;
  436.                            end;
  437.                         n := n / d;
  438.                         if (i <= strlen(inbuf^)) and (inbuf^[i] in ['e','E']) then
  439.                            begin
  440.                               i := i + 1;
  441.                               d1 := 10;
  442.                               if (i <= strlen(inbuf^)) and (inbuf^[i] in ['+','-']) then
  443.                                  begin
  444.                                     if inbuf^[i] = '-' then
  445.                                        d1 := 0.1;
  446.                                     i := i + 1;
  447.                                  end;
  448.                               j := 0;
  449.                               while (i <= strlen(inbuf^)) and (inbuf^[i] in ['0'..'9']) do
  450.                                  begin
  451.                                     j := j * 10 + ord(inbuf^[i]) - 48;
  452.                                     i := i + 1;
  453.                                  end;
  454.                               for k := 1 to j do
  455.                                  n := n * d1;
  456.                            end;
  457.                         t^.num := n;
  458.                      end;
  459.                   '+' : t^.kind := tokplus;
  460.                   '-' : t^.kind := tokminus;
  461.                   '*' : t^.kind := toktimes;
  462.                   '/' : t^.kind := tokdiv;
  463.                   '^' : t^.kind := tokup;
  464.                   '(', '[' : t^.kind := toklp;
  465.                   ')', ']' : t^.kind := tokrp;
  466.                   ',' : t^.kind := tokcomma;
  467.                   ';' : t^.kind := toksemi;
  468.                   ':' : t^.kind := tokcolon;
  469.                   '?' : t^.kind := tokprint;
  470.                   '=' : t^.kind := tokeq;
  471.                   '<' : 
  472.                      begin
  473.                         if (i <= strlen(inbuf^)) and (inbuf^[i] = '=') then
  474.                            begin
  475.                               t^.kind := tokle;
  476.                               i := i + 1;
  477.                            end
  478.                         else if (i <= strlen(inbuf^)) and (inbuf^[i] = '>') then
  479.                            begin
  480.                               t^.kind := tokne;
  481.                               i := i + 1;
  482.                            end
  483.                         else
  484.                            t^.kind := toklt;
  485.                      end;
  486.                   '>' :
  487.                      begin
  488.                         if (i <= strlen(inbuf^)) and (inbuf^[i] = '=') then
  489.                            begin
  490.                               t^.kind := tokge;
  491.                               i := i + 1;
  492.                            end
  493.                         else
  494.                            t^.kind := tokgt;
  495.                      end;
  496.                   otherwise
  497.                      begin
  498.                         t^.kind := toksnerr;
  499.                         t^.snch := ch;
  500.                      end;
  501.                end;
  502.             end;
  503.       until i > strlen(inbuf^);
  504.    end;
  505.  
  506.  
  507.  
  508. procedure listtokens(var f : text; buf : tokenptr);
  509.    var
  510.       ltr, ltr0 : boolean;
  511.    begin
  512.       ltr := false;
  513.       while buf <> nil do
  514.          begin
  515.             if buf^.kind in [tokvar, toknum, toknot..tokrenum] then
  516.                begin
  517.                   if ltr then write(f, ' ');
  518.                   ltr := (buf^.kind <> toknot);
  519.                end
  520.             else
  521.                ltr := false;
  522.             case buf^.kind of
  523.                tokvar     : write(f, buf^.vp^.name);
  524.                toknum     : write(f, numtostr(buf^.num));
  525.                tokstr     : write(f, '"', buf^.sp^, '"');
  526.                toksnerr   : write(f, '{', buf^.snch, '}');
  527.                tokplus    : write(f, '+');
  528.                tokminus   : write(f, '-');
  529.                toktimes   : write(f, '*');
  530.                tokdiv     : write(f, '/');
  531.                tokup      : write(f, '^');
  532.                toklp      : write(f, '(');
  533.                tokrp      : write(f, ')');
  534.                tokcomma   : write(f, ',');
  535.                toksemi    : write(f, ';');
  536.                tokcolon   : write(f, ' : ');
  537.                tokeq      : write(f, ' = ');
  538.                toklt      : write(f, ' < ');
  539.                tokgt      : write(f, ' > ');
  540.                tokle      : write(f, ' <= ');
  541.                tokge      : write(f, ' >= ');
  542.                tokne      : write(f, ' <> ');
  543.                tokand     : write(f, ' AND ');
  544.                tokor      : write(f, ' OR ');
  545.                tokxor     : write(f, ' XOR ');
  546.                tokmod     : write(f, ' MOD ');
  547.                toknot     : write(f, 'NOT ');
  548.                toksqr     : write(f, 'SQR');
  549.                toksqrt    : write(f, 'SQRT');
  550.                toksin     : write(f, 'SIN');
  551.                tokcos     : write(f, 'COS');
  552.                toktan     : write(f, 'TAN');
  553.                tokarctan  : write(f, 'ARCTAN');
  554.                toklog     : write(f, 'LOG');
  555.                tokexp     : write(f, 'EXP');
  556.                tokabs     : write(f, 'ABS');
  557.                toksgn     : write(f, 'SGN');
  558.                tokstr_    : write(f, 'STR$');
  559.                tokval     : write(f, 'VAL');
  560.                tokchr_    : write(f, 'CHR$');
  561.                tokasc     : write(f, 'ASC');
  562.                toklen     : write(f, 'LEN');
  563.                tokmid_    : write(f, 'MID$');
  564.                tokpeek    : write(f, 'PEEK');
  565.                toklet     : write(f, 'LET');
  566.                tokprint   : write(f, 'PRINT');
  567.                tokinput   : write(f, 'INPUT');
  568.                tokgoto    : write(f, 'GOTO');
  569.                tokif      : write(f, 'IF');
  570.                tokend     : write(f, 'END');
  571.                tokstop    : write(f, 'STOP');
  572.                tokfor     : write(f, 'FOR');
  573.                toknext    : write(f, 'NEXT');
  574.                tokwhile   : write(f, 'WHILE');
  575.                tokwend    : write(f, 'WEND');
  576.                tokgosub   : write(f, 'GOSUB');
  577.                tokreturn  : write(f, 'RETURN');
  578.                tokread    : write(f, 'READ');
  579.                tokdata    : write(f, 'DATA');
  580.                tokrestore : write(f, 'RESTORE');
  581.                tokgotoxy  : write(f, 'GOTOXY');
  582.                tokon      : write(f, 'ON');
  583.                tokdim     : write(f, 'DIM');
  584.                tokpoke    : write(f, 'POKE');
  585.                toklist    : write(f, 'LIST');
  586.                tokrun     : write(f, 'RUN');
  587.                toknew     : write(f, 'NEW');
  588.                tokload    : write(f, 'LOAD');
  589.                tokmerge   : write(f, 'MERGE');
  590.                toksave    : write(f, 'SAVE');
  591.                tokdel     : write(f, 'DEL');
  592.                tokbye     : write(f, 'BYE');
  593.                tokrenum   : write(f, 'RENUM');
  594.                tokthen    : write(f, ' THEN ');
  595.                tokelse    : write(f, ' ELSE ');
  596.                tokto      : write(f, ' TO ');
  597.                tokstep    : write(f, ' STEP ');
  598.                tokrem     : write(f, 'REM', buf^.sp^);
  599.             end;
  600.             buf := buf^.next;
  601.          end;
  602.    end;
  603.  
  604.  
  605.  
  606. procedure disposetokens(var tok : tokenptr);
  607.    var
  608.       tok1 : tokenptr;
  609.    begin
  610.       while tok <> nil do
  611.          begin
  612.             tok1 := tok^.next;
  613.             if tok^.kind in [tokstr, tokrem] then
  614.                dispose(tok^.sp);
  615.             dispose(tok);
  616.             tok := tok1;
  617.          end;
  618.    end;
  619.  
  620.  
  621.  
  622. procedure parseinput(var buf : tokenptr);
  623.    var
  624.       l, l0, l1 : lineptr;
  625.    begin
  626.       inbuf^ := strltrim(inbuf^);
  627.       curline := 0;
  628.       while (strlen(inbuf^) <> 0) and (inbuf^[1] in ['0'..'9']) do
  629.          begin
  630.             curline := curline * 10 + ord(inbuf^[1]) - 48;
  631.             strdelete(inbuf^, 1, 1);
  632.          end;
  633.       parse(inbuf, buf);
  634.       if curline <> 0 then
  635.          begin
  636.             l := linebase;
  637.             l0 := nil;
  638.             while (l <> nil) and (l^.num < curline) do
  639.                begin
  640.                   l0 := l;
  641.                   l := l^.next;
  642.                end;
  643.             if (l <> nil) and (l^.num = curline) then
  644.                begin
  645.                   l1 := l;
  646.                   l := l^.next;
  647.                   if l0 = nil then
  648.                      linebase := l
  649.                   else
  650.                      l0^.next := l;
  651.                   disposetokens(l1^.txt);
  652.                   dispose(l1);
  653.                end;
  654.             if buf <> nil then
  655.                begin
  656.                   new(l1);
  657.                   l1^.next := l;
  658.                   if l0 = nil then
  659.                      linebase := l1
  660.                   else
  661.                      l0^.next := l1;
  662.                   l1^.num := curline;
  663.                   l1^.txt := buf;
  664.                end;
  665.             clearloops;
  666.             restoredata;
  667.          end;
  668.    end;
  669.  
  670.  
  671.  
  672.  
  673.  
  674. procedure errormsg(s : string255);
  675.    begin
  676.       write(#7, s);
  677.       escape(42);
  678.    end;
  679.  
  680.  
  681. procedure snerr;
  682.    begin
  683.       errormsg('Syntax error');
  684.    end;
  685.  
  686. procedure tmerr;
  687.    begin
  688.       errormsg('Type mismatch error');
  689.    end;
  690.  
  691. procedure badsubscr;
  692.    begin
  693.       errormsg('Bad subscript');
  694.    end;
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701. procedure exec;
  702.  
  703.    var
  704.       gotoflag, elseflag : boolean;
  705.       t : tokenptr;
  706.       ioerrmsg : string255ptr;
  707.  
  708.  
  709.    function factor : valrec;
  710.       forward;
  711.  
  712.    function expr : valrec;
  713.       forward;
  714.  
  715.    function realfactor : real;
  716.       var
  717.          n : valrec;
  718.       begin
  719.          n := factor;
  720.          if n.stringval then tmerr;
  721.          realfactor := n.val;
  722.       end;
  723.  
  724.    function strfactor : basicstring;
  725.       var
  726.          n : valrec;
  727.       begin
  728.          n := factor;
  729.          if not n.stringval then tmerr;
  730.          strfactor := n.sval;
  731.       end;
  732.  
  733.    function stringfactor : string255;
  734.       var
  735.          n : valrec;
  736.       begin
  737.          n := factor;
  738.          if not n.stringval then tmerr;
  739.          stringfactor := n.sval^;
  740.          dispose(n.sval);
  741.       end;
  742.  
  743.    function intfactor : integer;
  744.       begin
  745.          intfactor := round(realfactor);
  746.       end;
  747.  
  748.    function realexpr : real;
  749.       var
  750.          n : valrec;
  751.       begin
  752.          n := expr;
  753.          if n.stringval then tmerr;
  754.          realexpr := n.val;
  755.       end;
  756.  
  757.    function strexpr : basicstring;
  758.       var
  759.          n : valrec;
  760.       begin
  761.          n := expr;
  762.          if not n.stringval then tmerr;
  763.          strexpr := n.sval;
  764.       end;
  765.  
  766.    function stringexpr : string255;
  767.       var
  768.          n : valrec;
  769.       begin
  770.          n := expr;
  771.          if not n.stringval then tmerr;
  772.          stringexpr := n.sval^;
  773.          dispose(n.sval);
  774.       end;
  775.  
  776.    function intexpr : integer;
  777.       begin
  778.          intexpr := round(realexpr);
  779.       end;
  780.  
  781.  
  782.    procedure require(k : tokenkinds);
  783.       begin
  784.          if (t = nil) or (t^.kind <> k) then
  785.             snerr;
  786.          t := t^.next;
  787.       end;
  788.  
  789.  
  790.    procedure skipparen;
  791.       label 1;
  792.       begin
  793.          repeat
  794.             if t = nil then snerr;
  795.             if (t^.kind = tokrp) or (t^.kind = tokcomma) then
  796.                goto 1;
  797.             if t^.kind = toklp then
  798.                begin
  799.                   t := t^.next;
  800.                   skipparen;
  801.                end;
  802.             t := t^.next;
  803.          until false;
  804.        1 :
  805.       end;
  806.  
  807.  
  808.    function findvar : varptr;
  809.       var
  810.          v : varptr;
  811.          i, j, k : integer;
  812.          tok : tokenptr;
  813.       begin
  814.          if (t = nil) or (t^.kind <> tokvar) then snerr;
  815.          v := t^.vp;
  816.          t := t^.next;
  817.          if (t <> nil) and (t^.kind = toklp) then
  818.             with v^ do
  819.                begin
  820.                   if numdims = 0 then
  821.                      begin
  822.                         tok := t;
  823.                         i := 0;
  824.                         j := 1;
  825.                         repeat
  826.                            if i >= maxdims then badsubscr;
  827.                            t := t^.next;
  828.                            skipparen;
  829.                            j := j * 11;
  830.                            i := i + 1;
  831.                            dims[i] := 11;
  832.                         until t^.kind = tokrp;
  833.                         numdims := i;
  834.                         if stringvar then
  835.                            begin
  836.                               hpm_new(sarr, j*4);
  837.                               for k := 0 to j-1 do
  838.                                  sarr^[k] := nil;
  839.                            end
  840.                         else
  841.                            begin
  842.                               hpm_new(arr, j*8);
  843.                               for k := 0 to j-1 do
  844.                                  arr^[k] := 0;
  845.                            end;
  846.                         t := tok;
  847.                      end;
  848.                   k := 0;
  849.                   t := t^.next;
  850.                   for i := 1 to numdims do
  851.                      begin
  852.                         j := intexpr;
  853.                         if (j < 0) or (j >= dims[i]) then
  854.                            badsubscr;
  855.                         k := k * dims[i] + j;
  856.                         if i < numdims then
  857.                            require(tokcomma);
  858.                      end;
  859.                   require(tokrp);
  860.                   if stringvar then
  861.                       sval := addr(sarr^[k])
  862.                   else
  863.                       val := addr(arr^[k]);
  864.                end
  865.          else
  866.             begin
  867.                if v^.numdims <> 0 then
  868.                   badsubscr;
  869.             end;
  870.          findvar := v;
  871.       end;
  872.  
  873.  
  874.    function inot(i : integer) : integer;
  875.       begin
  876.          inot := -1 - i;
  877.       end;
  878.  
  879.    function ixor(a, b : integer) : integer;
  880.       begin
  881.          ixor := asm_ior(asm_iand(a, inot(b)), asm_iand(inot(a), b));
  882.       end;
  883.  
  884.  
  885.    function factor : valrec;
  886.       var
  887.          v : varptr;
  888.          facttok : tokenptr;
  889.          n : valrec;
  890.          i, j : integer;
  891.          tok, tok1 : tokenptr;
  892.          s : basicstring;
  893.          trick :
  894.             record
  895.                case boolean of
  896.                   true : (i : integer);
  897.                   false : (c : ^char);
  898.             end;
  899.       begin
  900.          if t = nil then snerr;
  901.          facttok := t;
  902.          t := t^.next;
  903.          n.stringval := false;
  904.          case facttok^.kind of
  905.             toknum :
  906.                n.val := facttok^.num;
  907.             tokstr :
  908.                begin
  909.                   n.stringval := true;
  910.                   new(n.sval);
  911.                   n.sval^ := facttok^.sp^;
  912.                end;
  913.             tokvar :
  914.                begin
  915.                   t := facttok;
  916.                   v := findvar;
  917.                   n.stringval := v^.stringvar;
  918.                   if n.stringval then
  919.                      begin
  920.                         new(n.sval);
  921.                         n.sval^ := v^.sval^^;
  922.                      end
  923.                   else
  924.                      n.val := v^.val^;
  925.                end;
  926.             toklp :
  927.                begin
  928.                   n := expr;
  929.                   require(tokrp);
  930.                end;
  931.             tokminus :
  932.                n.val := - realfactor;
  933.             tokplus :
  934.                n.val := realfactor;
  935.             toknot :
  936.                n.val := inot(intfactor);
  937.             toksqr :
  938.                n.val := sqr(realfactor);
  939.             toksqrt :
  940.                n.val := sqrt(realfactor);
  941.             toksin :
  942.                n.val := sin(realfactor);
  943.             tokcos :
  944.                n.val := cos(realfactor);
  945.             toktan :
  946.                begin
  947.                   n.val := realfactor;
  948.                   n.val := sin(n.val) / cos(n.val);
  949.                end;
  950.             tokarctan :
  951.                n.val := arctan(realfactor);
  952.             toklog:
  953.                n.val := ln(realfactor);
  954.             tokexp :
  955.                n.val := exp(realfactor);
  956.             tokabs :
  957.                n.val := abs(realfactor);
  958.             toksgn :
  959.                begin
  960.                   n.val := realfactor;
  961.                   n.val := ord(n.val > 0) - ord(n.val < 0);
  962.                end;
  963.             tokstr_ :
  964.                begin
  965.                   n.stringval := true;
  966.                   new(n.sval);
  967.                   n.sval^ := numtostr(realfactor);
  968.                end;
  969.             tokval :
  970.                begin
  971.                   s := strfactor;
  972.                   tok1 := t;
  973.                   parse(s, t);
  974.                   tok := t;
  975.                   if tok = nil then
  976.                      n.val := 0
  977.                   else
  978.                      n := expr;
  979.                   disposetokens(tok);
  980.                   t := tok1;
  981.                   dispose(s);
  982.                end;
  983.             tokchr_ :
  984.                begin
  985.                   n.stringval := true;
  986.                   new(n.sval);
  987.                   n.sval^ := ' ';
  988.                   n.sval^[1] := chr(intfactor);
  989.                end;
  990.             tokasc :
  991.                begin
  992.                   s := strfactor;
  993.                   if strlen(s^) = 0 then
  994.                      n.val := 0
  995.                   else
  996.                      n.val := ord(s^[1]);
  997.                   dispose(s);
  998.                end;
  999.             tokmid_ :
  1000.                begin
  1001.                   n.stringval := true;
  1002.                   require(toklp);
  1003.                   n.sval := strexpr;
  1004.                   require(tokcomma);
  1005.                   i := intexpr;
  1006.                   if i < 1 then i := 1;
  1007.                   j := 255;
  1008.                   if (t <> nil) and (t^.kind = tokcomma) then
  1009.                      begin
  1010.                         t := t^.next;
  1011.                         j := intexpr;
  1012.                      end;
  1013.                   if j > strlen(n.sval^)-i+1 then
  1014.                      j := strlen(n.sval^)-i+1;
  1015.                   if i > strlen(n.sval^) then
  1016.                      n.sval^ := ''
  1017.                   else
  1018.                      n.sval^ := str(n.sval^, i, j);
  1019.                   require(tokrp);
  1020.                end;
  1021.             toklen :
  1022.                begin
  1023.                   s := strfactor;
  1024.                   n.val := strlen(s^);
  1025.                   dispose(s);
  1026.                end;
  1027.             tokpeek :
  1028.                begin
  1029.                   $range off$
  1030.                   trick.i := intfactor;
  1031.                   n.val := ord(trick.c^);
  1032.                   $if checking$ $range on$ $end$
  1033.                end;
  1034.             otherwise
  1035.                snerr;
  1036.          end;
  1037.          factor := n;
  1038.       end;
  1039.  
  1040.    function upexpr : valrec;
  1041.       var
  1042.          n, n2 : valrec;
  1043.       begin
  1044.          n := factor;
  1045.          while (t <> nil) and (t^.kind = tokup) do
  1046.             begin
  1047.                if n.stringval then tmerr;
  1048.                t := t^.next;
  1049.                n2 := upexpr;
  1050.                if n2.stringval then tmerr;
  1051.                if n.val < 0 then
  1052.                   begin
  1053.                      if n2.val <> trunc(n2.val) then n.val := ln(n.val);
  1054.                      n.val := exp(n2.val * ln(-n.val));
  1055.                      if odd(trunc(n2.val)) then
  1056.                         n.val := - n.val;
  1057.                   end
  1058.                else
  1059.                   n.val := exp(n2.val * ln(n.val));
  1060.             end;
  1061.          upexpr := n;
  1062.       end;
  1063.  
  1064.    function term : valrec;
  1065.       var
  1066.          n, n2 : valrec;
  1067.          k : tokenkinds;
  1068.       begin
  1069.          n := upexpr;
  1070.          while (t <> nil) and (t^.kind in [toktimes, tokdiv, tokmod]) do
  1071.             begin
  1072.                k := t^.kind;
  1073.                t := t^.next;
  1074.                n2 := upexpr;
  1075.                if n.stringval or n2.stringval then tmerr;
  1076.                if k = tokmod then
  1077.                   n.val := round(n.val) mod round(n2.val)
  1078.                else if k = toktimes then
  1079.                   n.val := n.val * n2.val
  1080.                else
  1081.                   n.val := n.val / n2.val;
  1082.             end;
  1083.          term := n;
  1084.       end;
  1085.  
  1086.    function sexpr : valrec;
  1087.       var
  1088.          n, n2 : valrec;
  1089.          k : tokenkinds;
  1090.       begin
  1091.          n := term;
  1092.          while (t <> nil) and (t^.kind in [tokplus, tokminus]) do
  1093.             begin
  1094.                k := t^.kind;
  1095.                t := t^.next;
  1096.                n2 := term;
  1097.                if n.stringval <> n2.stringval then tmerr;
  1098.                if k = tokplus then
  1099.                   if n.stringval then
  1100.                      begin
  1101.                         n.sval^ := n.sval^ + n2.sval^;
  1102.                         dispose(n2.sval);
  1103.                      end
  1104.                   else
  1105.                      n.val := n.val + n2.val
  1106.                else
  1107.                   if n.stringval then
  1108.                      tmerr
  1109.                   else
  1110.                      n.val := n.val - n2.val;
  1111.             end;
  1112.          sexpr := n;
  1113.       end;
  1114.  
  1115.    function relexpr : valrec;
  1116.       var
  1117.          n, n2 : valrec;
  1118.          f : boolean;
  1119.          k : tokenkinds;
  1120.       begin
  1121.          n := sexpr;
  1122.          while (t <> nil) and (t^.kind in [tokeq..tokne]) do
  1123.             begin
  1124.                k := t^.kind;
  1125.                t := t^.next;
  1126.                n2 := sexpr;
  1127.                if n.stringval <> n2.stringval then tmerr;
  1128.                if n.stringval then
  1129.                   begin
  1130.                      f := ((n.sval^ = n2.sval^) and (k in [tokeq, tokge, tokle]) or
  1131.                            (n.sval^ < n2.sval^) and (k in [toklt, tokle, tokne]) or
  1132.                            (n.sval^ > n2.sval^) and (k in [tokgt, tokge, tokne]));
  1133.                      dispose(n.sval);
  1134.                      dispose(n2.sval);
  1135.                   end
  1136.                else
  1137.                   f := ((n.val = n2.val) and (k in [tokeq, tokge, tokle]) or
  1138.                         (n.val < n2.val) and (k in [toklt, tokle, tokne]) or
  1139.                         (n.val > n2.val) and (k in [tokgt, tokge, tokne]));
  1140.                n.stringval := false;
  1141.                n.val := ord(f);
  1142.             end;
  1143.          relexpr := n;
  1144.       end;
  1145.  
  1146.    function andexpr : valrec;
  1147.       var
  1148.          n, n2 : valrec;
  1149.       begin
  1150.          n := relexpr;
  1151.          while (t <> nil) and (t^.kind = tokand) do
  1152.             begin
  1153.                t := t^.next;
  1154.                n2 := relexpr;
  1155.                if n.stringval or n2.stringval then tmerr;
  1156.                n.val := asm_iand(trunc(n.val), trunc(n2.val));
  1157.             end;
  1158.          andexpr := n;
  1159.       end;
  1160.  
  1161.    function expr : valrec;
  1162.       var
  1163.          n, n2 : valrec;
  1164.          k : tokenkinds;
  1165.       begin
  1166.          n := andexpr;
  1167.          while (t <> nil) and (t^.kind in [tokor, tokxor]) do
  1168.             begin
  1169.                k := t^.kind;
  1170.                t := t^.next;
  1171.                n2 := andexpr;
  1172.                if n.stringval or n2.stringval then tmerr;
  1173.                if k = tokor then
  1174.                   n.val := asm_ior(trunc(n.val), trunc(n2.val))
  1175.                else
  1176.                   n.val := ixor(trunc(n.val), trunc(n2.val));
  1177.             end;
  1178.          expr := n;
  1179.       end;
  1180.  
  1181.  
  1182.    procedure checkextra;
  1183.       begin
  1184.          if t <> nil then
  1185.             errormsg('Extra information on line');
  1186.       end;
  1187.  
  1188.  
  1189.    function iseos : boolean;
  1190.       begin
  1191.          iseos := (t = nil) or (t^.kind in [tokcolon, tokelse]);
  1192.       end;
  1193.  
  1194.  
  1195.    procedure skiptoeos;
  1196.       begin
  1197.          while not iseos do
  1198.             t := t^.next;
  1199.       end;
  1200.  
  1201.  
  1202.    function findline(n : integer) : lineptr;
  1203.       var
  1204.          l : lineptr;
  1205.       begin
  1206.          l := linebase;
  1207.          while (l <> nil) and (l^.num <> n) do
  1208.             l := l^.next;
  1209.          findline := l;
  1210.       end;
  1211.  
  1212.  
  1213.    function mustfindline(n : integer) : lineptr;
  1214.       var
  1215.          l : lineptr;
  1216.       begin
  1217.          l := findline(n);
  1218.          if l = nil then
  1219.             errormsg('Undefined line');
  1220.          mustfindline := l;
  1221.       end;
  1222.  
  1223.  
  1224.    procedure cmdend;
  1225.       begin
  1226.          stmtline := nil;
  1227.          t := nil;
  1228.       end;
  1229.  
  1230.  
  1231.    procedure cmdnew;
  1232.       var
  1233.          p : anyptr;
  1234.       begin
  1235.          cmdend;
  1236.          clearloops;
  1237.          restoredata;
  1238.          while linebase <> nil do
  1239.             begin
  1240.                p := linebase^.next;
  1241.                disposetokens(linebase^.txt);
  1242.                dispose(linebase);
  1243.                linebase := p;
  1244.             end;
  1245.          while varbase <> nil do
  1246.             begin
  1247.                p := varbase^.next;
  1248.                if varbase^.stringvar then
  1249.                   if varbase^.sval^ <> nil then
  1250.                      dispose(varbase^.sval^);
  1251.                dispose(varbase);
  1252.                varbase := p;
  1253.             end;
  1254.       end;
  1255.  
  1256.  
  1257.    procedure cmdlist;
  1258.       var
  1259.          l : lineptr;
  1260.          n1, n2 : integer;
  1261.       begin
  1262.          repeat
  1263.             n1 := 0;
  1264.             n2 := maxint;
  1265.             if (t <> nil) and (t^.kind = toknum) then
  1266.                begin
  1267.                   n1 := trunc(t^.num);
  1268.                   t := t^.next;
  1269.                   if (t = nil) or (t^.kind <> tokminus) then
  1270.                      n2 := n1;
  1271.                end;
  1272.             if (t <> nil) and (t^.kind = tokminus) then
  1273.                begin
  1274.                   t := t^.next;
  1275.                   if (t <> nil) and (t^.kind = toknum) then
  1276.                      begin
  1277.                         n2 := trunc(t^.num);
  1278.                         t := t^.next;
  1279.                      end
  1280.                   else
  1281.                      n2 := maxint;
  1282.                end;
  1283.             l := linebase;
  1284.             while (l <> nil) and (l^.num <= n2) do
  1285.                begin
  1286.                   if (l^.num >= n1) then
  1287.                      begin
  1288.                         write(l^.num:1, ' ');
  1289.                         listtokens(output, l^.txt);
  1290.                         writeln;
  1291.                      end;
  1292.                   l := l^.next;
  1293.                end;
  1294.             if not iseos then
  1295.                require(tokcomma);
  1296.          until iseos;
  1297.       end;
  1298.  
  1299.  
  1300.    procedure cmdload(merging : boolean; name : string255);
  1301.       var
  1302.          f : text;
  1303.          buf : tokenptr;
  1304.       begin
  1305.          if not merging then
  1306.             cmdnew;
  1307.          reset(f, name + '.TXT', 'shared');
  1308.          while not eof(f) do
  1309.             begin
  1310.                readln(f, inbuf^);
  1311.                parseinput(buf);
  1312.                if curline = 0 then
  1313.                   begin
  1314.                      writeln('Bad line in file');
  1315.                      disposetokens(buf);
  1316.                   end;
  1317.             end;
  1318.          close(f);
  1319.       end;
  1320.  
  1321.  
  1322.    procedure cmdrun;
  1323.       var
  1324.          l : lineptr;
  1325.          i : integer;
  1326.          s : string255;
  1327.       begin
  1328.          l := linebase;
  1329.          if not iseos then
  1330.             begin
  1331.                if t^.kind = toknum then
  1332.                   l := mustfindline(intexpr)
  1333.                else
  1334.                   begin
  1335.                      s := stringexpr;
  1336.                      i := 0;
  1337.                      if not iseos then
  1338.                         begin
  1339.                            require(tokcomma);
  1340.                            i := intexpr;
  1341.                         end;
  1342.                      checkextra;
  1343.                      cmdload(false, s);
  1344.                      if i = 0 then
  1345.                         l := linebase
  1346.                      else
  1347.                         l := mustfindline(i)
  1348.                   end
  1349.             end;
  1350.          stmtline := l;
  1351.          gotoflag := true;
  1352.          clearvars;
  1353.          clearloops;
  1354.          restoredata;
  1355.       end;
  1356.  
  1357.  
  1358.    procedure cmdsave;
  1359.       var
  1360.          f : text;
  1361.          l : lineptr;
  1362.       begin
  1363.          rewrite(f, stringexpr + '.TXT');
  1364.          l := linebase;
  1365.          while l <> nil do
  1366.             begin
  1367.                write(f, l^.num:1, ' ');
  1368.                listtokens(f, l^.txt);
  1369.                writeln(f);
  1370.                l := l^.next;
  1371.             end;
  1372.          close(f, 'save');
  1373.       end;
  1374.  
  1375.  
  1376.    procedure cmdbye;
  1377.       begin
  1378.          exitflag := true;
  1379.       end;
  1380.  
  1381.  
  1382.    procedure cmddel;
  1383.       var
  1384.          l, l0, l1 : lineptr;
  1385.          n1, n2 : integer;
  1386.       begin
  1387.          repeat
  1388.             if iseos then snerr;
  1389.             n1 := 0;
  1390.             n2 := maxint;
  1391.             if (t <> nil) and (t^.kind = toknum) then
  1392.                begin
  1393.                   n1 := trunc(t^.num);
  1394.                   t := t^.next;
  1395.                   if (t = nil) or (t^.kind <> tokminus) then
  1396.                      n2 := n1;
  1397.                end;
  1398.             if (t <> nil) and (t^.kind = tokminus) then
  1399.                begin
  1400.                   t := t^.next;
  1401.                   if (t <> nil) and (t^.kind = toknum) then
  1402.                      begin
  1403.                         n2 := trunc(t^.num);
  1404.                         t := t^.next;
  1405.                      end
  1406.                   else
  1407.                      n2 := maxint;
  1408.                end;
  1409.             l := linebase;
  1410.             l0 := nil;
  1411.             while (l <> nil) and (l^.num <= n2) do
  1412.                begin
  1413.                   l1 := l^.next;
  1414.                   if (l^.num >= n1) then
  1415.                      begin
  1416.                         if l = stmtline then
  1417.                            begin
  1418.                               cmdend;
  1419.                               clearloops;
  1420.                               restoredata;
  1421.                            end;
  1422.                         if l0 = nil then
  1423.                            linebase := l^.next
  1424.                         else
  1425.                            l0^.next := l^.next;
  1426.                         disposetokens(l^.txt);
  1427.                         dispose(l);
  1428.                      end
  1429.                   else
  1430.                      l0 := l;
  1431.                   l := l1;
  1432.                end;
  1433.             if not iseos then
  1434.                require(tokcomma);
  1435.          until iseos;
  1436.       end;
  1437.  
  1438.  
  1439.    procedure cmdrenum;
  1440.       var
  1441.          l, l1 : lineptr;
  1442.          tok : tokenptr;
  1443.          lnum, step : integer;
  1444.       begin
  1445.          lnum := 10;
  1446.          step := 10;
  1447.          if not iseos then
  1448.             begin
  1449.                lnum := intexpr;
  1450.                if not iseos then
  1451.                   begin
  1452.                      require(tokcomma);
  1453.                      step := intexpr;
  1454.                   end;
  1455.             end;
  1456.          l := linebase;
  1457.          if l <> nil then
  1458.             begin
  1459.                while l <> nil do
  1460.                   begin
  1461.                      l^.num2 := lnum;
  1462.                      lnum := lnum + step;
  1463.                      l := l^.next;
  1464.                   end;
  1465.                l := linebase;
  1466.                repeat
  1467.                   tok := l^.txt;
  1468.                   repeat
  1469.                      if tok^.kind in [tokgoto, tokgosub, tokthen, tokelse, 
  1470.                                       tokrun, toklist, tokrestore, tokdel] then
  1471.                         while (tok^.next <> nil) and (tok^.next^.kind = toknum) do
  1472.                            begin
  1473.                               tok := tok^.next;
  1474.                               lnum := round(tok^.num);
  1475.                               l1 := linebase;
  1476.                               while (l1 <> nil) and (l1^.num <> lnum) do
  1477.                                  l1 := l1^.next;
  1478.                               if l1 = nil then
  1479.                                  writeln('Undefined line ', lnum:1, ' in line ', l^.num2:1)
  1480.                               else
  1481.                                  tok^.num := l1^.num2;
  1482.                               if (tok^.next <> nil) and (tok^.next^.kind = tokcomma) then
  1483.                                  tok := tok^.next;
  1484.                            end;
  1485.                      tok := tok^.next;
  1486.                   until tok = nil;
  1487.                   l := l^.next;
  1488.                until l = nil;
  1489.                l := linebase;
  1490.                while l <> nil do
  1491.                   begin
  1492.                      l^.num := l^.num2;
  1493.                      l := l^.next;
  1494.                   end;
  1495.             end;
  1496.       end;
  1497.  
  1498.  
  1499.    procedure cmdprint;
  1500.       var
  1501.          semiflag : boolean;
  1502.          n : valrec;
  1503.       begin
  1504.          semiflag := false;
  1505.          while not iseos do
  1506.             begin
  1507.                semiflag := false;
  1508.                if t^.kind in [toksemi, tokcomma] then
  1509.                   begin
  1510.                      semiflag := true;
  1511.                      t := t^.next;
  1512.                   end
  1513.                else
  1514.                   begin
  1515.                      n := expr;
  1516.                      if n.stringval then
  1517.                         begin
  1518.                            write(n.sval^);
  1519.                            dispose(n.sval);
  1520.                         end
  1521.                      else
  1522.                         write(numtostr(n.val), ' ');
  1523.                   end;
  1524.             end;
  1525.          if not semiflag then 
  1526.             writeln;
  1527.       end;
  1528.  
  1529.  
  1530.    procedure cmdinput;
  1531.       var
  1532.          v : varptr;
  1533.          s : string255;
  1534.          tok, tok0, tok1 : tokenptr;
  1535.          strflag : boolean;
  1536.       begin
  1537.          if (t <> nil) and (t^.kind = tokstr) then
  1538.             begin
  1539.                write(t^.sp^);
  1540.                t := t^.next;
  1541.                require(toksemi);
  1542.             end
  1543.          else
  1544.             begin
  1545.                write('? ');
  1546.             end;
  1547.          tok := t;
  1548.          if (t = nil) or (t^.kind <> tokvar) then snerr;
  1549.          strflag := t^.vp^.stringvar;
  1550.          repeat
  1551.             if (t <> nil) and (t^.kind = tokvar) then
  1552.                if t^.vp^.stringvar <> strflag then snerr;
  1553.             t := t^.next;
  1554.          until iseos;
  1555.          t := tok;
  1556.          if strflag then
  1557.             begin
  1558.                repeat
  1559.                   readln(s);
  1560.                   v := findvar;
  1561.                   if v^.sval^ <> nil then
  1562.                      dispose(v^.sval^);
  1563.                   new(v^.sval^);
  1564.                   v^.sval^^ := s;
  1565.                   if not iseos then
  1566.                      begin
  1567.                         require(tokcomma);
  1568.                         write('?? ');
  1569.                      end;
  1570.                until iseos;
  1571.             end
  1572.          else
  1573.             begin
  1574.                readln(s);
  1575.                parse(addr(s), tok);
  1576.                tok0 := tok;
  1577.                repeat
  1578.                   v := findvar;
  1579.                   while tok = nil do
  1580.                      begin
  1581.                         write('?? ');
  1582.                         readln(s);
  1583.                         disposetokens(tok0);
  1584.                         parse(addr(s), tok);
  1585.                         tok0 := tok;
  1586.                      end;
  1587.                   tok1 := t;
  1588.                   t := tok;
  1589.                   v^.val^ := realexpr;
  1590.                   if t <> nil then
  1591.                      if t^.kind = tokcomma then
  1592.                         t := t^.next
  1593.                      else
  1594.                         snerr;
  1595.                   tok := t;
  1596.                   t := tok1;
  1597.                   if not iseos then
  1598.                      require(tokcomma);
  1599.                until iseos;
  1600.                disposetokens(tok0);
  1601.             end;
  1602.       end;
  1603.  
  1604.  
  1605.    procedure cmdlet(implied : boolean);
  1606.       var
  1607.          v : varptr;
  1608.      old : basicstring;
  1609.       begin
  1610.          if implied then
  1611.             t := stmttok;
  1612.          v := findvar;
  1613.          require(tokeq);
  1614.          if v^.stringvar then
  1615.             begin
  1616.                old := v^.sval^;
  1617.                v^.sval^ := strexpr;
  1618.                if old <> nil then
  1619.                   dispose(old);
  1620.             end
  1621.          else
  1622.             v^.val^ := realexpr;
  1623.       end;
  1624.  
  1625.  
  1626.    procedure cmdgoto;
  1627.       begin
  1628.          stmtline := mustfindline(intexpr);
  1629.          t := nil;
  1630.          gotoflag := true;
  1631.       end;
  1632.  
  1633.  
  1634.    procedure cmdif;
  1635.       var
  1636.          n : real;
  1637.          i : integer;
  1638.       begin
  1639.          n := realexpr;
  1640.          require(tokthen);
  1641.          if n = 0 then
  1642.             begin
  1643.                i := 0;
  1644.                repeat
  1645.                   if t <> nil then
  1646.                      begin
  1647.                         if t^.kind = tokif then
  1648.                            i := i + 1;
  1649.                         if t^.kind = tokelse then
  1650.                            i := i - 1;
  1651.                         t := t^.next;
  1652.                      end;
  1653.                until (t = nil) or (i < 0);
  1654.             end;
  1655.          if (t <> nil) and (t^.kind = toknum) then
  1656.             cmdgoto
  1657.          else
  1658.             elseflag := true;
  1659.       end;
  1660.  
  1661.  
  1662.    procedure cmdelse;
  1663.       begin
  1664.          t := nil;
  1665.       end;
  1666.  
  1667.  
  1668.    function skiploop(up, dn : tokenkinds) : boolean;
  1669.       label 1;
  1670.       var
  1671.          i : integer;
  1672.          saveline : lineptr;
  1673.       begin
  1674.          saveline := stmtline;
  1675.          i := 0;
  1676.          repeat
  1677.             while t = nil do
  1678.                begin
  1679.                   if (stmtline = nil) or (stmtline^.next = nil) then
  1680.                      begin
  1681.                         skiploop := false;
  1682.                         stmtline := saveline;
  1683.                         goto 1;
  1684.                      end;
  1685.                   stmtline := stmtline^.next;
  1686.                   t := stmtline^.txt;
  1687.                end;
  1688.             if t^.kind = up then
  1689.                i := i + 1;
  1690.             if t^.kind = dn then
  1691.                i := i - 1;
  1692.             t := t^.next;
  1693.          until i < 0;
  1694.          skiploop := true;
  1695.      1 :
  1696.       end;
  1697.  
  1698.  
  1699.    procedure cmdfor;
  1700.       var
  1701.          l : loopptr;
  1702.          lr : looprec;
  1703.          saveline : lineptr;
  1704.          i, j : integer;
  1705.       begin
  1706.          lr.vp := findvar;
  1707.          if lr.vp^.stringvar then snerr;
  1708.          require(tokeq);
  1709.          lr.vp^.val^ := realexpr;
  1710.          require(tokto);
  1711.          lr.max := realexpr;
  1712.          if (t <> nil) and (t^.kind = tokstep) then
  1713.             begin
  1714.                t := t^.next;
  1715.                lr.step := realexpr;
  1716.             end
  1717.          else
  1718.             lr.step := 1;
  1719.          lr.homeline := stmtline;
  1720.          lr.hometok := t;
  1721.          lr.kind := forloop;
  1722.          lr.next := loopbase;
  1723.          with lr do
  1724.             if ((step >= 0) and (vp^.val^ > max)) or ((step <= 0) and (vp^.val^ < max)) then
  1725.                begin
  1726.                   saveline := stmtline;
  1727.                   i := 0;
  1728.                   j := 0;
  1729.                   repeat
  1730.                      while t = nil do
  1731.                         begin
  1732.                            if (stmtline = nil) or (stmtline^.next = nil) then
  1733.                               begin
  1734.                                  stmtline := saveline;
  1735.                                  errormsg('FOR without NEXT');
  1736.                               end;
  1737.                            stmtline := stmtline^.next;
  1738.                            t := stmtline^.txt;
  1739.                         end;
  1740.                      if t^.kind = tokfor then
  1741.                         if (t^.next <> nil) and (t^.next^.kind = tokvar) and (t^.next^.vp = vp) then
  1742.                            j := j + 1
  1743.                         else
  1744.                            i := i + 1;
  1745.                      if (t^.kind = toknext) then
  1746.                         if (t^.next <> nil) and (t^.next^.kind = tokvar) and (t^.next^.vp = vp) then
  1747.                            j := j - 1
  1748.                         else
  1749.                            i := i - 1;
  1750.                      t := t^.next;
  1751.                   until (i < 0) or (j < 0);
  1752.                   skiptoeos;
  1753.                end
  1754.             else
  1755.                begin
  1756.                   new(l);
  1757.                   l^ := lr;
  1758.                   loopbase := l;
  1759.                end;
  1760.       end;
  1761.  
  1762.  
  1763.    procedure cmdnext;
  1764.       var
  1765.          v : varptr;
  1766.          found : boolean;
  1767.          l : loopptr;
  1768.       begin
  1769.          if not iseos then
  1770.             v := findvar
  1771.          else
  1772.             v := nil;
  1773.          repeat
  1774.             if (loopbase = nil) or (loopbase^.kind = gosubloop) then 
  1775.                errormsg('NEXT without FOR');
  1776.             found := (loopbase^.kind = forloop) and
  1777.                      ((v = nil) or (loopbase^.vp = v));
  1778.             if not found then
  1779.                begin
  1780.                   l := loopbase^.next;
  1781.                   dispose(loopbase);
  1782.                   loopbase := l;
  1783.                end;
  1784.          until found;
  1785.          with loopbase^ do
  1786.             begin
  1787.                vp^.val^ := vp^.val^ + step;
  1788.                if ((step >= 0) and (vp^.val^ > max)) or ((step <= 0) and (vp^.val^ < max)) then
  1789.                   begin
  1790.                      l := loopbase^.next;
  1791.                      dispose(loopbase);
  1792.                      loopbase := l;
  1793.                   end
  1794.                else
  1795.                   begin
  1796.                      stmtline := homeline;
  1797.                      t := hometok;
  1798.                   end;
  1799.             end;
  1800.       end;
  1801.  
  1802.  
  1803.    procedure cmdwhile;
  1804.       var
  1805.          l : loopptr;
  1806.       begin
  1807.          new(l);
  1808.          l^.next := loopbase;
  1809.          loopbase := l;
  1810.          l^.kind := whileloop;
  1811.          l^.homeline := stmtline;
  1812.          l^.hometok := t;
  1813.          if not iseos then
  1814.             if realexpr = 0 then
  1815.                begin
  1816.                   if not skiploop(tokwhile, tokwend) then 
  1817.                      errormsg('WHILE without WEND');
  1818.                   l := loopbase^.next;
  1819.                   dispose(loopbase);
  1820.                   loopbase := l;
  1821.                   skiptoeos;
  1822.                end;
  1823.       end;
  1824.  
  1825.  
  1826.    procedure cmdwend;
  1827.       var
  1828.          tok : tokenptr;
  1829.          tokline : lineptr;
  1830.          l : loopptr;
  1831.          found : boolean;
  1832.       begin
  1833.          repeat
  1834.             if (loopbase = nil) or (loopbase^.kind = gosubloop) then
  1835.                errormsg('WEND without WHILE');
  1836.             found := (loopbase^.kind = whileloop);
  1837.             if not found then
  1838.                begin
  1839.                   l := loopbase^.next;
  1840.                   dispose(loopbase);
  1841.                   loopbase := l;
  1842.                end;
  1843.          until found;
  1844.          if not iseos then
  1845.             if realexpr <> 0 then
  1846.                found := false;
  1847.          tok := t;
  1848.          tokline := stmtline;
  1849.          if found then
  1850.             begin
  1851.                stmtline := loopbase^.homeline;
  1852.                t := loopbase^.hometok;
  1853.                if not iseos then
  1854.                   if realexpr = 0 then
  1855.                      found := false;
  1856.             end;
  1857.          if not found then
  1858.             begin
  1859.                t := tok;
  1860.                stmtline := tokline;
  1861.                l := loopbase^.next;
  1862.                dispose(loopbase);
  1863.                loopbase := l;
  1864.             end;
  1865.       end;
  1866.  
  1867.  
  1868.    procedure cmdgosub;
  1869.       var
  1870.          l : loopptr;
  1871.       begin
  1872.          new(l);
  1873.          l^.next := loopbase;
  1874.          loopbase := l;
  1875.          l^.kind := gosubloop;
  1876.          l^.homeline := stmtline;
  1877.          l^.hometok := t;
  1878.          cmdgoto;
  1879.       end;
  1880.  
  1881.  
  1882.    procedure cmdreturn;
  1883.       var
  1884.          l : loopptr;
  1885.          found : boolean;
  1886.       begin
  1887.          repeat
  1888.             if loopbase = nil then
  1889.                errormsg('RETURN without GOSUB');
  1890.             found := (loopbase^.kind = gosubloop);
  1891.             if not found then
  1892.                begin
  1893.                   l := loopbase^.next;
  1894.                   dispose(loopbase);
  1895.                   loopbase := l;
  1896.                end;
  1897.          until found;
  1898.          stmtline := loopbase^.homeline;
  1899.          t := loopbase^.hometok;
  1900.          l := loopbase^.next;
  1901.          dispose(loopbase);
  1902.          loopbase := l;
  1903.          skiptoeos;
  1904.       end;
  1905.  
  1906.  
  1907.    procedure cmdread;
  1908.       var
  1909.          v : varptr;
  1910.          tok : tokenptr;
  1911.          found : boolean;
  1912.       begin
  1913.          repeat
  1914.             v := findvar;
  1915.             tok := t;
  1916.             t := datatok;
  1917.             if dataline = nil then
  1918.                begin
  1919.                   dataline := linebase;
  1920.                   t := dataline^.txt;
  1921.                end;
  1922.             if (t = nil) or (t^.kind <> tokcomma) then
  1923.                repeat
  1924.                   while t = nil do
  1925.                      begin
  1926.                         if (dataline = nil) or (dataline^.next = nil) then
  1927.                            errormsg('Out of Data');
  1928.                         dataline := dataline^.next;
  1929.                         t := dataline^.txt;
  1930.                      end;
  1931.                   found := (t^.kind = tokdata);
  1932.                   t := t^.next;
  1933.                until found and not iseos
  1934.             else
  1935.                t := t^.next;
  1936.             if v^.stringvar then
  1937.                begin
  1938.                   if v^.sval^ <> nil then
  1939.                      dispose(v^.sval^);
  1940.                   v^.sval^ := strexpr;
  1941.                end
  1942.             else
  1943.                v^.val^ := realexpr;
  1944.             datatok := t;
  1945.             t := tok;
  1946.             if not iseos then
  1947.                require(tokcomma);
  1948.          until iseos;
  1949.       end;
  1950.  
  1951.  
  1952.    procedure cmddata;
  1953.       begin
  1954.          skiptoeos;
  1955.       end;
  1956.  
  1957.  
  1958.    procedure cmdrestore;
  1959.       begin
  1960.          if iseos then
  1961.             restoredata
  1962.          else
  1963.             begin
  1964.                dataline := mustfindline(intexpr);
  1965.                datatok := dataline^.txt;
  1966.             end;
  1967.       end;
  1968.  
  1969.  
  1970.    procedure cmdgotoxy;
  1971.       var
  1972.          i : integer;
  1973.       begin
  1974.          i := intexpr;
  1975.          require(tokcomma);
  1976.          gotoxy(i, intexpr);
  1977.       end;
  1978.  
  1979.  
  1980.    procedure cmdon;
  1981.       var
  1982.          i : integer;
  1983.          l : loopptr;
  1984.       begin
  1985.          i := intexpr;
  1986.          if (t <> nil) and (t^.kind = tokgosub) then
  1987.             begin
  1988.                new(l);
  1989.                l^.next := loopbase;
  1990.                loopbase := l;
  1991.                l^.kind := gosubloop;
  1992.                l^.homeline := stmtline;
  1993.                l^.hometok := t;
  1994.                t := t^.next;
  1995.             end
  1996.          else
  1997.             require(tokgoto);
  1998.          if i < 1 then
  1999.             skiptoeos
  2000.          else
  2001.             begin
  2002.                while (i > 1) and not iseos do
  2003.                   begin
  2004.                      require(toknum);
  2005.                      if not iseos then
  2006.                         require(tokcomma);
  2007.                      i := i - 1;
  2008.                   end;
  2009.                if not iseos then
  2010.                   cmdgoto;
  2011.             end;
  2012.       end;
  2013.  
  2014.  
  2015.    procedure cmddim;
  2016.       var
  2017.          i, j, k : integer;
  2018.          v : varptr;
  2019.          done : boolean;
  2020.       begin
  2021.          repeat
  2022.             if (t = nil) or (t^.kind <> tokvar) then snerr;
  2023.             v := t^.vp;
  2024.             t := t^.next;
  2025.             with v^ do
  2026.                begin
  2027.                   if numdims <> 0 then
  2028.                      errormsg('Array already dimensioned');
  2029.                   j := 1;
  2030.                   i := 0;
  2031.                   require(toklp);
  2032.                   repeat
  2033.                      k := intexpr + 1;
  2034.                      if k < 1 then badsubscr;
  2035.                      if i >= maxdims then badsubscr;
  2036.                      i := i + 1;
  2037.                      dims[i] := k;
  2038.                      j := j * k;
  2039.                      done := (t <> nil) and (t^.kind = tokrp);
  2040.                      if not done then
  2041.                         require(tokcomma);
  2042.                   until done;
  2043.                   t := t^.next;
  2044.                   numdims := i;
  2045.                   if stringvar then
  2046.                      begin
  2047.                         hpm_new(sarr, j*4);
  2048.                         for i := 0 to j-1 do
  2049.                            sarr^[i] := nil;
  2050.                      end
  2051.                   else
  2052.                      begin
  2053.                         hpm_new(arr, j*8);
  2054.                         for i := 0 to j-1 do
  2055.                            arr^[i] := 0;
  2056.                      end;
  2057.                end;
  2058.             if not iseos then
  2059.                require(tokcomma);
  2060.          until iseos;
  2061.       end;
  2062.  
  2063.  
  2064.    procedure cmdpoke;
  2065.       var
  2066.          trick :
  2067.             record
  2068.                case boolean of
  2069.                   true : (i : integer);
  2070.                   false : (c : ^char);
  2071.             end;
  2072.       begin
  2073.          $range off$
  2074.          trick.i := intexpr;
  2075.          require(tokcomma);
  2076.          trick.c^ := chr(intexpr);
  2077.          $if checking$ $range on$ $end$
  2078.       end;
  2079.  
  2080.  
  2081.    begin {exec}
  2082.       try
  2083.          repeat
  2084.             repeat
  2085.                gotoflag := false;
  2086.                elseflag := false;
  2087.                while (stmttok <> nil) and (stmttok^.kind = tokcolon) do
  2088.                   stmttok := stmttok^.next;
  2089.                t := stmttok;
  2090.                if t <> nil then
  2091.                   begin
  2092.                      t := t^.next;
  2093.                      case stmttok^.kind of
  2094.                         tokrem     : ;
  2095.                         toklist    : cmdlist;
  2096.                         tokrun     : cmdrun;
  2097.                         toknew     : cmdnew;
  2098.                         tokload    : cmdload(false, stringexpr);
  2099.                         tokmerge   : cmdload(true, stringexpr);
  2100.                         toksave    : cmdsave;
  2101.                         tokbye     : cmdbye;
  2102.                         tokdel     : cmddel;
  2103.                         tokrenum   : cmdrenum;
  2104.                         toklet     : cmdlet(false);
  2105.                         tokvar     : cmdlet(true);
  2106.                         tokprint   : cmdprint;
  2107.                         tokinput   : cmdinput;
  2108.                         tokgoto    : cmdgoto;
  2109.                         tokif      : cmdif;
  2110.                         tokelse    : cmdelse;
  2111.                         tokend     : cmdend;
  2112.                         tokstop    : escape(-20);
  2113.                         tokfor     : cmdfor;
  2114.                         toknext    : cmdnext;
  2115.                         tokwhile   : cmdwhile;
  2116.                         tokwend    : cmdwend;
  2117.                         tokgosub   : cmdgosub;
  2118.                         tokreturn  : cmdreturn;
  2119.                         tokread    : cmdread;
  2120.                         tokdata    : cmddata;
  2121.                         tokrestore : cmdrestore;
  2122.                         tokgotoxy  : cmdgotoxy;
  2123.                         tokon      : cmdon;
  2124.                         tokdim     : cmddim;
  2125.                         tokpoke    : cmdpoke;
  2126.                      otherwise
  2127.                         errormsg('Illegal command');
  2128.                      end;
  2129.                   end;
  2130.                if not elseflag and not iseos then
  2131.                   checkextra;
  2132.                stmttok := t;
  2133.             until t = nil;
  2134.             if stmtline <> nil then
  2135.                begin
  2136.                   if not gotoflag then
  2137.                      stmtline := stmtline^.next;
  2138.                   if stmtline <> nil then
  2139.                      stmttok := stmtline^.txt;
  2140.                end;
  2141.          until stmtline = nil;
  2142.       recover
  2143.          begin
  2144.             if escapecode = -20 then
  2145.                begin
  2146.                   write('Break');
  2147.                end
  2148.             else if escapecode = 42 then
  2149.                begin end
  2150.             else
  2151.                case escapecode of
  2152.                   -4 : write(#7'Integer overflow');
  2153.                   -5 : write(#7'Divide by zero');
  2154.                   -6 : write(#7'Real math overflow');
  2155.                   -7 : write(#7'Real math underflow');
  2156.                   -8, -19..-15 : write(#7'Value range error');
  2157.                   -10 :
  2158.                      begin
  2159.                         new(ioerrmsg);
  2160.                         misc_getioerrmsg(ioerrmsg^, ioresult);
  2161.                         write(#7, ioerrmsg^);
  2162.                         dispose(ioerrmsg);
  2163.                      end;
  2164.                   otherwise
  2165.                      begin
  2166.                         if excp_line <> -1 then
  2167.                            writeln(excp_line);
  2168.                         escape(escapecode);
  2169.                      end;
  2170.                end;
  2171.             if stmtline <> nil then
  2172.                write(' in ', stmtline^.num:1);
  2173.             writeln;
  2174.          end;
  2175.    end; {exec}
  2176.  
  2177.  
  2178.  
  2179.  
  2180.  
  2181. begin {main}
  2182.    new(inbuf);
  2183.    linebase := nil;
  2184.    varbase := nil;
  2185.    loopbase := nil;
  2186.    writeln('Chipmunk BASIC 1.0');
  2187.    writeln;
  2188.    exitflag := false;
  2189.    repeat
  2190.       try
  2191.          repeat
  2192.             write('>');
  2193.             readln(inbuf^);
  2194.             parseinput(buf);
  2195.             if curline = 0 then
  2196.                begin
  2197.                   stmtline := nil;
  2198.                   stmttok := buf;
  2199.                   if stmttok <> nil then
  2200.                      exec;
  2201.                   disposetokens(buf);
  2202.                end;
  2203.          until exitflag or eof(input);
  2204.       recover
  2205.          if escapecode <> -20 then
  2206.             misc_printerror(escapecode, ioresult)
  2207.          else
  2208.             writeln;
  2209.    until exitflag or eof(input);
  2210. end.
  2211.  
  2212.  
  2213.  
  2214.  
  2215.