(****************************************************** * * Donated to the Pascal/Z Users Group by Ithaca * Intersystems, Dec 1980. ******************************************************) Program xref; {$i+,e+,l- } { This is a quick and dirty program to do Pascal cross reference listings } { without regard to Pascal scoping rules. It has a minimum of comments and} { was intended for internal use only } { This program may die terribly if your program is not of correct Pascal } { syntax. Each symbol which only occurs once is marked with an '*'. } const tab = 9; cr = 13; lf = 10; blanks = ' '; symlen = 8; tabsize = 750; listsize = 10; type symbol = array[ 1..symlen ] of char; xreflist = record nextlist: ^xreflist; xreflines: array[ 1..listsize ] of integer; end; $string255 = string 255; $string0 = string 0; byte = 0..255; var i, j, linepos, symcnt: integer; caps, good_ctrl, { set of acceptable control characters } stop, stoppnum: set of char; tab_index: integer; entry: ^xreflist; { save all of the symbols in alphabetical order } symbols: array[ 1..tabsize ] of symbol; { for each symbol there is a list of references, this table has a } { pointer to the start of the list } xreftable: array[ 1..tabsize ] of ^xreflist; { count the number of references for the corresponding symbol } xctr: array[ 1..tabsize ] of integer; { it is important to know the line number in order to xref } linectr: integer; firstchar: boolean; { is this the first character on this line } answer: char; { used in reading the Pascal program } already_read: boolean; one_ahead, curch: char; { the latest symbol extracted from the Pascal program } current_symbol: array[ 1..symlen ] of char; { input/output files } pasprog, xrefout: text; { for constructing file names } filnam: string 50; { do a binary search for the current identifier, if found return the index } { and set the function return value to TRUE. } { if not found set index to correct insertion point. } function bsearch( var index: integer ): boolean; var i,j,k: integer; done: boolean; begin i := 1; j := symcnt; done := false; repeat k := (j - i + 1) div 2 + i; if current_symbol < symbols[ k ] then j := k - 1 else if current_symbol > symbols[ k ] then i := k + 1 else done := true until done or (i > j ); index := k; if not done and (symbols[k] < current_symbol) then index := k + 1; bsearch := done end; { get the next character } { convert ugly control control characters to spaces and convert upper case } { to lower case } procedure nextch; begin if firstchar then linectr := linectr + 1; firstchar := eoln( pasprog ); if already_read then begin curch := one_ahead; already_read := false end else if not eof( pasprog ) then begin read( pasprog, curch ); { convert ugly control chars to spaces } if (curch < ' ') and not(curch in good_ctrl) then curch := ' '; { convert upper to lower case } if curch in caps then curch := chr( ord( curch ) + 32 ); end; end; { return the look-a-head character from the input stream } function lookahead: char; var temp: char; begin if already_read then lookahead := one_ahead else begin temp := curch; nextch; one_ahead := curch; lookahead := curch; already_read := true; curch := temp end; end; { find the next symbol skipping over quoted strings, comments, numbers and } { special symbols (i.e. <> ) } procedure parse; var i: byte; begin { skip characters until we get one that can start an identifier or } { we hit the end of the file } repeat nextch; if curch = '''' then begin repeat nextch until curch = '''' end else if ((curch='(') and (lookahead='*')) or (curch = '{') then repeat repeat nextch until (curch = '*') or (curch='}') until (lookahead = ')') or (curch='}'); until not (curch in stoppnum) or eof( pasprog ); i := 0; current_symbol := blanks; { read the identifier into current_symbol, ignoring characters which } { exceed the maximum symbol length } repeat i := i + 1; if i <= symlen then current_symbol[ i ] := curch; nextch; until curch in stop; end; { add a cross reference entry to the table } procedure add_xref( sym_index, ref_line: integer ); var ptrnum: integer; begin entry := xreftable[ sym_index ]; ptrnum := xctr[sym_index] mod listsize + 1; xctr[sym_index] := xctr[sym_index]+1; while (entry^.nextlist <> nil) do entry := entry^.nextlist; if ptrnum = 1 then begin new( entry^.nextlist ); entry := entry^.nextlist; entry^.nextlist := nil end; entry^.xreflines[ptrnum] := ref_line end; { add the current symbol to the symbol table at position 'index' } procedure add_symbol( index: integer ); var i: integer; begin symcnt := symcnt + 1; for i := symcnt downto index+1 do begin symbols[ i ] := symbols[ i-1 ]; xctr[ i ] := xctr[ i-1 ]; xreftable[ i ] := xreftable[ i-1 ]; end; new( entry ); xctr[index] := 1; xreftable[index] := entry; entry^.nextlist := nil; entry^.xreflines[1] := linectr; symbols[index] := current_symbol end; { add an initial entry to the symbol table....these entries are the } { Pascal/Z reserved words. } procedure init( res: symbol ); var i: integer; junk: boolean; begin current_symbol := res; junk := bsearch( i ); add_symbol( i ) end; function index( x, y: $string255 ): integer; external; procedure setlength( var x: $string0; y: integer ); external; { start of program } begin writeln( 'XREF -- version 1a' ); already_read := false; good_ctrl := [ chr( tab ), chr( cr ), chr( lf ) ]; stop := [ chr( tab ),' ',':',',','+','-','/','*','(',')','=','.','>', '<','{','}','[',']', '''', '^', ';' ]; stoppnum := stop + [ '0'..'9' ]; caps := [ 'A'..'Z' ]; repeat if eoln( 0 ) then write( 'File name -- ' ); readln( filnam ); linepos := index( filnam, '.' ); if linepos <> 0 then setlength( filnam, linepos-1 ); append( filnam, '.pas' ); reset( filnam, pasprog ); until not eof( pasprog ); for i := 1 to tabsize do symbols[ i ] := '} '; symcnt := 0; linectr := 0; firstchar := true; init( 'and ' ); init( 'array ' ); init( 'begin ' ); init( 'case ' ); init( 'const ' ); init( 'div ' ); init( 'do ' ); init( 'downto ' ); init( 'else ' ); init( 'end ' ); init( 'external' ); init( 'file ' ); init( 'for ' ); init( 'forward ' ); init( 'function' ); init( 'goto ' ); init( 'if ' ); init( 'in ' ); init( 'label ' ); init( 'mod ' ); init( 'nil ' ); init( 'not ' ); init( 'of ' ); init( 'or ' ); init( 'packed ' ); init( 'procedur' ); init( 'program ' ); init( 'record ' ); init( 'repeat ' ); init( 'set ' ); init( 'string ' ); init( 'then ' ); init( 'to ' ); init( 'type ' ); init( 'until ' ); init( 'var ' ); init( 'while ' ); init( 'with ' ); while not eof( pasprog ) do begin parse; if current_symbol <> blanks then begin if bsearch( tab_index ) then add_xref( tab_index, linectr ) else add_symbol( tab_index ) end; end; linepos := index( filnam, '.' ); setlength( filnam, linepos-1 ); append( filnam, '.xrf' ); rewrite( filnam, xrefout ); writeln( xrefout, 'Total identifiers = ', symcnt-38:1 ); for j := 1 to symcnt do if xreftable[ j ]^.xreflines[ 1 ] <> 0 then begin writeln( xrefout, ' ' ); write( xrefout, symbols[ j ], ' ' ); entry := xreftable[ j ]; for i := 1 to xctr[ j ] do begin write( xrefout, entry^.xreflines[(i-1) mod listsize + 1]:6 ); if (i mod 10 = 0) and (xctr[ j ] > i ) then begin writeln( xrefout ); write( xrefout, ' ' ) end; if i mod listsize = 0 then entry := entry^.nextlist; end; if xctr[ j ] = 1 then write( xrefout, '*' ); end; write( 'Include reserved words? ' ); readln( answer ); if answer in [ 'Y', 'y' ] then begin writeln( xrefout ); writeln( xrefout ); writeln( xrefout, 'Reserved words:' ); for j := 1 to symcnt do if xreftable[ j ]^.xreflines[ 1 ] = 0 then begin writeln( xrefout, ' ' ); write( xrefout, symbols[ j ], ' ' ); entry := xreftable[ j ]; for i := 2 to xctr[ j ] do begin write( xrefout, entry^.xreflines[(i-1) mod listsize + 1]:6 ); if (i mod 10 = 0) and (xctr[ j ] > i ) then begin writeln( xrefout ); write( xrefout, ' ' ) end; if i mod listsize = 0 then entry := entry^.nextlist; end; end; end; end. .