DataMuseum.dk

Presents historical artifacts from the history of:

DANOSI

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DANOSI

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦9531d7eeb⟧ TextFile

    Length: 30009 (0x7539)
    Types: TextFile
    Names: »PASCROSS.PAS«

Derivation

└─⟦e2123b2a1⟧ Bits:30010498 DVBS1.SW2103.src.1.8-1 Pascal TOOLS JTAS 1989-04-26 LEIF NIELSEN E.d.
    └─⟦this⟧ »PASCROSS.PAS« 

TextFile

      {[A=20,I=2,L=4,E=3,W=1-100] PASCFORM direktiv }\r
      {$R-,S+,I+,B+,N- }\r
      {$M 16000, 0, 655000 }  {Take all of mem. to heap }\r
 \r
  PROGRAM PasCrossRef;\r
 \r
      { This program will generate a program listing and/or cross     }\r
      { reference map of any Turbo Pascal program, i.e. a map that    }\r
      { lists all identifiers used within the program as well as the  }\r
      { line numbers of all lines that contain references to the      }\r
      { identifiers. Optionally, include files may be incorporated    }\r
      { in the source listing.                                        }\r
 \r
      { On processing the input file, all identifiers are extracted   }\r
      { and compared with the reserved words of Turbo Pascal. If an   }\r
      { identifier is not a reserved word, it is entered into a       }\r
      { binary tree. Each entry in the binary tree contains a pointer }\r
      { to the identifier, and a left node and a right node pointer   }\r
      { to subsequent entries (or NIL if no entries follow). Further- }\r
      { more, an entry contains a pointer to the first record in a    }\r
      { line number reference chain, and a pointer to the last record }\r
      { in that chain. When an identifier is entered into the tree    }\r
      { for the first time, the program allocates both a new identi-  }\r
      { fier record and a line number reference record. Subsequent    }\r
      { references to that identifier will then expand the line num-  }\r
      { ber reference chain, provided that the line number is not the }\r
      { same as that of the last reference.                           }\r
 \r
      { When all lines have been processed, the program traverses the }\r
      { binary tree, printing all identifiers along with the numbers  }\r
      { of the lines within which they are referenced.                }\r
      {-----------------------------------------------------------------------------\r
      Date.  Init.  Vers.  Explanation.\r
 \r
      1988-01-01 OKT  1.0  Expanded original and asjusted to Turbo Pascal 3.0\r
      1988-03-03 OKT  1.1  Changed to Turbo Pascal 4.0, and improved parameters.\r
      -----------------------------------------------------------------------------}\r
 \r
  USES\r
    Crt,\r
    Dos,\r
    dosutil,\r
    param,\r
    help;\r
 \r
 \r
  CONST\r
 \r
    Version = ('1.1');\r
 \r
      { Constants controlling default settings }\r
 \r
    CompressedPageWidth = 128;\r
    NormalPageWidth = 80;\r
    CompressedSpacing = 12;\r
    NormalSpacing = 6;\r
    PageWidth = CompressedPageWidth;\r
    Spacing = CompressedSpacing;\r
    PageLength = 60;\r
 \r
      { Various constants }\r
 \r
    MaxDots = 50;		{ Max number of dots per line on CRT }\r
    MaxReservedWords = 53;\r
    ReservedWordLng = 14;\r
    NoOfVersions = 4;\r
    MaxDevices = 3;\r
    FormFeed = ^L;	{ Form-feed character }\r
    VerticalTabLength = 2;     { Number of lines to skip at top of page }\r
    File_buff_size = 512;\r
 \r
  TYPE\r
    EnterExit = (en, ex);\r
    PrinterControl = ARRAY[EnterExit] OF STRING[32];\r
    NumberForm = (None, Binary, ASCII);\r
    DeviceControlType = ARRAY[1..MaxDevices] OF RECORD\r
                                                   Name : STRING[12];\r
                                                   Numeric : NumberForm;\r
                                                   PrinterControlCode,\r
                                                   LeftMarginCode,\r
                                                   CompressCode: PrinterControl;\r
                                                END;\r
    ResWordType = RECORD\r
                     NoOfReservedWords : integer;\r
                     ReservedWords : ARRAY[1..MaxReservedWords] OF\r
                     STRING[ReservedWordLng];\r
                  END;\r
 \r
  CONST\r
 \r
      { Escape sequences used to control the printer }\r
    DC : DeviceControlType = (\r
                               (Name : 'EPSON'; Numeric : Binary;\r
                               PrinterControlCode : (^['@'^['R'#0,^['@');\r
                               LeftMarginCode : (^['l','');\r
                               CompressCode : (^O,'')),\r
                               (Name : 'HPLASER'; Numeric : ASCII;\r
                               PrinterControlCode : (^['E',^['E');\r
                               LeftMarginCode : (^['&a','L');\r
                               CompressCode : (^['&k2S','')),\r
                               (Name : 'NUL'; Numeric : None;\r
                               PrinterControlCode : ('','');\r
                               LeftMarginCode : ('','');\r
                               CompressCode : ('','')));\r
\r
\r
      { Table of reserved words }\r
\r
\r
ReservedWordTable : array[1..NoOfVersions] of ResWordType =(\r
  (NoOfReservedWords: 44; ReservedWords: (\r
{   Poly Pascal values:   }\r
    'LABEL','ELSE','CASE','AT','AND','ARRAY','BEGIN','DIV','CODE','CONST',\r
    'DO','DOWNTO','FOR','EXTERNAL','END','EXOR','FILE','GOTO','FORWARD',\r
    'FUNCTION','IF','IN','REPEAT','OTHERWISE','NOT','MOD','NIL','OF','OR',\r
    'PROGRAM','PACKED','PROCEDURE','RECORD','TO','SHR','SET','SHL','STRING',\r
    'THEN','VAR','TYPE','UNTIL','WHILE','WITH','','','','','','','','','')),\r
  (NoOfReservedWords: 53; ReservedWords: (\r
{   Real Time Pascal values:   }\r
    'LOCK','END','CHANNEL','BEGIN','ARRAY','AND','AS','CASE','BEGINBODY',\r
    'DO','CONTINUELOOP','CONST','DIV','ELSE','DOWNTO','FORWARD','EXPORT',\r
    'EXIT','ENDLOOP','EXITLOOP','FOR','EXTERNAL','IF','GOTO','FUNCTION',\r
    'LABEL','IN','SET','OTHERWISE','NOT','LOOP','LOCKMES','MOD','OR','OF',\r
    'PROCEDURE','POOL','PACKED','PREFIX','RECORD','PROCESS','REPEAT',\r
    'UNTIL','TO','THEN','SHIFT','TYPESIZE','TYPE','WHILE','VARSIZE',\r
    'VAR','XOR','WITH')),\r
 (NoOfReservedWords : 44; ReservedWords: (\r
{   Turbo Pascal version 3 values:  }\r
    'MOD','END','CONST','ARRAY','AND','ABSOLUTE','CASE','BEGIN','DOWNTO','DO',\r
    'DIV','ELSE','GOTO','FORWARD','FILE','EXTERNAL','FUNCTION','FOR','IN','IF',\r
    'INLINE','LABEL','SHL','PACKED','OVERLAY','NOT','NIL','OR','OF','RECORD',\r
    'PROGRAM','PROCEDURE','SET','REPEAT','UNTIL','THEN','STRING','SHR','TO',\r
    'TYPE','WITH','WHILE','VAR','XOR','','','','','','','','','')),\r
  (NoOfReservedWords: 48; ReservedWords: (\r
{   Turbo Pascal version 4 values:  }\r
    'LABEL','EXTERNAL','CONST','ARRAY','AND','ABSOLUTE','CASE','BEGIN',\r
    'DOWNTO','DO','DIV','END','ELSE','IF','FORWARD','FOR','FILE','GOTO',\r
    'FUNCTION','INLINE','IN','IMPLEMENTATION','INTERRUPT','INTERFACE',\r
    'SHL','PACKED','NOT','NIL','MOD','OR','OF','RECORD','PROGRAM',\r
    'PROCEDURE','SET','REPEAT','UNIT','THEN','STRING','SHR','TYPE',\r
    'TO','VAR','USES','UNTIL','WITH','WHILE','XOR','','','','','')));\r
\r
  TYPE\r
 \r
      { Identifier types }\r
 \r
    IdentPtr = ^Ident;\r
    Ident = STRING[32];\r
 \r
      { Line record types. Each line record contains the number of a  }\r
      { line, within which a given identifier is referenced, and a    }\r
      { pointer to the next line record.                              }\r
 \r
    LineRecPtr = ^LineRec;\r
    LineRec = RECORD\r
                 Number: INTEGER;\r
                 Next: LineRecPtr;\r
              END;\r
 \r
      { Identifier record types. Each identifier record contains a    }\r
      { pointer to the identifier string, a pointer to the first and  }\r
      { the last line record in the reference chain, and a left node  }\r
      { and a right node pointer to subsequent entries in the binary  }\r
      { tree.                                                         }\r
 \r
    IdentRecPtr = ^IdentRec;\r
    IdentRec = RECORD\r
                  Id: IdentPtr;\r
                  Reserved: BOOLEAN;\r
                  FirstLine,LastLine: LineRecPtr;\r
                  Left,Right: IdentRecPtr;\r
               END;\r
 \r
      { Source line type. The maximum length of a source line is 127  }\r
      { characters.                                                   }\r
\r
    SourceLine = STRING[127];\r
 \r
  VAR\r
 \r
      { Option varables }\r
    PrintCompressed,		{ True if compressed print }\r
    PrintIncludeFile,		{ True if include files are also printed }\r
    PrintListing,			{ True if source listing requested }\r
    PrintLineNumbers,		{ True if linenumbers is to be printed }\r
    PrintCrossRef : BOOLEAN;	{ True if a cross reference is printed }\r
    PrintPageLength,		{ Number of lines to print on page }\r
    PrintPageWidth,		{ Width of printed page }\r
    PrintSpacing : INTEGER;	{ No of blanks in front of line }\r
 \r
      { Global variables.						}\r
 \r
    LineNumber,		{ Current line number }\r
    NoOfIdents,		{ Number of identifiers processed }\r
    LinePos,		{ Position within current line }\r
    CurRow,              { Current line on printed page }\r
    PageNo,              { Current page number }\r
    DeviceNo,\r
    PascalVersion,\r
    LineLength: INTEGER;	{ Length of current line }\r
    Ch: CHAR;		{ Current character }\r
    IncludeActive,\r
    InOpen,			{ True if input file open }\r
    OutOpen,			{ True if output file open }\r
    Error: BOOLEAN;		{ Error flag }\r
    Line: SourceLine;	{ Current source line }\r
    IdTree: IdentRecPtr;	{ Root of cross reference tree }\r
    MainFile: TEXT{[4096]};	{ Input file }\r
      {! 15. Use the n^ew standard procedure SetTextBuf to set Text buffer size.}\r
    IncludeFile : TEXT{[4096]};\r
      {! 16. Use the new s^tandard procedure SetTextBuf to set Text buffer size.}\r
    OutFile: TEXT;	{ Output file }\r
    I_buff, IC_buff, O_buff: ARRAY[1..File_buff_size] OF byte;\r
    IncludeFileName,\r
    MainFileName: STRING; { Name of main program file }\r
    MainHeadLine,\r
    HeadLine : SourceLine;\r
    SR : SearchRec;\r
    Date : DateTime;\r
    CurrentDate : STRING;\r
    Dummy : word;  { to be used as dummy parameter }\r
 \r
      { UserFreeMem returns the number of bytes available on the heap.    }\r
      { The result type is real to allow for values outside the inte- }\r
      { ger range.                                                    }\r
 \r
 \r
 \r
  CONST\r
    MaxParam  = 2;\r
    MaxOption = 10;\r
 \r
    ParamList : ARRAY[1..MaxParam] OF ParamRec =\r
     ((Kind:KnownFile;Defined:FALSE ;KeyWord:'M';NumVal:0;TextVal:'.PAS'),\r
      (Kind:FileType; Defined:FALSE ;KeyWord:'O';NumVal:0;TextVal:'PRN'));\r
 \r
    OptionList : ARRAY[1..MaxOption] OF ParamRec =\r
     ((Kind:Numeric;  Defined:FALSE ;KeyWord:'PAGE'    ;NumVal:PageLength;TextVal:''),\r
      (Kind:Numeric;  Defined:FALSE ;KeyWord:'SPACING' ;NumVal:Spacing;TextVal:''),\r
      (Kind:Numeric;  Defined:FALSE ;KeyWord:'WIDTH'   ;NumVal:PageWidth;TextVal:''),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'COMPRESS';NumVal:0;TextVal:'ON'),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'INCLUDE' ;NumVal:0;TextVal:'OFF'),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'NUMBERS' ;NumVal:0;TextVal:'ON'),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'LIST'    ;NumVal:0;TextVal:'ON'),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'XREF'    ;NumVal:0;TextVal:'ON'),\r
      (Kind:Numeric;  Defined:FALSE ;KeyWord:'VERSION' ;NumVal:4;TextVal:''),\r
      (Kind:TextType; Defined:false; KeyWord:'DEVICE'  ;NumVal:0;TextVal:'EPSON'));\r
 \r
    Search1 = '{$I'; Search2 = '{$i'; Search3 = '(*$I'; Search4 = '(*$i';\r
 \r
    PROCEDURE ProgError(Msg : STRING);\r
    BEGIN\r
      WriteLn(Msg);\r
      Halt;\r
    END; { ProgError }\r
 \r
    FUNCTION IncludeIn(VAR CurStr: SourceLine): BOOLEAN;\r
    VAR\r
      ChkChar : CHAR;\r
      Column  : INTEGER;\r
    BEGIN\r
      ChkChar := '-';\r
      Column := Pos(Search1,CurStr);\r
      IF Column <> 0 THEN\r
        ChkChar := CurStr[Column+3]\r
      ELSE\r
        BEGIN\r
          Column := Pos(Search2,CurStr);\r
          IF Column <> 0 THEN\r
            ChkChar := CurStr[Column+4]\r
          ELSE\r
            BEGIN\r
              Column := Pos(Search3,CurStr);\r
              IF Column <> 0 THEN\r
                ChkChar := CurStr[Column+3]\r
              ELSE\r
                BEGIN\r
                  Column := Pos(Search4,CurStr);\r
                  IF Column <> 0 THEN\r
                    ChkChar := CurStr[Column+4];\r
                END;\r
            END;\r
        END;\r
      IncludeIn := ChkChar IN [' ','0'..'9','A'..'Z','a'..'z','!','@','#','$',\r
        '%','^','&','(',')','_'];\r
    END { IncludeIn };\r
 \r
 \r
    FUNCTION Parse(IncStr: SourceLine): STRING;\r
 \r
    CONST\r
      PathLength = 63;\r
    VAR\r
      NameStart,\r
      NameEnd  : INTEGER;\r
    BEGIN\r
      NameStart := Pos('$I',IncStr);\r
      IF NameStart = 0 THEN NameStart := Pos('$i',IncStr);\r
      NameStart := NameStart + 2;\r
      WHILE IncStr[NameStart] = ' ' DO NameStart := Succ(NameStart);\r
      NameEnd := NameStart;\r
      WHILE (NOT (IncStr[NameEnd] IN [' ','}','*']))\r
        AND ((NameEnd - NameStart) <= PathLength)\r
        DO NameEnd := Succ(NameEnd);\r
      NameEnd := Pred(NameEnd);\r
      IF Pos('.',Copy(IncStr,NameStart,(NameEnd-NameStart+1))) = 0 THEN\r
        Parse := Copy(IncStr,NameStart,(NameEnd-NameStart+1))+'.PAS'\r
      ELSE\r
        Parse := Copy(IncStr,NameStart,(NameEnd-NameStart+1));\r
    END {Parse};\r
 \r
 \r
    PROCEDURE NewPage(Message : STRING);\r
 \r
    VAR\r
      i: INTEGER;\r
      s : STRING;\r
    BEGIN\r
      IF PageNo > 0 THEN\r
        BEGIN\r
          FOR i := 1 TO VerticalTabLength DO WriteLn(OutFile);\r
          Str(PageNo:0,s);\r
          s := 'PAGE '+s;\r
          i := PrintPageWidth - Length(s);\r
          WriteLn(OutFile,'':i,s);\r
          Write(OutFile,FormFeed);\r
        END;\r
      IF Message <> '' THEN\r
        BEGIN\r
          s := 'Printed: '+CurrentDate;\r
          i := PrintPageWidth - Length(Message) - Length(s);\r
          WriteLn(OutFile,Message,'':i,s);\r
          FOR i := 1 TO VerticalTabLength DO WriteLn(OutFile);\r
        END;\r
      PageNo := Succ(PageNo);\r
      CurRow := 1;\r
    END {vertical tab};\r
 \r
 \r
    PROCEDURE ProcessLine(LineNo: INTEGER; PrintStr: SourceLine);\r
 \r
    VAR\r
      PrintCh  : CHAR;\r
      TabVal,\r
      CurChPos,\r
      LinePos  : INTEGER;\r
    BEGIN\r
      CurRow := Succ(CurRow);\r
      IF CurRow > PrintPageLength THEN NewPage(HeadLine);\r
      LinePos := 1;\r
      IF PrintLineNumbers THEN\r
        BEGIN\r
          IF LineNo = 0 THEN Write(OutFile,'---- ')\r
          ELSE Write(OutFile,LineNo:4,' ');\r
          LinePos := LinePos + 5;\r
        END;\r
      TabVal := 8;\r
      FOR CurChPos := 1 TO Length(PrintStr) DO\r
        BEGIN\r
          IF PrintStr[CurChPos] <> ^I THEN\r
            BEGIN\r
              LinePos := Succ(LinePos);\r
              IF LinePos > PrintPageWidth THEN\r
                BEGIN\r
                  WriteLn(OutFile);\r
                  CurRow := Succ(CurRow);\r
                  IF CurRow > PrintPageLength THEN NewPage(HeadLine);\r
                  Write(OutFile,'':PrintSpacing);\r
                  LinePos := PrintSpacing + 1;\r
                  IF PrintLineNumbers THEN\r
                    BEGIN\r
                      Write(OutFile,'':5);\r
                      LinePos := LinePos + 5;\r
                    END;\r
                  TabVal := 8;\r
                END;\r
              Write(OutFile,PrintStr[CurChPos]);\r
              TabVal := Pred(TabVal);\r
              IF TabVal = 0 THEN TabVal := 8;\r
            END\r
          ELSE\r
            BEGIN\r
              LinePos := LinePos + TabVal;\r
              IF LinePos > PrintPageWidth THEN\r
                BEGIN\r
                  WriteLn(OutFile);\r
                  CurRow := Succ(CurRow);\r
                  IF CurRow > PrintPageLength THEN NewPage(HeadLine);\r
                  LinePos := 1;\r
                  IF PrintLineNumbers THEN\r
                    BEGIN\r
                      Write(OutFile,'':5);\r
                      LinePos := LinePos + 5;\r
                    END;\r
                  TabVal := 8;\r
                END\r
              ELSE\r
                BEGIN\r
                  Write(OutFile,'':TabVal);\r
                  TabVal := 8;\r
                END;\r
            END;\r
        END;\r
      WriteLn(OutFile);\r
    END {Process line};\r
 \r
      { NEXTCH reads the next character from the input file into CH.  }\r
      { If a source listing was requested, NEXTCH lists input lines   }\r
      { to the output file as they are read. Otherwise, a dot is      }\r
      { printed on the console for each line read. A ^Z character is  }\r
      { returned on reaching the end of the input file.               }\r
 \r
 \r
    PROCEDURE NextCh;\r
 \r
    VAR\r
      p,t: INTEGER;\r
      TmpStr : STRING;\r
    BEGIN\r
      IF (LinePos<=LineLength) THEN\r
        BEGIN\r
          Ch:=Line[LinePos]; LinePos:=LinePos+1;\r
          Ch:=UpCase(Ch);\r
        END\r
      ELSE\r
        BEGIN\r
          IF IncludeActive THEN\r
            BEGIN\r
              IF NOT Eof(IncludeFile) THEN\r
                BEGIN\r
                  ReadLn(IncludeFile,Line); LineNumber := LineNumber + 1;\r
                  IF PrintListing THEN ProcessLine( LineNumber, Line )\r
                  ELSE\r
                    BEGIN\r
                      Write('.');\r
                      IF LineNumber MOD MaxDots=0 THEN WriteLn;\r
                    END;\r
                  LineLength:=Length(Line); LinePos:=1; Ch:=' ';\r
                END\r
              ELSE\r
                BEGIN\r
                  IF PrintListing THEN\r
                    BEGIN\r
                      ProcessLine(0,' ');\r
                      ProcessLine(0,'End of include file: '+IncludeFileName);\r
                      ProcessLine(0,' ');\r
                    END;\r
                  IncludeActive := FALSE;\r
                  Close(IncludeFile);\r
                  Ch := ' ';\r
                  HeadLine := MainHeadLine;\r
                END;\r
            END\r
          ELSE\r
            BEGIN\r
              IF PrintIncludeFile THEN\r
                BEGIN\r
                  IF IncludeIn(Line) THEN\r
                    BEGIN\r
                      IncludeFileName := UpperStr(Parse(Line));\r
                      IF NOT FileExist(IncludeFileName) THEN\r
                        BEGIN\r
                          Ch := ' '; Line := '';\r
                          ProcessLine(0,'ERROR -- Include file not found: '\r
                          +IncludeFileName);\r
                        END\r
                      ELSE\r
                        BEGIN\r
                          Assign(IncludeFile,IncludeFileName);\r
                          SetTextBuf(IncludeFile, IC_buff);\r
                          Reset(IncludeFile);\r
                          IF PrintListing THEN\r
                            BEGIN\r
                              ProcessLine(0,' ');\r
                              ProcessLine(0,'Start of include file: '+IncludeFileName);\r
                              ProcessLine(0,' ');\r
                            END;\r
                          IncludeActive := TRUE;\r
                          FindFirst(IncludeFileName,0,SR);\r
                          UnpackTime(SR.Time,Date);\r
                          HeadLine := 'Include file: '+IncludeFileName;\r
                          IF DosError <> 0 THEN\r
                            HeadLine := HeadLine+' ('+DateTimeText(Date)+')';\r
                          Ch := ' ';\r
                        END;\r
                    END;\r
                END;\r
              IF (NOT Eof(MainFile)) AND (NOT IncludeActive) THEN\r
                BEGIN\r
                  ReadLn(MainFile,Line); LineNumber:=LineNumber+1;\r
                  IF PrintListing THEN ProcessLine( LineNumber, Line )\r
                  ELSE\r
                    BEGIN\r
                      Write('.');\r
                      IF LineNumber MOD MaxDots=0 THEN WriteLn;\r
                    END;\r
                  LineLength:=Length(Line); LinePos:=1; Ch:=' ';\r
                END\r
              ELSE\r
                IF Eof(MainFile) THEN Ch:=^Z;\r
            END;\r
        END;\r
    END;\r
 \r
      { ENTERID enters NEWID into the cross reference binary tree.    }\r
      { Note that an identifier record is allocated only if the iden- }\r
      { tifier is not already within the tree. Also note the use of   }\r
      { the getmem procedure to allocate only the required number   }\r
      { of bytes for the identifier instead of the maximum Length.    }\r
 \r
 \r
    PROCEDURE EnterId(NewId: Ident; ResWord: BOOLEAN);\r
 \r
    VAR\r
      x: LineRecPtr;\r
 \r
      PROCEDURE Enter(VAR Root: IdentRecPtr);\r
      BEGIN\r
        IF Root=NIL THEN\r
          BEGIN\r
            New(Root);\r
            WITH Root^ DO\r
              BEGIN\r
                GetMem(Id,Length(NewId)+1); Id^:=NewId;\r
                Reserved:=ResWord;\r
                IF NOT Reserved THEN\r
                  BEGIN\r
                    New(FirstLine);\r
                    FirstLine^.Number:=LineNumber; FirstLine^.Next:=NIL;\r
                    LastLine:=FirstLine;\r
                    NoOfIdents:=NoOfIdents+1;\r
                  END;\r
                Left:=NIL; Right:=NIL;\r
              END;\r
          END ELSE\r
          IF NewId<Root^.Id^ THEN Enter(Root^.Left) ELSE\r
            IF NewId>Root^.Id^ THEN Enter(Root^.Right) ELSE\r
              WITH Root^ DO\r
                IF NOT Reserved THEN\r
                  IF LineNumber<>LastLine^.Number THEN\r
                    BEGIN\r
                      New(x); x^.Number:=LineNumber; x^.Next:=NIL;\r
                      LastLine^.Next:=x;\r
                      LastLine:=x;\r
                    END;\r
      END;\r
 \r
    BEGIN {EnterId}\r
      Enter(IdTree);\r
    END;\r
 \r
      { INITIALIZE is used to initialize input and output files and   }\r
      { all global variables.                                         }\r
 \r
 \r
    PROCEDURE Initialize;\r
 \r
    VAR\r
      i: INTEGER;\r
      InName,OutName: STRING[64];\r
      ListYN: STRING[1];\r
      St : STRING;\r
    BEGIN\r
      Error:=FALSE;\r
      TextColor(LightGray);\r
      WriteLn('Turbo Pascal Cross Reference, Version ', version );\r
      WriteLn('Copyright (C) Ole Krog Thomsen, 1987, 1988');\r
      WriteLn;\r
 \r
      IF ( ParamCount = 0 ) OR\r
        ( ParamCount >= 1) AND ( ParamStr(1 ) = '?') THEN\r
        BEGIN\r
          ShowHelp;\r
          Halt;\r
        END;\r
      St := ProgFileName;\r
      Delete(St, Pos('.',St), 255);\r
      WHILE pos('\',St) > 0 DO delete(St, 1, Pos('\',St));\r
      GetOptions(StripBlanks(EnvStrVal(St)), OptionList, MaxOption);\r
      GetParams(ParamList, MaxParam, OptionList, MaxOption);\r
      InOpen:=FALSE; OutOpen:=FALSE; IncludeActive := FALSE;\r
      DeviceNo := 1;\r
      WITH OptionList[10] DO\r
        IF Defined THEN\r
          BEGIN\r
            i := 1;\r
            WHILE (i <= MaxDevices) AND\r
              (UpperStr(TextVal) <> DC[i].Name) DO i := i + 1;\r
            IF UpperStr(TextVal) = DC[i].Name THEN DeviceNo := i\r
            ELSE ProgError('Unknown device: '+TextVal);\r
          END;\r
      PrintLineNumbers := OptionList[6].TextVal = 'ON';\r
      PrintCompressed := OptionList[4].TextVal = 'ON';\r
      PrintIncludeFile := OptionList[5].TextVal = 'ON';\r
      PrintListing := OptionList[7].TextVal = 'ON';\r
      PrintCrossRef := OptionList[8].TextVal = 'ON';\r
      PrintPageLength := OptionList[1].NumVal;\r
      PrintSpacing := OptionList[2].NumVal;\r
      PrintPageWidth := OptionList[3].NumVal;\r
      PascalVersion := OptionList[9].NumVal;\r
      IF (PascalVersion < 1) OR (PascalVersion > NoOfVersions) THEN\r
        ProgError('Unknown Pascal version: ');\r
      CurRow := PrintPageLength; PageNo := 0;\r
      InName := ParamList[1].TextVal;\r
      IF (NOT PrintCompressed) AND (NOT OptionList[3].Defined) THEN\r
        BEGIN\r
          PrintPageWidth := NormalPageWidth;\r
          PrintSpacing := NormalSpacing;\r
        END;\r
      IF PrintSpacing > 0 THEN PrintPageWidth := PrintPageWidth - PrintSpacing;\r
      IF FileExist(InName) THEN\r
        BEGIN\r
          Assign(MainFile, InName);\r
          SetTextBuf(MainFile, I_buff);\r
          Reset(MainFile);\r
        END\r
      ELSE\r
        BEGIN\r
          WriteLn('Input File Error');\r
          Error:=true; Halt;\r
        END;\r
      InOpen:=TRUE;\r
      OutName := ParamList[2].TextVal;\r
      Assign(OutFile, OutName);\r
      SetTextBuf(OutFile, O_buff);\r
        {$I-}\r
      Rewrite(OutFile);\r
        {$I+}\r
      IF IOResult <> 0 THEN\r
        BEGIN\r
          WriteLn('Output File Error');\r
          Error:=true; Halt;\r
        END;\r
      OutOpen:=TRUE;\r
      FindFirst(InName,0,SR);\r
      MainFileName := SR.Name;\r
      UnpackTime(SR.Time, Date);\r
      HeadLine := 'Main file: '+MainFileName+' ('+DateTimeText(Date)+')';\r
      MainHeadLine := HeadLine;\r
      GetSysDate(Date);\r
      CurrentDate := DateTimeText(Date);\r
      IdTree:=NIL;\r
      WITH ReservedWordTable[PascalVersion] DO\r
        FOR i:=1 TO NoOfReservedWords DO EnterId(ReservedWords[i],TRUE);\r
      WITH DC[DeviceNo] DO\r
        IF PrintListing OR PrintCrossRef THEN\r
          BEGIN\r
            Write(OutFile,PrinterControlCode[en]);\r
            IF PrintCompressed THEN Write(OutFile,CompressCode[en],CompressCode[ex]);\r
            IF PrintSpacing > 0 THEN\r
              CASE Numeric OF\r
                None: { do nothing };\r
                Binary:\r
                  Write(OutFile,LeftMarginCode[en],Char(PrintSpacing),LeftMarginCode[ex]);\r
                ASCII:\r
                  Write(OutFile,LeftMarginCode[en],PrintSpacing:0,LeftMarginCode[ex])\r
              END;\r
          END;\r
      LineNumber:=0; NoOfIdents:=0;\r
      LinePos:=1; LineLength:=0; NextCh;\r
    END;\r
 \r
      { PROCESSFILE processes the input file, creating a cross refe-  }\r
      { rence binary tree.                                            }\r
 \r
 \r
    PROCEDURE ProcessFile;\r
 \r
    VAR\r
      IFree: REAL;\r
 \r
        { GETSYMBOL reads the next symbol from the input file. If the   }\r
        { symbol is an identifier, it is processed using PROCESSIDENT   }\r
        { below.                                                        }\r
 \r
      PROCEDURE GetSymbol;\r
      CONST\r
        AlphaNums: SET OF '0'..'_' = ['0'..'9','A'..'Z','_'];\r
        HexDigits: SET OF '0'..'F' = ['0'..'9','A'..'F'];\r
 \r
          { PROCESSIDENT reads an identifier and enters it into the cross }\r
          { reference tree.                                               }\r
 \r
        PROCEDURE ProcessIdent;\r
        VAR\r
          NewId: Ident;\r
        BEGIN\r
          NewId:='';\r
          REPEAT\r
            NewId:=NewId+Ch; NextCh;\r
          UNTIL NOT(Ch IN AlphaNums);\r
          EnterId(NewId,FALSE);\r
        END;\r
 \r
      BEGIN {GetSymbol}\r
        CASE Ch OF\r
          'A'..'Z','_': ProcessIdent;\r
          '''':\r
            REPEAT\r
              REPEAT NextCh UNTIL (Ch='''') OR (Ch=^Z);\r
              NextCh;\r
            UNTIL Ch<>'''';\r
          '$':\r
            REPEAT NextCh UNTIL NOT(Ch IN HexDigits);\r
          '{':\r
            BEGIN\r
              REPEAT NextCh UNTIL (Ch='}') OR (Ch=^Z);\r
              NextCh;\r
            END;\r
          '(':\r
            BEGIN\r
              NextCh;\r
              IF Ch='*' THEN\r
                BEGIN\r
                  NextCh;\r
                  REPEAT\r
                    WHILE (Ch<>'*') AND (Ch<>^Z) DO NextCh;\r
                    NextCh;\r
                  UNTIL (Ch=')') OR (Ch=^Z);\r
                  NextCh;\r
                END;\r
            END;\r
        ELSE\r
          NextCh;\r
      END;\r
    END;\r
 \r
  BEGIN {ProcessFile}\r
    IFree:=MaxAvail;\r
    WHILE (Ch<>^Z) AND (MaxAvail>100.0) DO GetSymbol;\r
    IF NOT PrintListing THEN\r
      BEGIN\r
        IF (LineNumber MOD MaxDots<>0) THEN WriteLn;\r
        WriteLn;\r
      END;\r
    IF (MaxAvail<=100.0) THEN\r
      BEGIN\r
        WriteLn('Symbol Table Overflow');\r
        Error:=TRUE;\r
      END ELSE\r
      BEGIN\r
        WriteLn(LineNumber,' lines read from input file.');\r
        WriteLn(NoOfIdents,' identifiers processed.');\r
        WriteLn(IFree-MaxAvail:0:0,' bytes used, ',MaxAvail:0,' free.');\r
        IF PrintListing THEN\r
          BEGIN\r
            WHILE CurRow < PrintPageLength DO\r
              BEGIN\r
                WriteLn(OutFile);\r
                CurRow := Succ(CurRow);\r
              END;\r
          END;\r
      END;\r
  END;\r
 \r
    { PRINTXREF outputs the cross reference map }\r
 \r
 \r
  PROCEDURE PrintXRef;\r
 \r
  VAR\r
    n, lf: INTEGER;\r
    x: LineRecPtr;\r
 \r
      { TRAVERSE traverses the binary tree from "left" to "right",    }\r
      { printing all identifiers and the numbers of the lines within  }\r
      { which they are referenced.                                    }\r
 \r
    PROCEDURE Traverse(Root: IdentRecPtr);\r
    BEGIN\r
      IF Root<>NIL THEN\r
        BEGIN\r
          Traverse(Root^.Left);\r
          WITH Root^ DO\r
            IF NOT Reserved THEN\r
              BEGIN\r
                Write(OutFile,Id^);\r
                x:=FirstLine; n:=1;\r
                REPEAT\r
                  IF n MOD lf=1 THEN\r
                    BEGIN\r
                      WriteLn(OutFile);\r
                      CurRow := Succ(CurRow);\r
                      IF CurRow > PrintPageLength THEN NewPage(HeadLine);\r
                    END;\r
                  Write(OutFile,x^.Number:8); x:=x^.Next; n:=n+1;\r
                UNTIL x=NIL;\r
                WriteLn(OutFile);\r
                CurRow := Succ(CurRow);\r
                IF CurRow > PrintPageLength THEN NewPage(HeadLine);\r
              END;\r
          Traverse(Root^.Right);\r
        END;\r
    END;\r
 \r
  BEGIN {PrintXRef}\r
    NewPage(HeadLine);\r
    lf := PrintPageWidth DIV 9;\r
    Traverse(IdTree);\r
    WHILE CurRow < PrintPageLength DO\r
      BEGIN\r
        WriteLn(OutFile);\r
        CurRow := Succ(CurRow);\r
      END;\r
    WriteLn(OutFile);\r
  END;\r
 \r
 \r
 \r
  BEGIN\r
    Initialize;\r
    IF NOT Error THEN ProcessFile;\r
    HeadLine := 'Cross reference of main file: '+MainFileName;\r
    IF (NOT Error) AND PrintCrossRef THEN PrintXRef;\r
    IF PrintListing OR PrintCrossRef THEN\r
      BEGIN\r
        NewPage('');\r
        Write(OutFile,DC[DeviceNo].PrinterControlCode[ex]);\r
      END;\r
    IF InOpen THEN close(MainFile);\r
    IF OutOpen THEN close(OutFile);\r
  END.\r
\r
«eof»