{$C-,M-,F-}{ PASCAL/Z COMPILER OPTIONS }
PROGRAM WADUZITDO;
{
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ PROGRAM TITLE:	What Does It Do?		+
+							+
+ WRITTEN BY:		Larry Kheriaty, Computer Center +
+			Western Washington Univ.	+
+			Bellingham, Wa. 98225		+
+			BYTE MAG, Sept 1978		+
+							+
+ SUMMARY:						+
+ A minimal PILOT interpreter.	A sample of what can be +
+ done with the high level language Pascal. Commands	+
+ will be found in the file WADUZIT.DOC.		+
+							+
+ Modification record:					+
+    1.1   -August 1979 Entered by Ray Penley		+
+	    program does not work as originally written.+
+    1.2   -added EndOfString marker (EOS)		+
+		  and EndOfFile marker (EOFS)		+
+	    added DEBUG FLAG; procedure PAD;		+
+	    rewrote PROCEDURE LIST			+
+	    program still not working.			+
+    1.3   -April 1, 1981 - finally got program to work!+
+	    rewrote LIST; some mods to EXECUTE; 	+
+	    added getc(); putc(); readchar(); advance;	+
+	    added KEYIN(); signon header & prompt.	+
+    1.4   -April 3, 1981 - Modified so that all lines	+
+	    are "linelength" characters long.  This	+
+	    allows a cleaner line insert and delete.	+
+	    added procedure debug;/deleted advance;	+
+							+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
}

LABEL	1;		{ Program termination on ctrl-e 	}

