IMPLEMENTATION MODULE DiskIO ;


FROM FIO IMPORT File, OpenToRead, ReadChar, Close, IsNoError ;
FROM StrIO IMPORT ReadString, WriteString, WriteLn ;
FROM ASCII IMPORT nul, lf, cr ;
FROM StrLib IMPORT StrCopy, StrEqual ;


VAR
   f: File ;
   CurrentChar: CHAR ;
   NextChar   : CHAR ;
   Eof        : BOOLEAN ;
   FileName   : ARRAY [0..79] OF CHAR ;

(* %%%FORWARD%%%
PROCEDURE ReadSymbol (VAR a: ARRAY OF CHAR) ; FORWARD ;
PROCEDURE Delimiter() : BOOLEAN ; FORWARD ;
PROCEDURE AdvanceChar ; FORWARD ;
   %%%FORWARD%%% *)


PROCEDURE OpenSourceFile ;
VAR
   a: ARRAY [0..79] OF CHAR ;
BEGIN
   REPEAT
      WriteString('Source File: ') ;
      ReadString( a ) ;
      WriteLn ;
      f := OpenToRead(a)
   UNTIL IsNoError(f) ;
   StrCopy(a, FileName) ;
   Eof := FALSE ;
   AdvanceChar ;
   AdvanceChar ;
   GetNextSymbol ;
   GetNextSymbol
END OpenSourceFile ;


PROCEDURE OpenSource (a: ARRAY OF CHAR)  ;
BEGIN
   f := OpenToRead(a) ;
   StrCopy(a, FileName) ;
   Eof := FALSE ;
   AdvanceChar ;
   AdvanceChar ;
   GetNextSymbol ;
   GetNextSymbol
END OpenSource ;


PROCEDURE CloseSourceFile ;
BEGIN
   Close( f )
END CloseSourceFile ;


PROCEDURE GetNextSymbol ;
BEGIN
   StrCopy( CurrentSymbol, LastSymbol ) ;
   StrCopy( NextSymbol, CurrentSymbol ) ;
   ReadSymbol( NextSymbol )
END GetNextSymbol ;


PROCEDURE ReadSymbol (VAR a: ARRAY OF CHAR) ;
VAR
   i    : CARDINAL ;
   Level: CARDINAL ;
   ok   : BOOLEAN ;
BEGIN

   (* Get rid of all excess spaces *)

   REPEAT
      IF CurrentChar=' '
      THEN
         WHILE CurrentChar=' ' DO
            AdvanceChar
         END ;
         ok := FALSE
      ELSIF (CurrentChar='(') AND (NextChar='*')
      THEN
         Level := 0 ;
         REPEAT
            IF (CurrentChar='(') AND (NextChar='*')
            THEN
               INC(Level)
            ELSIF (CurrentChar='*') AND (NextChar=')')
            THEN
               DEC(Level)
            END ;
            AdvanceChar ;
            IF Eof AND (Level>0)
            THEN
               WriteString('End of file encountered before *) found') ; WriteLn ;
               WriteString('Filename: ') ; WriteString(FileName) ; WriteLn ;
               HALT
            END
         UNTIL Level=0 ;
         AdvanceChar ;
         AdvanceChar ;
         ok := FALSE
      ELSIF CurrentChar='{'
      THEN
         WHILE CurrentChar#'}' DO
            AdvanceChar
         END ;
         AdvanceChar ;
         ok := FALSE
      ELSE
         ok := TRUE
      END
   UNTIL ok ;
   i := 0 ;
   IF CurrentChar='"'
   THEN
      a[i] := CurrentChar ;
      INC( i ) ;
      REPEAT
         AdvanceChar ;
         a[i] := CurrentChar ;
         INC( i )
      UNTIL CurrentChar='"' ;
      AdvanceChar
   ELSIF CurrentChar="'"
   THEN
      a[i] := CurrentChar ;
      INC( i ) ;
      REPEAT
         AdvanceChar ;
         a[i] := CurrentChar ;
         INC( i )
      UNTIL CurrentChar="'" ;
      AdvanceChar
   ELSIF (CurrentChar='[') OR
         (CurrentChar=']') OR
         (CurrentChar='^') OR
         (CurrentChar='(') OR
         (CurrentChar=')') OR
         (CurrentChar='.') AND (NextChar#'.')
   THEN
      a[i] := CurrentChar ;
      INC( i ) ;
      AdvanceChar ;
   ELSIF Delimiter()
   THEN
      REPEAT
         a[i] := CurrentChar ;
         INC( i ) ;
         AdvanceChar
      UNTIL (NOT Delimiter()) OR (CurrentChar="'") OR (CurrentChar='"')
   ELSE
      REPEAT
         a[i] := CurrentChar ;
         AdvanceChar ;
         INC( i )
      UNTIL Delimiter() OR (i>HIGH(a)) OR (CurrentChar=' ')
   END ;
   IF i<=HIGH(a)
   THEN
      a[i] := nul
   END
END ReadSymbol ;


(* Delimiter returns true if and only if CurrentChar is a delimiter *)

PROCEDURE Delimiter() : BOOLEAN ;
BEGIN
   IF (CurrentChar='-') OR
      (CurrentChar='+') OR (CurrentChar='*') OR (CurrentChar='\') OR
      (CurrentChar='|') OR (CurrentChar='(') OR (CurrentChar=')') OR
      (CurrentChar='"') OR (CurrentChar="'") OR (CurrentChar='{')
   THEN
      RETURN( TRUE )
   ELSIF
      (CurrentChar='}') OR (CurrentChar='[') OR (CurrentChar=']') OR
      (CurrentChar='#') OR (CurrentChar='=') OR (CurrentChar='<')
   THEN
      RETURN( TRUE )
   ELSIF
      (CurrentChar='>') OR (CurrentChar='.') OR (CurrentChar=';') OR
      (CurrentChar=':') OR (CurrentChar='^') OR (CurrentChar=',')
   THEN
      RETURN( TRUE )
   ELSE
      RETURN( FALSE )
   END
END Delimiter ;


PROCEDURE AdvanceChar ;
BEGIN
   CurrentChar := NextChar ;
   NextChar := ReadChar(f) ;
   IF NOT IsNoError(f)
   THEN
      Eof := TRUE
   END ;
   IF (NextChar<' ')
   THEN
      NextChar := ' '
   END
END AdvanceChar ;


END DiskIO.