File ID2ID.PS

Directory of image this file is from
This file as a plain text file

(**	  ID2ID - RENAME IDENTIFIERS IN A PASCAL PROGRAM.
*
*	  JAMES F. MINER    79/06/01, 79/09/30, 80/02/05, 80/02/10.
*	     SOCIAL SCIENCE RESEARCH FACILITIES CENTER.
*	  ANDY MICKEL	    79/06/28.
*	     UNIVERSITY COMPUTER CENTER
*	  UNIVERSITY OF MINNESOTA
*	  MINNEAPOLIS, MN 55455 USA
*
*	     (BASED ON AN EARLIER VERSION BY JOHN T. EASTON AND
*	      JAMES F. MINER, 76/11/29, AS MODIFIED BY ANDY MICKEL
*	      AND RICK L. MARCUS, 78/12/08)
*
*	  THE NAMES AND ORGANIZATIONS GIVEN HERE MUST NOT BE DELETED
*	  IN ANY USE OF THIS PROGRAM.
*
*	  SEE THE PTOOLS WRITEUP FOR EXTERNAL DOCUMENTATION.
*
*
**	  ID2ID - INTERNAL DOCUMENTATION.
*
*	     ID2ID READS A FILE OF IDPAIRS AND BUILDS AN AVL-BALANCED
*	  BINARY TREE OF IDENTIFIERS WHILE CHECKING FOR DUPLICATES.  IT
*	  THEN READS THE SOURCE PROGRAM AND EDITS IT TO A TARGET FILE BY
*	  SUBSTITUTING IDENTIFIERS FOUND IN THE TREE.  A FINAL CHECK IS
*	  MADE FOR NEW IDENTIFIERS WHICH WERE ALREADY SEEN IN THE
*	  SOURCE, AND A REPORT MAY BE GENERATED.
*)

