{ Cross-reference generator for Pascal/Z programs. Cross references lower case identifiers, ignores comments enclosed in braces and quoted strings. } { Author: Peter Grogono } {$M- inhibit multiply/divide check } {$R- inhibit range/bound check } {$S- inhibit stack overflow check } {$U- inhibit range/bound check for parameters } program xref; const {$ICONSTS.PAS } namelen = 8; { Significant length of identifier } filenamelen = 14; { For i/o file names } extin = '.PPP'; { Default input file extension } extout = '.XRT'; { Default output extension } maxwidth = 80; { Maximum width of output line } minspace = 100; { Abandon if < minspace bytes free} type {$ITYPES.PAS } nametype = string namelen; fntype = string filenamelen; itemptr = ^ itemrecord; entryptr = ^ entryrecord; itemrecord = record line : integer; next : itemptr end; { itemrecord } entryrecord = record name : nametype; items : itemptr; left, right : entryptr end; { entryrecord } var infilename, outfilename : fntype; infile, outfile : text; roots : array ['a'..'z'] of entryptr; name : nametype; line, oldline, symcount, entcount : integer; ch : char; maxent, entlen : byte; spaceleft : boolean; {$IPROCS.PAS } {$IGETFILES.PAS } { Read one character from the input file; check for end of file; count lines } procedure getchar; begin if eof(infile) then ch := blank else if eoln(infile) then begin readln(infile,ch); line := line + 1 end else read(infile,ch) end; { getchar } { Read an identifier from the input file; ignore names that start with an upper case letter, comments, quoted strings, and other characters. } procedure getname; var done : boolean; begin done := false; repeat if ch in ['a'..'z'] then begin setlength(name,0); oldline := line; while ch in ['a'..'z','A'..'Z','0'..'9','_'] do begin if length(name) < namelen then append(name,ch); getchar end; { while } done := true end else if ch = '{' then begin repeat getchar until (ch = '}') or eof(infile); getchar end else if ch = '''' then begin repeat getchar until (ch = '''') or eof(infile); getchar end else getchar until done or eof(infile) end; { getname } { Store a name in one of the binary trees. The tree is chosen according to the first letter of the name. The tree is searched with a REPEAT loop rather than by recursion for speed. } procedure storename; var entry : entryptr; item : itemptr; entered : boolean; { Make an entry in the symbol table. } procedure makentry (var entry : entryptr); var tempentry : entryptr; tempitem : itemptr; begin new(tempitem); tempitem^.line := oldline; tempitem^.next := nil; new(tempentry); tempentry^.name := name; tempentry^.items := tempitem; tempentry^.left := nil; tempentry^.right := nil; entry := tempentry; symcount := symcount + 1; entered := true end; { makentry } begin { storename } entry := roots[name[1]]; entered := false; repeat if name < entry^.name then if entry^.left = nil then makentry(entry^.left) else entry := entry^.left else if name > entry^.name then if entry^.right = nil then makentry(entry^.right) else entry := entry^.right else { name matched } begin if entry^.items^.line <> line then begin new(item); item^.line := oldline; item^.next := entry^.items; entry^.items := item end; entered := true end until entered; entcount := entcount + 1 end; { storename } { Print a tree given its root. The list of line numbers associated with an identifier is LIFO and must be reversed before printing. } procedure print (entry : entryptr); var forwards, backwards, temp : itemptr; entcount : byte; begin if entry <> nil then begin print(entry^.left); if length(entry^.name) > 0 then begin write(outfile,entry^.name,blank:namelen+2-length(entry^.name)); forwards := nil; backwards := entry^.items; while backwards <> nil do { reverse list } begin temp := backwards; backwards := temp^.next; temp^.next := forwards; forwards := temp end; { while } entcount := 0; while forwards <> nil do begin if entcount >= maxent then begin writeln(outfile); write(outfile,blank:namelen+2); entcount := 0 end; write(outfile,forwards^.line:entlen); entcount := entcount + 1; forwards := forwards^.next end; { while } writeln(outfile) end; print(entry^.right) end end; { print } { Main program } begin { Open files } getfilenames(extin,extout); writeln('Reading from ',infilename); reset(infilename,infile); if eof(infile) then writeln(infilename,' is empty.') else begin writeln('Writing to ',outfilename); reset(infilename,infile); rewrite(outfilename,outfile); { Initialize 26 binary trees. Storename requires dummy entries. } for ch := 'a' to 'z' do begin new(roots[ch]); setlength(roots[ch]^.name,0); roots[ch]^.items := nil; roots[ch]^.left := nil; roots[ch]^.right := nil end; { for } { Initialize counters and space flag } symcount := 0; entcount := 0; spaceleft := true; { Initialize input procedures } line := 1; getchar; getname; { Scan the program } while spaceleft and not eof(infile) do begin if (0 < space) and (space < minspace) then begin writeln('Memory exhausted at line ',line:1); spaceleft := false end; storename; getname end; { while } { Define output layout } entlen := 3; if line > 99 then entlen := 4; if line > 999 then entlen := 5; maxent := (maxwidth - namelen - 2) div entlen; { Print the tree } for ch := 'a' to 'z' do print(roots[ch]); { Display report } writeln(line-1:1,' lines read, ',symcount:1,' symbols stored, ', entcount:1,' entries recorded.'); if space > 0 then writeln('Space left: ',space:1,' bytes.') end end. { xref } .