[INHERIT('SYS$LIBRARY:STARLET')] { FAB-related definitions }

program LispKit(Input, Output, InFile, OutFile);

(*-----------------------------------------------------------------*)
(*                                                                 *)
(*   Reference model lazy interactive SECD machine, 3              *)
(*      -- version 3a                                    April 83  *)
(*      -- IMPLODE and EXPLODE instructions, version 3b    May 83  *)
(*                                                                 *)
(*   Modifications specific to VAX VMS Pascal gaj        April 83  *)
(*   Break long lines in file output gaj                August 83  *)
(*   I/O compatible with both version 1 & 2 compilers    April 84  *)
(*                                                                 *)
(*-----------------------------------------------------------------*)
(*                                                                 *)
(*    (c)  Copyright  P Henderson, G A Jones, S B Jones            *)
(*                    Oxford University Computing Laboratory       *)
(*                    Programming Research Group                   *)
(*                    8-11 Keble Road                              *)
(*                    OXFORD  OX1 3QD                              *)
(*                                                                 *)
(*-----------------------------------------------------------------*)
(*                                                                 *)
(*   Documentation:                                                *)
(*                                                                 *)
(*     P Henderson, G A Jones, S B Jones                           *)
(*         The LispKit Manual                                      *)
(*         Oxford University Computing Laboratory                  *)
(*         Programming Research Group technical monograph PRG-32   *)
(*         Oxford, August 1983                                     *)
(*                                                                 *)
(*     P Henderson                                                 *)
(*         Functional Programming: Application and Implementation. *)
(*         Prentice-Hall International, London, 1980               *)
(*                                                                 *)
(*-----------------------------------------------------------------*)

(*------------------ Machine dependent constants ------------------*)

label 99;

const TopCell = 40000;     (*    size of heap storage    *)
      FileRecordLimit = 255;
      OutFileWidth = 200;
      OutTermWidth = 80;

(*--------------- Machine dependent file management ---------------*)

var InOpen : boolean;
    InFile : text;
    NewInput, InFromTerminal, OutToTerminal : boolean;
    OutFile : text; 
    OutFileColumn : integer;
    OutTermColumn : integer;
    NullName : packed array[1..255] of char;

function IsTerminal(VAR f : text) : boolean;
  type phyle = [UNSAFE] text;
       pointer = ^FAB$TYPE;
  var p : pointer;
      d : [UNSAFE] DEV$TYPE;
  function PAS$FAB(VAR f : phyle) : pointer; EXTERN;
begin p := PAS$FAB(f);
      d := p^.FAB$L_DEV;
      IsTerminal := d.DEV$V_TRM
end {IsTerminal};

procedure OpenInFile;
var s : packed array[1..255] of char;
begin writeln(Output);
      write(Output, 'Take input from where? ');
      if eoln(Input) then s := NullName else read(Input, s);
      readln(Input);
      if s = NullName then
        open(File_Variable := InFile,
             File_Name := 'SYS$INPUT',
             History := Old)
      else
        open(File_Variable := InFile,
             File_Name := s,
             History := Old,
             Error := CONTINUE);
      InOpen := Status(InFile) <= 0;
      if InOpen then
          begin reset(InFile); InFromTerminal := IsTerminal(InFile) end
      else write(Output, 'Cannot read from that file')
end {OpenInFile};

procedure CloseInFile; begin close(InFile); InOpen := false end;

procedure ChangeOutFile;
var s : packed array[1..255] of char;
    ok : boolean;
begin close(OutFile);
      repeat writeln(Output);
             write(Output, 'Send output to where? ');
             if eoln(Input) then s := NullName else read(Input, s);
             readln(Input);
             if s = NullName then
               open(File_Variable := OutFile,
                    File_Name := 'SYS$OUTPUT',
                    History := New,
                    Record_Length := FileRecordLimit)
             else
               open(File_Variable := OutFile,
                    File_Name := s,
                    History := New,
                    Record_Length := FileRecordLimit,
                    Error := CONTINUE);
             ok := Status(OutFile) <= 0;
             if ok then rewrite(OutFile)
             else write(Output, 'Cannot write to that file')
      until ok;
      OutToTerminal := IsTerminal(OutFile);
      OutTermColumn := 0;
      OutFileColumn := 0
end {ChangeOutFile};

(*------------------- Character input and output ------------------*)

procedure GetChar(VAR ch : char);
const EM = 8;
begin while not InOpen do begin OpenInFile; NewInput := true end;
      if eof(InFile) then begin CloseInFile; ch := ' ' end
      else
        if eoln(InFile) then
              begin readln(InFile); NewInput := true; ch := ' ' end
      else
        begin if NewInput then
                begin if InFromTerminal then OutTermColumn := 0;
                      NewInput := false
                end;
              read(InFile, ch);
              if ch = chr(EM) then
                   begin readln(InFile); ChangeOutFile; ch := ' ' end
        end;
end {GetChar};

procedure PutChar(ch : char);
const CR = 13;
begin if ch = ' '
      then if OutToTerminal then
              begin if OutTermColumn >= OutTermWidth then ch := chr(CR) end
           else
              begin if OutFileColumn >= OutFileWidth then ch := chr(CR) end;
      if ch = chr(CR) then
         begin writeln(OutFile);
               if OutToTerminal then
                     OutTermColumn := 0
               else OutFileColumn := 0
         end
      else
         begin write(OutFile, ch);
               if OutToTerminal then
                    OutTermColumn := OutTermColumn + 1
               else OutFileColumn := OutFileColumn + 1
         end
end {PutChar};

(*------- Machine dependent initialisation and finalisation -------*)

procedure Initialise(Version, SubVersion : char);
var i : 1..255;
begin writeln(Output, 'VAX Pascal SECD machine ', Version, SubVersion);
      for i := 1 to 255 do NullName[i] := ' ';
      open(File_Variable := InFile,
           File_Name := 'LISPKIT$SECDBOOT',
           History := Old,
           Error := CONTINUE);
      InOpen := status(InFile) <= 0;
      if InOpen then
             begin reset(InFile); InFromTerminal := IsTerminal(InFile) end
      else writeln(Output, 'No file LispKit$SECDboot');
      NewInput := true;
      open(File_Variable := OutFile,
           File_Name := 'SYS$OUTPUT',
           History := New,
           Record_Length := FileRecordLimit);
      rewrite(OutFile);
      OutToTerminal := IsTerminal(OutFile);
      OutTermColumn := 0;
      OutFileColumn := 0
end {Initialise};

procedure Terminate;
begin writeln(OutFile); close(OutFile); goto 99 end {Terminate};

(*-----------------------------------------------------------------*)

procedure Machine; { omitted }

(*------------------- body of program LispKit ---------------------*)

begin Machine; 99: end {LispKit}.