CONST
  prompt = '>';
  CTRLD  = 4;		{ control-D will display the whole	 }
			{ memory buffer.			 }
  CTRLE  = 5;		{ assign control-E as program terminator }
  lines  = 50;		{ total # of lines per program		 }
  linelength = 64 + 1;	{ # chars/line plus one for EOS marker	 }
  BUFSIZE =		{ total # of chars =			 }
     lines*linelength+1;{    linelength times (# of lines) + 1	 }

VAR
  tcount,		{ line counter }
  ppos, 		{ present position location }
  lpos	: INTEGER;	{ last position location    }

  BACKSPACE,		{ backspace character  }
  bell, 		{ terminal bell char   }
  EOS,			{ End of string marker }
  EOFS, 		{ End of file marker   }
  null, 		{ null character       }
  lastchar,		{ last character       }
  FLAG, 		{ match flag	       }
  pchar : CHAR; 	{ current character    }

  membuffer : ARRAY [1..BUFSIZE] OF CHAR;{ the working area in memory }

  listing,		{ Listing to console flag }
  xeof, 		{ End of file flag }
  xeoln : BOOLEAN;	{ End of line flag }



PROCEDURE KEYIN(VAR ch: char); EXTERNAL;
{ Direct keyboard input of a single character }


Procedure getc(VAR ch: char);
{ Read single character from the keyboard/ with echo }
begin 
  KEYIN(ch);Write(ch);
  If ORD(ch)=13 then ch := EOS;
  xeoln := ( ch=EOS );
end;


Procedure putc(ch: char);
{ Write out a single character to the output device }
begin
  if ( ch=EOS ) then
    writeln
  else
    write(ch);
end;


Procedure Restart;
begin
  ppos := 1;
  tcount := 0;
  writeln('Ready');
  putc(prompt);
end;


PROCEDURE INITIALIZE;
BEGIN
  BACKSPACE := CHR(8);
  bell := CHR(7);
  EOS := '|';		{ end of string character }
  EOFS := CHR(127);	{ end of file character   }
  null := CHR(0);
  listing := false;
  xeof := true; 	{ must be end of file since buffer is empty }
  xeoln := false;

  { initialize the entire input buffer into lines }
  ppos := 0;
  repeat
    ppos := ppos + 1;
    if ( ppos MOD linelength=0 ) then
       membuffer[ppos] := EOS	    { end of string }
    else
       membuffer[ppos] := null;
  until ( ppos=bufsize );
  membuffer[ppos] := EOFS;	    { end of file }
END;


Procedure Readchar(var ch: char);
{ Reads a single character from the input buffer }
begin
  ch := membuffer[ppos];
  ppos := ppos + 1;
  xeof := ( ch=EOFS );
  xeoln := ( ch=EOS );
end;


Procedure push(ch: CHAR);
begin
  membuffer[ppos] := ch;
  ppos := ppos +1;
end;


PROCEDURE LIST;
BEGIN
  Readchar(pchar);
  if ( listing ) then
    begin tcount := tcount + 1;
	  write(tcount:3,':  ');
    end;
  while not (xeof or xeoln) do
    begin if ( pchar<>null ) then putc(pchar);
	  Readchar(pchar);
    end;
  putc(EOS);
END;


PROCEDURE PAD;
{ Pads a line by filling with nulls }
BEGIN
  while ( ppos MOD linelength<>0 ) do push(null);
  push(EOS);
END;


PROCEDURE EXECUTE;
VAR	i: INTEGER;
	DONE : BOOLEAN;
BEGIN
  ppos := 1;		{ * execution always starts here * }
  DONE := FALSE;
  REPEAT
    pchar := membuffer[ppos] ;
    IF (pchar < '*') THEN pchar := '*';
    CASE pchar OF

	'*':	{ * program marker - jump destination * }
		ppos := ppos + 1;

	'Y','N':
		{ * YT:text  *	NT:text  *  YJ:n  *  NJ:n  * etc.  * }
		IF pchar=FLAG THEN
		  ppos := ppos+1
		ELSE
		  repeat
		    Readchar(pchar);
		  until ( xeof ) or ( xeoln );

	'A':	begin  { *    A:    * }
		  lpos := ppos;
		  getc(pchar);
		  lastchar := pchar;
		  putc(EOS);
		  ppos := ppos + 2
		end;

	'M':	BEGIN	{ *	M:x	     * }
		  IF ( lastchar=membuffer[ppos+2] ) then
		     FLAG := 'Y'
		  ELSE
		     FLAG := 'N';
		  ppos := ppos+3
		END;

	'J':	{ *   J:n    * }
		IF ( membuffer[ppos+2]='0' ) then
		  ppos := lpos
		ELSE
		  begin { CONVERT ASCII CHAR TO NUMBER }
		    i := ORD(membuffer[ppos+2])-48;
		    REPEAT
		      Readchar(pchar);
		      IF ( pchar='*' ) THEN i := i - 1
		    UNTIL ( i=0 ) OR ( xeof );
		  END;

	'T':	BEGIN	{ *   T:text	* }
		  ppos := ppos + 2;
		  LIST
		END;

	'S':	BEGIN	{ *   S:	 * }
		  DONE := TRUE;
		END

	ELSE:	LIST;

    END;(* case *)
  Until ( done ) or (membuffer[ppos]=EOFS);
END;


Procedure debug;
var	ch: char;
begin
  ppos := 1;	{ * start at first char in the memory buffer * }
  repeat
     repeat
	Readchar(ch);
	if ( ch=null ) then putc('.')
	else putc(ch);
     until (ch=eos) or (ch=eofs);
  until (ch=eofs);
  writeln;
  Restart;
end;


Procedure DoCommand(comchar: char);
begin
  putc(EOS);
  CASE comchar of

    '/':  begin listing := true;
		LIST;
		listing := false;
		putc(prompt);
	  end;

    '\':  Restart;

    '$':  begin EXECUTE;
		Restart;
	  end;

    '%':  begin PAD;
		Restart;
	  end;
  END{of CASE};
end;



BEGIN	(* MAIN PROGRAM *)
  WRITELN(' ':20, 'WHAT DOES IT DO?');
  WRITELN(' ':20, 'by Larry Kheriaty');
  WRITELN(' ':20, 'this version by Ray Penley');
  WRITELN;WRITELN;
  INITIALIZE;
  restart;
  getc(pchar);
  While true do { start infinite loop }
    BEGIN
      if ord(pchar)=CTRLE then {EXIT}
	 goto 1
      else if ord(pchar)=CTRLD then
	 Debug
      else IF ( pchar=BACKSPACE ) and ( ppos>1 ) then
	ppos := ppos - 1
      else
	begin if pchar IN ['/','\','$','%'] then
		DoCommand(pchar)
	      else
		begin IF ( pchar<>eos ) then
			push(pchar)	 { * store present char * }
		      else
			begin PAD;
			      putc(EOS);
			      putc(prompt);
			end;
		end;
	end;
      if ( ppos>=bufsize ) then
	 begin writeln(bell, '+++MEMORY FULL');
	       restart;
	 end;
      getc(pchar);
    END;
1:WRITELN;
END.