PROGRAM ID2ID(SOURCE, TARGET, IDPAIRS, REPORT);

  LABEL
    13 (* FOR FATAL ERRORS *);

  CONST
    MAXLENGTH = 25;
       BLANKS = '			  ' (* MUST BE MAXLENGTH LONG *);
    ShiftBias = -32;  { ord(uppercase letter) - ord(lowercase letter) }

  TYPE
      CHARSET = SET OF CHAR;
     IDLENGTH = 1 .. MAXLENGTH;
       IDTYPE = RECORD
		    NAME: PACKED ARRAY [IDLENGTH] OF CHAR;
	       CaseShift: set of IdLength; { indices of uppercase letters }
		  LENGTH: IDLENGTH
		END;
      BALANCE = (HIGHERLEFT, EVEN, HIGHERRIGHT);
      NODEPTR = ^ NODE;
	 NODE = RECORD
			 ID: IDTYPE;
		       LEFT,
		      RIGHT: NODEPTR;
			BAL: BALANCE;
		    IDISNEW: BOOLEAN;
		CASE
		    IDISOLD: BOOLEAN OF
		  TRUE:
		    (NEWPTR: NODEPTR);
		  FALSE:
		    (SEENINSOURCE: BOOLEAN)
		END;

  VAR
       IDTABLE: NODEPTR (* SYMBOL TABLE *);

       IDPAIRS,
	SOURCE,
	TARGET,
	REPORT: TEXT;

       UpperCaseLetters,  Continuators,
       LETTERS,
	DIGITS,
	LETTERSANDDIGITS: CHARSET;


  PROCEDURE INITIALIZE;

  BEGIN
    REWRITE(REPORT);
    UpperCaseLetters :=
	       ['A','B','C','D','E','F','G','H','I','J','K','L','M',
		'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
    Letters := UpperCaseLetters +
	       ['a','b','c','d','e','f','g','h','i','j','k','l','m',
		'n','o','p','q','r','s','t','u','v','w','x','y','z'];
    DIGITS := ['0' .. '9'];
    LETTERSANDDIGITS := LETTERS + DIGITS;
    Continuators := LettersAndDigits + ['_']
  END (* INITIALIZE *);


  PROCEDURE READID(VAR INFILE: TEXT; VAR IDENT: IDTYPE);

    VAR
      CHCOUNT: 0 .. MAXLENGTH;

  BEGIN
    IDENT.NAME := BLANKS;   CHCOUNT := 0;  Ident.CaseShift := [];
    REPEAT
      CHCOUNT := CHCOUNT + 1;
      if InFile^ in UpperCaseLetters then
	begin
	  Ident.CaseShift := Ident.CaseShift + [ChCount];
	  Ident.Name[ChCount] := chr( ord(InFile^) - ShiftBias )
	end
      else IDENT.NAME[CHCOUNT] := INFILE^;
      get(InFile)
    UNTIL NOT (INFILE^ IN Continuators) OR (CHCOUNT = MAXLENGTH);
    IDENT.LENGTH := CHCOUNT
  END (* READID *);

  procedure WriteId(var F: Text;  var Identifier: IdType);
    var
      i:  IdLength;
  begin
    with Identifier do
      for i := 1 to Length do
	if i in CaseShift then
	  write(F, chr( ord(Name[i]) + ShiftBias ))
	else write(F, Name[i])
  end { WriteId };


  PROCEDURE READIDPAIRSANDCREATESYMBOLTABLE;

    TYPE
      IDKIND = (OLDKIND, NEWKIND);

    VAR
	OLDID,
	NEWID: IDTYPE;
	 LINK: NODEPTR (* REMEMBER NEWID POINTER *);
      LINENUM: INTEGER;
      INCRHGT: BOOLEAN;


    PROCEDURE ERROR;

    BEGIN
      WRITELN(REPORT, 'ON LINE NUMBER ': 29, LINENUM: 1,
	      ' OF THE "IDPAIRS" FILE.');
    END (* ERROR *);


    PROCEDURE ENTER(VAR IDENTIFIER: IDTYPE; KIND: IDKIND; VAR P: NODEPTR;
		    VAR INCREASEDHEIGHT: BOOLEAN);

  (* ENTER USES AN AVL-BALANCED TREE SEARCH ALGORITHM BY NIKLAUS WIRTH. *)
  (*	  (SEE SECTION 4.4 IN "ALGORITHMS + DATA STRUCTURES = PROGRAMS" *)
  (*	   PRENTICE HALL, 1976, PP. 215-222.)				*)

      VAR
	P1,
	P2: NODEPTR;

    BEGIN
      IF P = NIL THEN
	BEGIN (* ID NOT FOUND IN TREE; INSERT IT. *)
	  NEW(P);   INCREASEDHEIGHT := TRUE;
	  WITH P^ DO
	    BEGIN
	      ID := IDENTIFIER;
	      IDISNEW := KIND = NEWKIND;   IDISOLD := KIND = OLDKIND;
	      LEFT := NIL;   RIGHT := NIL;   BAL := EVEN;
	      IF IDISNEW THEN BEGIN LINK := P;	SEENINSOURCE := FALSE END
	      ELSE NEWPTR := LINK
	    END
	END
      ELSE
	IF IDENTIFIER.NAME < P^.ID.NAME THEN
	  BEGIN
	    ENTER(IDENTIFIER, KIND, P^.LEFT, INCREASEDHEIGHT);
	    IF INCREASEDHEIGHT THEN (* LEFT BRANCH HAS GROWN HIGHER *)
	      CASE P^.BAL OF
		HIGHERRIGHT:
		  BEGIN P^.BAL := EVEN;   INCREASEDHEIGHT := FALSE END;
		EVEN:
		  P^.BAL := HIGHERLEFT;
		HIGHERLEFT:
		  BEGIN (* REBALANCE *)
		    P1 := P^.LEFT;
		    IF P1^.BAL = HIGHERLEFT THEN
		      BEGIN (* SINGLE LL ROTATION *)
			P^.LEFT := P1^.RIGHT;	P1^.RIGHT := P;
			P^.BAL := EVEN;   P := P1
		      END
		    ELSE
		      BEGIN (* DOUBLE LR ROTATION *)
			P2 := P1^.RIGHT;   P1^.RIGHT := P2^.LEFT;
			P2^.LEFT := P1;   P^.LEFT := P2^.RIGHT;
			P2^.RIGHT := P;
			IF P2^.BAL = HIGHERLEFT THEN P^.BAL := HIGHERRIGHT
			ELSE P^.BAL := EVEN;
			IF P2^.BAL = HIGHERRIGHT THEN P1^.BAL := HIGHERLEFT
			ELSE P1^.BAL := EVEN;
			P := P2
		      END;
		    P^.BAL := EVEN;   INCREASEDHEIGHT := FALSE;
		  END;
	      END (* CASE *)
	  END
	ELSE
	  IF IDENTIFIER.NAME > P^.ID.NAME THEN
	    BEGIN
	      ENTER(IDENTIFIER, KIND, P^.RIGHT, INCREASEDHEIGHT);
	      IF INCREASEDHEIGHT THEN (* RIGHT BRANCH HAS GROWN HIGHER *)
		CASE P^.BAL OF
		  HIGHERLEFT:
		    BEGIN P^.BAL := EVEN;   INCREASEDHEIGHT := FALSE END;
		  EVEN:
		    P^.BAL := HIGHERRIGHT;
		  HIGHERRIGHT:
		    BEGIN (* REBALANCE *)
		      P1 := P^.RIGHT;
		      IF P1^.BAL = HIGHERRIGHT THEN
			BEGIN (* SINGLE RR ROTATION *)
			  P^.RIGHT := P1^.LEFT;   P1^.LEFT := P;
			  P^.BAL := EVEN;   P := P1
			END
		      ELSE
			BEGIN (* DOUBLE RL ROTATION *)
			  P2 := P1^.LEFT;   P1^.LEFT := P2^.RIGHT;
			  P2^.RIGHT := P1;   P^.RIGHT := P2^.LEFT;
			  P2^.LEFT := P;
			  IF P2^.BAL = HIGHERRIGHT THEN P^.BAL := HIGHERLEFT
			  ELSE P^.BAL := EVEN;
			  IF P2^.BAL = HIGHERLEFT THEN P1^.BAL := HIGHERRIGHT
			  ELSE P1^.BAL := EVEN;
			  P := P2
			END;
		      P^.BAL := EVEN;	INCREASEDHEIGHT := FALSE
		    END;
		END (* CASE *)
	    END
	  ELSE
	    BEGIN (* IDENTIFIER IS ALREADY IN TREE *)
	      INCREASEDHEIGHT := FALSE;
	      WITH P^ DO
		BEGIN
		  if Kind = OldKind then
		    begin
		      if IdIsOld then { duplicate old id's }
			BEGIN
			  WRITE(REPORT, '*** DUPLICATE OLDIDS ENCOUNTERED: ');
			  WriteId(Report, Identifier);
			  WriteLn(Report);
			  ERROR;  GOTO 13
			END
		      else IdIsOld := true;
		      NewPtr := Link
		    end
		  ELSE	{ Kind = NewKind }
		    begin
		      if IdIsNew then  { duplicate new id's }
			BEGIN
			  WRITE(REPORT, '--- WARNING:  ');
			  WriteId(Report, Identifier);
			  WriteLn(Report, ' HAS ALSO APPEARED AS ANOTHER NEWID');
			  Error
			end
		      else IdIsNew := true;
		      LINK := P
		    END
		END
	    END
    END (* ENTER *);


    PROCEDURE TRUNCATION(VAR IDENT: IDTYPE);

    BEGIN
      WRITE(REPORT, '--- WARNING:  TRUNCATION	FOR IDENTIFER, ');
      WriteId(Report, Ident);
      WriteLn(Report);
      WRITELN(REPORT, 'EXTRA CHARACTERS IGNORED.': 39);   ERROR;
      REPEAT GET(IDPAIRS) UNTIL NOT (IDPAIRS^ IN LETTERSANDDIGITS);
    END (* TRUNCATION *);


  BEGIN (* READIDPAIRSANDCREATESYMBOLTABLE *)
    IDTABLE := NIL;   RESET(IDPAIRS);	LINENUM := 1;	INCRHGT := FALSE;
    WHILE NOT EOF(IDPAIRS) DO
      BEGIN
	WHILE (IDPAIRS^ = ' ') AND NOT EOLN(IDPAIRS) DO GET(IDPAIRS);
	IF IDPAIRS^ IN LETTERS THEN
	  BEGIN
	    READID(IDPAIRS, OLDID);
	    IF IDPAIRS^ IN LETTERSANDDIGITS THEN TRUNCATION(OLDID);
	    WHILE (IDPAIRS^ IN [' ', ',']) AND NOT EOLN(IDPAIRS) DO GET(IDPAIRS);
	    IF IDPAIRS^ IN LETTERS THEN
	      BEGIN
		READID(IDPAIRS, NEWID);
		IF IDPAIRS^ IN LETTERSANDDIGITS THEN TRUNCATION(NEWID);
		ENTER(NEWID, NEWKIND, IDTABLE, INCRHGT);
		ENTER(OLDID, OLDKIND, IDTABLE, INCRHGT);
	      END
	    ELSE
	      if EOLn(IdPairs) then { map OldId to itself }
		begin
		  Enter(OldId, NewKind, IdTable, IncrHgt);
		  Enter(OldId, OldKind, IdTable, IncrHgt)
		end
	      else
		BEGIN WRITELN(REPORT, '--- WARNING:  MALFORMED IDPAIR');  ERROR END
	  END
	ELSE
	  BEGIN WRITELN(REPORT, '--- WARNING:  MALFORMED IDPAIR');   ERROR END;
	READLN(IDPAIRS);   LINENUM := LINENUM + 1
      END
  END (* READIDPAIRSANDCREATESYMBOLTABLE *);


  PROCEDURE EDITSOURCETOTARGET;

    LABEL
      1;	(* TO ESCAPE EOF INSIDE OF A COMMENT *)

    VAR
	    SOURCEID: IDTYPE;
	     DIGITSE,
      IMPORTANTCHARS: CHARSET;


    PROCEDURE SUBSTITUTE(VAR IDENTIFIER: IDTYPE; P: NODEPTR);


      PROCEDURE WRITESOURCEID;

      BEGIN
	WriteId(Target, SourceId);
	WHILE SOURCE^ IN LETTERSANDDIGITS DO
	  BEGIN WRITE(TARGET, SOURCE^);   GET(SOURCE) END
      END (* WRITESOURCEID *);


    BEGIN (* SUBSTITUTE *)
      IF P = NIL THEN (* IDENTIFIER NOT IN TREE, ECHO *) WRITESOURCEID
      ELSE
	IF IDENTIFIER.NAME < P^.ID.NAME THEN SUBSTITUTE(IDENTIFIER, P^.LEFT)
	ELSE
	  IF IDENTIFIER.NAME > P^.ID.NAME THEN SUBSTITUTE(IDENTIFIER, P^.RIGHT)
	  ELSE (* FOUND *)
	    WITH P^ DO
	      IF IDISOLD THEN
		BEGIN
		  WriteId(Target, NewPtr^.Id);
		  WHILE SOURCE^ IN LETTERSANDDIGITS DO GET(SOURCE)
		END
		  ELSE BEGIN SEENINSOURCE := TRUE;   WRITESOURCEID END
    END (* SUBSTITUTE *);


  BEGIN (* EDITSOURCETOTARGET *)
    RESET(SOURCE);   REWRITE(TARGET);
    IMPORTANTCHARS := LETTERSANDDIGITS + ['(', '{', ''''];
    DIGITSE := DIGITS + ['E','e'];
    WHILE NOT EOF(SOURCE) DO
      BEGIN
	WHILE NOT EOLN(SOURCE) DO
	  IF SOURCE^ IN IMPORTANTCHARS THEN
	    CASE SOURCE^ OF
	      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
	      'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
	      'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
	      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
	      'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
	      's', 't', 'u', 'v', 'w', 'x', 'y', 'z':
		BEGIN READID(SOURCE, SOURCEID);   SUBSTITUTE(SOURCEID, IDTABLE)
		END;
	      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		REPEAT WRITE(TARGET, SOURCE^);	 GET(SOURCE)
		UNTIL NOT (SOURCE^ IN DIGITSE);
	      '''':
		BEGIN
		  REPEAT WRITE(TARGET, SOURCE^);   GET(SOURCE)
		  UNTIL (SOURCE^ = '''') OR EOLN(SOURCE);
		  IF EOLN(SOURCE) THEN
		    WRITELN(REPORT, '--- WARNING:  UNCLOSED STRING FOUND ',
				    'IN SOURCE PROGRAM.')
		  ELSE BEGIN  WRITE(TARGET, SOURCE^);	GET(SOURCE)  END
		END;
	      '(':
		BEGIN
		  WRITE(TARGET, SOURCE^);   GET(SOURCE);
		  IF SOURCE^ = '*' THEN (* COMMENT *)
		    BEGIN  WRITE(TARGET, SOURCE^);  GET(SOURCE);
		      REPEAT
			WHILE SOURCE^ <> '*' DO
			  BEGIN
			    IF EOLN(SOURCE) THEN
			      BEGIN  WRITELN(TARGET);  READLN(SOURCE);
				IF EOF(SOURCE) THEN GOTO 1 (* EXIT SCAN *)
			      END
			    ELSE BEGIN WRITE(TARGET, SOURCE^); GET(SOURCE) END
			  END;
			WRITE(TARGET, SOURCE^);   GET(SOURCE)
		      UNTIL SOURCE^ = ')';
		      WRITE(TARGET, SOURCE^);	GET(SOURCE)
		    END
		END;
	      '{':   (* STDCOMMENT *)
		BEGIN
		  REPEAT
		    IF EOLN(SOURCE) THEN
		      BEGIN  WRITELN(TARGET);  READLN(SOURCE);
			IF EOF(SOURCE) THEN GOTO 1  (* EXIT SCAN *)
		      END
		    ELSE BEGIN WRITE(TARGET, SOURCE^); GET(SOURCE) END
		  UNTIL SOURCE^ = '}';
		  WRITE(TARGET, SOURCE^);   GET(SOURCE)
		END
	    END (* CASE *)
	  ELSE (* OTHER CHARACTERS *)
	    BEGIN  WRITE(TARGET, SOURCE^);   GET(SOURCE) END;
	READLN(SOURCE);   WRITELN(TARGET)
      END;
    1: (* COME FROM EOF INSIDE OF COMMENT *)
  END (* EDITSOURCETOTARGET *);


  PROCEDURE CHECKSEENINSOURCE(P: NODEPTR);

  BEGIN
    IF P <> NIL THEN
      BEGIN
	CHECKSEENINSOURCE(P^.LEFT);
	WITH P^ DO
	  IF IDISNEW AND NOT IDISOLD THEN
	    IF SEENINSOURCE THEN
	      BEGIN
		WRITE(REPORT, '--- WARNING:  ');
		WriteId(Report, Id);
		WriteLn(Report, ' WAS SPECIFIED AS A NEW IDENTIFIER ');
		WRITELN(REPORT, 'AND WAS ALSO SEEN IN THE SOURCE ': 46,
			'PROGRAM UNCHANGED.');
	      END;
	CHECKSEENINSOURCE(P^.RIGHT)
      END
  END (* CHECKSEENINSOURCE *);


BEGIN (* ID2ID *)
  INITIALIZE;
  READIDPAIRSANDCREATESYMBOLTABLE;
  EDITSOURCETOTARGET;
  CHECKSEENINSOURCE(IDTABLE);
13:
END (* ID2ID *).



Feel free to contact me, David Gesswein djg@pdp8online.com with any questions, comments on the web site, or if you have related equipment, documentation, software etc. you are willing to part with.  I am interested in anything PDP-8 related, computers, peripherals used with them, DEC or third party, or documentation. 

PDP-8 Home Page   PDP-8 Site Map   PDP-8 Site Search