Musterlösung zu Aufgabe 2 -- Phones.m2


MODULE Phones;
  IMPORT Arguments;
  FROM SysExit IMPORT Exit;
  FROM Strings IMPORT StrCmp;
  FROM StdIO IMPORT FILE, MODE, stderr, stdout,
                stdin, Fopen, Feof;
  FROM FtdIO IMPORT Done, FreadCard, FwriteCard, 
       FwriteString, FreadString, FwriteLn, FwriteChar;

(* -------- Data of a Person with its Operations ----------*)
  CONST 
     NameLength = 30;
     PhoneLength = 15;
  TYPE
     Name = ARRAY[0..NameLength] OF CHAR;     
     Phone = ARRAY [0..PhoneLength] OF CHAR;

     Date = RECORD
              day : CARDINAL[0..31];
              month: CARDINAL[1..12];
              year: CARDINAL[1900..2100];
            END;

     PersDat = RECORD
                 famName: Name;
                 firstName: Name;
                 birthDate: Date;
                 phone: Phone;
               END;

  PROCEDURE nameIsLess(x,y: PersDat): BOOLEAN;
  BEGIN
	IF StrCmp(x.famName,y.famName) < 0 THEN
		RETURN TRUE
	ELSE
		RETURN FALSE;
	END
  END nameIsLess;

  PROCEDURE isYounger(x,y: PersDat): BOOLEAN;
  BEGIN
	IF (x.birthDate.year <> y.birthDate.year) THEN
		RETURN (x.birthDate.year > y.birthDate.year)
	END;
	(* x.birthDate.year = y.birthDate.year *)
	IF (x.birthDate.month <> y.birthDate.month) THEN
		RETURN (x.birthDate.month > y.birthDate.month)
	END;
	(* same year and same month*)
	RETURN (x.birthDate.day > y.birthDate.day)
  END isYounger;
	
  PROCEDURE WriteRec(f: FILE; pers: PersDat);
        (*f open stream to write *)
  BEGIN
     WITH pers DO
        FwriteString(f,famName);
        FwriteChar(f,' ');
        FwriteString(f,firstName);
        FwriteChar(f,' ');
        FwriteCard(f,birthDate.day,0);
        FwriteChar(f,' ');
        FwriteCard(f,birthDate.month,0);
        FwriteChar(f,' ');
        FwriteCard(f,birthDate.year,0);
        FwriteChar(f,' ');
        FwriteString(f,phone);
        FwriteLn(f);
      END;
  END WriteRec;
     
  PROCEDURE ReadRec(f:FILE; VAR pers: PersDat):BOOLEAN;
        (*f open stream for read *)
        VAR d,m,y: CARDINAL;
  BEGIN
     IF Feof(f) 
     THEN
           RETURN FALSE
     END;
     (*wegen Typpruefung verweigert FreadCard das 
       Einlesen in einen Unterbereich - daher 
       der Umweg ueber die CARDINAl-Variablen
      *)
      WITH pers DO
        FreadString(f,famName);
        FreadString(f,firstName);
        FreadCard(f,d); birthDate.day:=d;
        FreadCard(f,m); birthDate.month:=m;
        FreadCard(f,y); birthDate.year:=y;
        FreadString(f,phone);
      END;
      IF Done 
      THEN
            RETURN TRUE
      ELSE
            RETURN FALSE
      END;
  END ReadRec;
  
(* ---------------- Table of Person Data ---------------*)
  CONST
     NumberOfPers = 50;
  TYPE
     Range = [ 1.. NumberOfPers];
     PersList = ARRAY Range OF PersDat;
     IndexList = ARRAY Range OF Range;
  VAR 
     persList: PersList;
     nameList, ageList: IndexList;

(* -------------- Procedure sort ---------------------*)

  TYPE CmpPersDat = PROCEDURE(PersDat, PersDat):BOOLEAN;

  PROCEDURE Sort(	
		a: PersList;
		number: CARDINAL;
		cmp:CmpPersDat;
		VAR res: IndexList);
  
    VAR 
	minInd,i,j,tmp: CARDINAL;

  BEGIN
	FOR i := 1 TO number DO
	  res[i] := i;
   	END;

	FOR i:=1 TO number-1 DO
	  minInd := i;
	  FOR j:=i+1 TO number DO
	    IF cmp(a[res[j]],a[res[minInd]]) THEN
	      minInd := j;
	    END;
	  END;
	  tmp := res[i];
	  res[i] := res[minInd];
	  res[minInd] := tmp;
	END;
  END Sort;

(* ------------------------ main ------------------------*)
  VAR 
     fromFile: FILE;
     itsFile: BOOLEAN;
     inFile: Name;
     i, number: CARDINAL;

BEGIN
   Arguments.InitArgs(" [ inputfile ]");
   IF  Arguments.GetArg(inFile) 
   THEN 
      (*read from File*)
      itsFile := TRUE;
   ELSE
      (* read from stdin *)
      itsFile := FALSE;
   END;
   Arguments.AllArgs;

   IF itsFile THEN
     IF NOT Fopen(fromFile, inFile, read, TRUE) THEN
        FwriteString(stderr, "Fehler beim Oeffnen!");
        FwriteLn(stderr);
        Exit(1);
     END
   ELSE
      fromFile := stdin;
   END;

   (*Initialization - Separator is whiteSpace - 
    * no test !!!
    *)
    i:= 1;
    WHILE (i <= NumberOfPers) AND 
		ReadRec(fromFile, persList[i]) 
    DO
       INC(i);
    END;
    IF i<=NumberOfPers 
       (*loop terminated with ReadRec = False*)
    THEN
       number := i-1;
    ELSE
       number := i;
    END;
    
    FwriteString(stdout, "Orginal List: ");
    FwriteLn(stdout);
    FOR i := 1 TO number DO
	  WriteRec(stdout,persList[i]);
    END;
    
    Sort(persList, number, nameIsLess, nameList);
    FwriteString(stdout, "List Sorted by Name: ");
    FwriteLn(stdout);
    FOR i := 1 TO number DO
	  WriteRec(stdout,persList[nameList[i]]);
    END;
    
    Sort(persList, number, isYounger, ageList);
    FwriteString(stdout, "List Sorted by Age: ");
    FwriteLn(stdout);
    FOR i := 1 TO number DO
	  WriteRec(stdout,persList[ageList[i]]);
    END;
END Phones.

Musterlösung zu Aufgabe 2 || Übungen || Vorlesung || SS 97 || SAI

Franz Schweiggert, 12.05.1997