home *** CD-ROM | disk | FTP | other *** search
- MODULE TrieCrossRef;
- (* M.Holzherr, April 88, MacMETH2.4.
- Analyseprogramm fuer syntaktisch korrekte MODULA-2 - Programme. Auf ein
- vom Benutzer zu bezeichnendes Ausgabefile werden alle Deklarationen eines
- Moduls und alle in Prozeduren verwendeten, dort aber nicht deklarierten
- Bezeichner aufgelistet. Voraussetzung fuer das Funktionieren dieses Ana-
- lyseprogramms ist die Existenz eines Textfiles mit allen MODULA-2 -
- Schluesselworten (* dieses wird als erstes vom Programm gelesen *) .
-
- IMPLEMENTATIONSSPEZIFISCHE BESONDERHEITEN : Die Prozeduren OpenInput
- und OpenOutput verlangen zur Laufzeit die Eingabe des entsprechenden
- Eingabe- bzw. Ausgabefilenamens. Schliesst man diesen Namen mit einem
- Punkt ab, so wird zum Beispiel die Extension MOD an den Filenamen ange-
- haengt, wenn der Aufruf "OpenInput( 'MOD' )" lautet
-
- Anpassung durch TOOLBOX:
- Wurde mit TopSpeed-M2 auf MS-DOS getestet, der "strengere" Compiler
- erforderte einige Korrekturen. *)
-
- FROM InOut IMPORT Write, Read, WriteLn, WriteString,
- (* proc *) OpenInput, CloseInput, OpenOutput, CloseOutput,
- (* Boolesche Variable *) Done ;
- FROM Storage IMPORT ALLOCATE, DEALLOCATE;
-
- CONST (* Achtung, die folgenden Konstantenwerte sind nicht willkuerlich
- gewaehlt. So bedeutet z.B. begin = 4 , dass das Wort BEGIN auf
- dem File mit den MODULA-Schluesselworten an 4. Stelle vorkommt. *)
- begin = 4; case = 10; end = 20;
- for = 25; if = 30; loop = 36;
- procedure = 48; while = 62; with = 63;
-
- TYPE TRIE = POINTER TO NODE; (* Zeiger auf Woerterbuchknoten *)
- NODE = RECORD
- Char : CHAR;
- syNo : INTEGER; (* SymbolNummer; syNo <> 0 <=> Wortende *)
- vertical, (* vertical = Zeiger auf "Nachkomme" *)
- horizontal : TRIE (* horizontal = Zeiger auf "Geschwister" *)
- END;
-
- VAR ch : CHAR; (* letzter vom File gelesener Buchstabe *)
- triesPos, noOfCharsThisLine : INTEGER;
- syCounter : INTEGER; (* Laufnummer der Symbole *)
- outputActif, mark : BOOLEAN;
-
- (* -1---- skipComment ueberspringt Kommentare (auch geschachtelte) ------ *)
- PROCEDURE skipComment;
- VAR c : CHAR;
- BEGIN
- c:= ch;
- REPEAT
- IF (c = '(') & (ch = '*') THEN skipComment END;
- c:= ch; Read(ch)
- UNTIL (c = '*') & (ch = ')')
- END skipComment;
-
- (* -2---- newLine beginnt eine neue, eingerueckte Zeile ----------------- *)
- PROCEDURE newLine;
- VAR i : INTEGER;
- BEGIN
- IF outputActif THEN
- WriteLn; noOfCharsThisLine:= 0;
- FOR i:= 0 TO triesPos - 1 DO
- Write(' '); Write(' '); INC( noOfCharsThisLine,2)
- END;
- END;
- END newLine;
-
- (* -3---- put schreibt A in den Eingabestrom, falls outputActif = TRUE --- *)
- PROCEDURE put( A : ARRAY OF CHAR );
- VAR i : INTEGER;
- BEGIN
- IF outputActif THEN
- IF INTEGER(HIGH(A)) + noOfCharsThisLine > 75 THEN newLine; END;
- FOR i:= 0 TO HIGH(A) DO
- Write(A[i]);
- INC( noOfCharsThisLine);
- END;
- END;
- END put;
-
- (* -4---- putInt schreibt die Integerzahl val durch Aufruf von put ------- *)
- PROCEDURE putInt( val : INTEGER );
- VAR a : ARRAY[0..0] OF CHAR;
- BEGIN
- IF val >= 10 THEN putInt(val DIV 10) END;
- a[0]:= CHR( val MOD 10 + INTEGER(ORD('0')) ); put(a)
- END putInt;
-
- (* -5- copy(t) zeigt auf eine 1:1 - Kopie des Woerterbuchs auf das t zeigt *)
- PROCEDURE copy( t : TRIE ) : TRIE;
- VAR q : TRIE;
- BEGIN
- IF t = NIL THEN RETURN NIL
- ELSE ALLOCATE(q, SIZE(NODE) );
- q^ := t^;
- q^.vertical:= copy( t^.vertical);
- q^.horizontal:= copy(t^.horizontal);
- RETURN q
- END
- END copy;
-
- (* -6- delete(t) gibt den Speicherplatz des Gebildes auf das t zeigt frei - *)
- PROCEDURE delete( VAR t : TRIE (* in/out *) );
- BEGIN
- IF t <> NIL THEN
- delete(t^.vertical);
- delete(t^.horizontal);
- DEALLOCATE( t, SIZE(NODE) );
- END
- END delete;
-
-
- (* 7- insert liest ein Wort buchstabenweise und fuegt es in das Woerterbuch
- ein, falls es nicht schon eingetragen ist. Beim Aufruf muss der erste
- Buchstabe des Wortes schon gelesen sein. ----- *)
- PROCEDURE insert( VAR p : TRIE (* in/out *); VAR sy : INTEGER (* out *) );
-
- (* -7-1-- make erzeugt neuen Knoten -- *)
- PROCEDURE make( VAR p : TRIE (* out *) );
- BEGIN
- ALLOCATE( p, SIZE( NODE) );
- WITH p^ DO Char:= ch; syNo:= 0; vertical:= NIL; horizontal:= NIL END;
- END make;
-
- (* -7-2-- readAndInsertNextChar liest und verarbeitet das naechste Zeichen *)
- PROCEDURE readAndInsertNextChar;
- VAR Ch : CHAR; a : ARRAY[0..0] OF CHAR;
- BEGIN
- a[0]:= ch; put(a);
- Read(ch); Ch:= CAP(ch);
- IF ( (Ch >= 'A') & (Ch <= 'Z') ) OR ( (ch >= '0') & (ch <= '9') ) THEN
- insert(p^.vertical, sy)
- ELSE IF (p^.syNo = 0) THEN
- IF mark THEN INC( syCounter ); p^.syNo:= syCounter
- ELSE p^.syNo:= -1
- END;
- END;
- sy:= p^.syNo;
- WHILE (ch = '^') OR (ch = '.')
- OR ((Ch >= 'A') & (Ch <= 'Z')) OR ((ch >= '0') & (ch <= '9')) DO
- Read(ch); Ch:= CAP(ch)
- END;
- END;
- END readAndInsertNextChar;
-
- VAR q : TRIE;
- BEGIN (* insert *)
- IF p = NIL THEN
- make(p); readAndInsertNextChar;
- ELSIF p^.Char > ch THEN
- make(q); q^.horizontal:= p; p:= q;
- readAndInsertNextChar;
- ELSIF p^.Char < ch THEN
- insert(p^.horizontal, sy)
- ELSE readAndInsertNextChar;
- END
- END insert;
-
- (* 8- print schreibt den interessanteren Teil des Woerterbuchs p alphabetisch
- geordnet auf das Ausgabemedium --------------------------------------- *)
- VAR S : ARRAY[0..100] OF CHAR; (* S[0...level] = aktueller Wortteil *)
- PROCEDURE print( p : TRIE; level : INTEGER );
- VAR i : INTEGER; a : ARRAY[0..0] OF CHAR;
- BEGIN
- IF p <> NIL THEN
- S[level]:= p^.Char;
- IF p^.syNo = -1 THEN
- IF noOfCharsThisLine > 65 THEN newLine END;
- FOR i:= 0 TO level DO a[0]:= S[i]; put(a) END;
- put(' ');
- END;
- print(p^.vertical, level + 1);
- print(p^.horizontal, level );
- END
- END print;
-
- (* hier folgen Konstanten und Variablen, die nur vom Hauptprogramm benoetigt
- werden *)
- CONST n = 20;
- VAR c : CHAR;
- a : ARRAY[0..0] OF CHAR;
- waitSemicolon : BOOLEAN; (* waitSemicolon = TRUE <=> naechstes Semicolon
- beendet eine Prozedur *)
- equalSignFound : BOOLEAN;
- keys : TRIE; (*zeigt auf Woerterbuch mit den MODULA-Schluesselwoertern*)
-
- Tries : ARRAY[0..n] OF TRIE;
- (* Tries[i] zeigt auf das Woerterbuch der Bezeichner, die zur
- aktuellen Prozedur der Verschachtelungstiefe i gehoert *)
- NoOfProcs : ARRAY[0..n] OF INTEGER; (* NoOfProcs[i] = Anzahl Prozeduren
- der Verschachtelungstiefe i *)
- noOfEndExpected, rBracketExpected, i : INTEGER;
- SY : INTEGER;
- BEGIN (* TrieCrossRef *)
- outputActif:= TRUE; mark:= TRUE;
- syCounter:= 0; noOfCharsThisLine:= 0; triesPos:= 0; NoOfProcs[triesPos]:= 0;
- keys:= NIL; FOR i:= 0 TO n DO Tries[i]:= NIL END;
- WriteString('Namen des Files mit den Modula-Schluesselwoertern eingeben :' );
- OpenInput('MOD');
- Read(ch);
- WHILE Done DO (* Done = FALSE bedeutet Fileende erreicht *)
- IF (ch >= 'A') & (ch <= 'Z') THEN insert(keys, SY); put(' ') END;
- IF ch = '(' THEN Read(ch); IF ch = '*' THEN skipComment END END;
- Read(ch)
- END;
- CloseInput; WriteLn;
- WriteLn; Tries[triesPos]:= copy(keys);
- noOfEndExpected:= 0; rBracketExpected:= 0; waitSemicolon:= FALSE;
- WriteLn;
- WriteString('Namen des zu analysierenden Programmfiles eingeben :');
- OpenInput('MOD');
- WriteLn;
- WriteString('-- Cross-Reference-Analyse wird gleich gestartet! -- ');
- WriteLn;
- WriteString('Namen des Files eingeben, auf das die Analyse auszugeben ist:');
- OpenOutput('MOD');
- WriteString('DEKLARATIONEN UND NICHT LOKALE BEZEICHNER ' );
- WriteLn; WriteLn;
- Read(ch);
- LOOP
- IF NOT Done THEN (* Fileende erreicht *) EXIT END;
- CASE ch OF
- '(' : Read(ch); IF ch = '*' THEN
- skipComment; Read(ch)
- ELSE put('('); INC(rBracketExpected);
- END;
- | ')' : put(')'); DEC(rBracketExpected); Read(ch)
- | '=' : put('= '); equalSignFound:= TRUE; Read(ch)
- | ':' : put(': '); equalSignFound:= TRUE; Read(ch)
- | ';' : put('; '); equalSignFound:= FALSE;
- IF waitSemicolon THEN
- outputActif:= TRUE; waitSemicolon:= FALSE; newLine;
- ELSIF (rBracketExpected = 0) THEN
- newLine;
- END; Read(ch)
- | "'", '"' : c:= ch; a[0]:= ch; put(a);
- REPEAT Read(ch); a[0]:= ch; put(a) UNTIL ch = c;
- Read(ch)
- | '0'..'9' : a[0]:= ch; put(a); Read(ch)
- | 'a'..'z',
- 'A'..'Z' : IF noOfCharsThisLine > 65 THEN newLine END;
- insert(Tries[triesPos],SY); put(' ');
- CASE SY OF case, for, if, loop, while, with :
- IF NOT mark THEN INC(noOfEndExpected) END;
- ELSE
- END;
- CASE SY OF
- begin : put(' ');
- FOR i:= 0 TO triesPos - 1 DO
- put('-'); putInt(NoOfProcs[i])
- END;
- put('- ');
- outputActif:= FALSE; mark:= FALSE;
- INC(noOfEndExpected);
- | end : IF NOT mark THEN
- DEC(noOfEndExpected);
- IF noOfEndExpected = 0 THEN
- outputActif:= TRUE;
- put(' GLOBAL DEKLARIERT -> ');
- print(Tries[triesPos], 0); put(' <-');
- newLine;
- DEC(triesPos);
- IF triesPos < 0 THEN (* Moduleende erreicht *)
- EXIT
- END;
- outputActif:= FALSE;
- waitSemicolon:= TRUE; mark:= TRUE
- END
- END
- | procedure
- : IF NOT equalSignFound THEN
- (* PROCEDURE leitet Prozedur ein, kein Prozedurtyp *)
- INC(NoOfProcs[triesPos]);
- FOR i:= 0 TO triesPos DO
- put('-'); putInt(NoOfProcs[i])
- END;
- put('- ');
- INC(triesPos); NoOfProcs[triesPos]:= 0;
- delete(Tries[triesPos]);
- Tries[triesPos]:= copy(keys)
- END
- ELSE
- END (* CASE *)
-
- ELSE IF ch <= ' ' THEN
- REPEAT Read(ch) UNTIL NOT Done OR (ch > ' ');
- IF NOT Done THEN EXIT END
- ELSE a[0]:= ch; put(a); put(' '); Read(ch)
- END
- END (* CASE *)
- END; (* LOOP *)
- CloseInput; CloseOutput;
- WriteString('fertig'); Read(ch);
- END TrieCrossRef.
-
-
-
-
-
-
-