home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj8911.zip / HEJLSBER.LST < prev    next >
File List  |  1989-10-04  |  12KB  |  628 lines

  1. _CONTAINER OBJECT TYPES IN TURBO PASCAL_
  2. by Anders Hejlsberg
  3.  
  4. [LISTING ONE]
  5.  
  6. unit Contain;
  7.  
  8. {$S-}
  9.  
  10. interface
  11.  
  12. type
  13.  
  14. { Base object type }
  15.  
  16.   Base = object
  17.     destructor Done; virtual;
  18.   end;
  19.  
  20. { Abstract linked list node type }
  21.  
  22.   ListNodePtr = ^ListNode;
  23.   ListNode = object(Base)
  24.     Next: ListNodePtr;
  25.     function Prev: ListNodePtr;
  26.   end;
  27.  
  28. { Linked list iteration procedure type }
  29.  
  30.   ListAction = procedure(N: ListNodePtr);
  31.  
  32. { Linked list type }
  33.  
  34.   ListPtr = ^List;
  35.  
  36.   List = object(Base)
  37.     Last: ListNodePtr;
  38.     constructor Init;
  39.     destructor Done; virtual;
  40.     procedure Append(N: ListNodePtr);
  41.     procedure Delete;
  42.     function Empty: Boolean;
  43.     procedure ForEach(Action: ListAction);
  44.     function First: ListNodePtr;
  45.     procedure Insert(N: ListNodePtr);
  46.     function Next(N: ListNodePtr): ListNodePtr;
  47.     function Prev(N: ListNodePtr): ListNodePtr;
  48.     procedure Remove(N: ListNodePtr);
  49.   end;
  50.  
  51. { Abstract binary node type }
  52.  
  53.   TreeNodePtr = ^TreeNode;
  54.   TreeNode = object(Base)
  55.     Left, Right: TreeNodePtr;
  56.   end;
  57.  
  58. { Binary tree iteration procedure type }
  59.  
  60.   TreeAction = procedure(N: TreeNodePtr);
  61.  
  62. { Binary tree node creation procedure type }
  63.  
  64.   TreeCreate = function(Key: Pointer): TreeNodePtr;
  65.  
  66. { Binary tree type }
  67.  
  68.   TreePtr = ^Tree;
  69.   Tree = object(Base)
  70.     Root: TreeNodePtr;
  71.     constructor Init;
  72.     destructor Done; virtual;
  73.     function Compare(Key1, Key2: Pointer): Integer; virtual;
  74.     procedure Delete;
  75.     function Empty: Boolean;
  76.     function Find(Key: Pointer): TreeNodePtr;
  77.     procedure ForEach(Action: TreeAction);
  78.     function GetKey(N: TreeNodePtr): Pointer; virtual;
  79.     procedure Insert(N: TreeNodePtr);
  80.     function Search(Key: Pointer; Create: TreeCreate):
  81. TreeNodePtr;
  82.   end;
  83.  
  84. implementation
  85.  
  86. { Base methods }
  87.  
  88. destructor Base.Done;
  89. begin
  90. end;
  91.  
  92. { ListNode methods }
  93.  
  94. function ListNode.Prev: ListNodePtr;
  95. var
  96.   P: ListNodePtr;
  97. begin
  98.   P :=  Self;
  99.   while P^.Next <>  Self do P := P^.Next;
  100.  
  101.   Prev := P;
  102. end;
  103.  
  104. { List methods }
  105.  
  106. {$F+}
  107.  
  108. procedure DelListNode(N: ListNodePtr);
  109. begin
  110.   Dispose(N, Done);
  111. end;
  112.  
  113. {$F-}
  114.  
  115. constructor List.Init;
  116. begin
  117.   Last := nil;
  118. end;
  119.  
  120. destructor List.Done;
  121. begin
  122.  
  123.   Delete;
  124. end;
  125.  
  126. procedure List.Append(N: ListNodePtr);
  127. begin
  128.   Insert(N);
  129.   Last := N;
  130. end;
  131.  
  132. procedure List.Delete;
  133. begin
  134.   ForEach(DelListNode);
  135.   Last := nil;
  136. end;
  137.  
  138. function List.Empty: Boolean;
  139. begin
  140.   Empty := Last = nil;
  141. end;
  142.  
  143. procedure List.ForEach(Action: ListAction);
  144.  
  145. var
  146.   P, Q: ListNodePtr;
  147. begin
  148.   P := First;
  149.   while P <> nil do
  150.   begin
  151.     Q := P;
  152.     P := Next(P);
  153.     Action(Q);
  154.   end;
  155. end;
  156.  
  157. function List.First: ListNodePtr;
  158. begin
  159.   if Last = nil then First := nil else First := Last^.Next;
  160. end;
  161.  
  162. procedure List.Insert(N: ListNodePtr);
  163. begin
  164.   if Last = nil then Last := N else N^.Next := Last^.Next;
  165.   Last^.Next := N;
  166.  
  167. end;
  168.  
  169. function List.Next(N: ListNodePtr): ListNodePtr;
  170. begin
  171.   if N = Last then Next := nil else Next := N^.Next;
  172. end;
  173.  
  174. function List.Prev(N: ListNodePtr): ListNodePtr;
  175. begin
  176.   if N = First then Prev := nil else Prev := N^.Prev;
  177. end;
  178.  
  179. procedure List.Remove(N: ListNodePtr);
  180. var
  181.   P: ListNodePtr;
  182. begin
  183.   if Last <> nil then
  184.   begin
  185.     P := Last;
  186.     while (P^.Next <> N) and (P^.Next <> Last) do P := P^.Next;
  187.     if P^.Next = N then
  188.  
  189.     begin
  190.       P^.Next := N^.Next;
  191.       if Last = N then if P = N then Last := nil else Last := P;
  192.     end;
  193.   end;
  194. end;
  195.  
  196. { Tree methods }
  197.  
  198. var
  199.   NewTreeNode: TreeNodePtr;
  200.  
  201. {$F+}
  202.  
  203. function GetTreeNode(Key: Pointer): TreeNodePtr;
  204. begin
  205.   GetTreeNode := NewTreeNode;
  206. end;
  207.  
  208. procedure DelTreeNode(N: TreeNodePtr);
  209. begin
  210.  
  211.   Dispose(N, Done);
  212. end;
  213.  
  214. {$F-}
  215.  
  216. constructor Tree.Init;
  217. begin
  218.   Root := nil;
  219. end;
  220.  
  221. destructor Tree.Done;
  222. begin
  223.   Delete;
  224. end;
  225.  
  226. function Tree.Compare(Key1, Key2: Pointer): Integer;
  227. begin
  228.   Compare := 0;
  229. end;
  230.  
  231. procedure Tree.Delete;
  232.  
  233. begin
  234.   ForEach(DelTreeNode);
  235.   Root := nil;
  236. end;
  237.  
  238. function Tree.Empty: Boolean;
  239. begin
  240.   Empty := Root = nil;
  241. end;
  242.  
  243. function Tree.Find(Key: Pointer): TreeNodePtr;
  244. begin
  245.   NewTreeNode := nil;
  246.   Find := Search(Key, GetTreeNode);
  247. end;
  248.  
  249. procedure Tree.ForEach(Action: TreeAction);
  250.  
  251.   procedure Traverse(P: TreeNodePtr);
  252.   var
  253.     R: TreeNodePtr;
  254.  
  255.   begin
  256.     if P <> nil then
  257.     begin
  258.       R := P^.Right;
  259.       Traverse(P^.Left);
  260.       Action(P);
  261.       Traverse(R);
  262.     end;
  263.   end;
  264.  
  265. begin
  266.   Traverse(Root);
  267. end;
  268.  
  269. function Tree.GetKey(N: TreeNodePtr): Pointer;
  270. begin
  271.   GetKey := N;
  272. end;
  273.  
  274. procedure Tree.Insert(N: TreeNodePtr);
  275. begin
  276.  
  277.   NewTreeNode := N;
  278.   N := Search(GetKey(N), GetTreeNode);
  279. end;
  280.  
  281. function Tree.Search(Key: Pointer; Create: TreeCreate):
  282. TreeNodePtr;
  283.  
  284.   procedure Traverse(var P: TreeNodePtr);
  285.   var
  286.     C: Integer;
  287.   begin
  288.     if P = nil then
  289.     begin
  290.       P := Create(Key);
  291.       P^.Left := nil;
  292.       P^.Right := nil;
  293.       Search := P;
  294.     end else
  295.     begin
  296.       C := Compare(Key, GetKey(P));
  297.       if C < 0 then Traverse(P^.Left) else
  298.         if C > 0 then Traverse(P^.Right) else
  299.  
  300.           Search := P;
  301.     end;
  302.   end;
  303.  
  304. begin
  305.   Traverse(Root);
  306. end;
  307.  
  308. end.
  309.  
  310.  
  311. [LISTING TWO]
  312.  
  313. program CrossRef;
  314.  
  315. {$S-}
  316. {$M 8192,8192,655360}
  317.  
  318. uses Contain;
  319.  
  320.  
  321. const
  322.  
  323.   MaxIdentLen = 20;      { Maximum identifier length }
  324.   LineNoWidth = 6;       { Width of line numbers in listing }
  325.   RefPerLine  = 8;       { Line numbers per line in
  326. cross-reference }
  327.   IOBufSize   = 4096;    { Input/Output buffer size }
  328.  
  329.   FormFeed  = #12;
  330.   EndOfLine = #13;
  331.   EndOfFile = #26;
  332.  
  333. type
  334.  
  335. { Input/Output buffer }
  336.  
  337.   IOBuffer = array[1..IOBufSize] of Char;
  338.  
  339. { Identifier string }
  340.  
  341.   IdentPtr = ^Ident;
  342.   Ident = string[MaxIdentLen];
  343.  
  344. { Line reference object }
  345.  
  346.   LineRefPtr = ^LineRef;
  347.   LineRef = object(ListNode)
  348.     LineNo: Integer;
  349.     constructor Init(Line: Integer);
  350.   end;
  351.  
  352. { Identifier reference object }
  353.  
  354.   IdentRefPtr = ^IdentRef;
  355.   IdentRef = object(TreeNode)
  356.     Lines: List;
  357.     Name: IdentPtr;
  358.     constructor Init(S: Ident);
  359.     destructor Done; virtual;
  360.   end;
  361.  
  362. { Identifier tree }
  363.  
  364.   IdentTreePtr = ^IdentTree;
  365.   IdentTree = object(Tree)
  366.     function Compare(Key1, Key2: Pointer): Integer; virtual;
  367.     function GetKey(N: TreeNodePtr): Pointer; virtual;
  368.   end;
  369.  
  370. const
  371.  
  372. { Turbo Pascal reserved words }
  373.  
  374.   KeyWordCount = 52;
  375.   KeyWord: array[1..KeyWordCount] of string[15] = (
  376.     'ABSOLUTE', 'AND', 'ARRAY', 'BEGIN', 'CASE', 'CONST',
  377.     'CONSTRUCTOR', 'DESTRUCTOR', 'DIV', 'DO', 'DOWNTO', 'ELSE',
  378.     'END', 'EXTERNAL', 'FILE', 'FOR', 'FORWARD', 'FUNCTION',
  379.     'GOTO', 'IF', 'IMPLEMENTATION', 'IN', 'INLINE', 'INTERFACE',
  380.     'INTERRUPT', 'LABEL', 'MOD', 'NIL', 'NOT', 'OBJECT', 'OF',
  381.     'OR', 'PACKED', 'PROCEDURE', 'PROGRAM', 'RECORD', 'REPEAT',
  382.     'SET', 'SHL', 'SHR', 'STRING', 'THEN', 'TO', 'TYPE', 'UNIT',
  383.     'UNTIL', 'USES', 'VAR', 'VIRTUAL', 'WHILE', 'WITH', 'XOR');
  384.  
  385.  
  386. var
  387.  
  388.   Idents: IdentTree;         { Tree of IdentRef objects }
  389.   LineCount: Integer;        { Current line number }
  390.   RefCount: Integer;         { Counter used by PrintLine }
  391.   InputBuffer: IOBuffer;     { Standard input buffer }
  392.   OutputBuffer: IOBuffer;    { Standard output buffer }
  393.  
  394. { LineRef constructor }
  395.  
  396. constructor LineRef.Init(Line: Integer);
  397. begin
  398.   LineNo := Line;
  399. end;
  400.  
  401. { IdentRef constructor }
  402.  
  403. constructor IdentRef.Init(S: Ident);
  404. begin
  405.   Lines.Init;
  406.   GetMem(Name, Length(S) + 1);
  407.  
  408.   Name^ := S;
  409. end;
  410.  
  411. { IdentRef destructor }
  412.  
  413. destructor IdentRef.Done;
  414. begin
  415.   FreeMem(Name, Length(Name^) + 1);
  416.   Lines.Done;
  417. end;
  418.  
  419. { Compare keys of two IdentRef objects in an IdentTree }
  420.  
  421. function IdentTree.Compare(Key1, Key2: Pointer): Integer;
  422. begin
  423.   if IdentPtr(Key1)^ < IdentPtr(Key2)^ then Compare := -1 else
  424.   if IdentPtr(Key1)^ > IdentPtr(Key2)^ then Compare := 1 else
  425.   Compare := 0;
  426. end;
  427.  
  428. { Return the key of an IdentRef object in an IdentTree }
  429.  
  430. function IdentTree.GetKey(N: TreeNodePtr): Pointer;
  431. begin
  432.   GetKey := IdentRefPtr(N)^.Name;
  433. end;
  434.  
  435. { Insert keywords in identifier tree }
  436.  
  437. procedure InsertKeyWord(L, R: Integer);
  438. var
  439.   I: Integer;
  440. begin
  441.   I := (L + R) div 2;
  442.   Idents.Insert(New(IdentRefPtr, Init(KeyWord[I])));
  443.   if L < I then InsertKeyWord(L, I - 1);
  444.   if I < R then InsertKeyWord(I + 1, R);
  445. end;
  446.  
  447. {$F+}
  448.  
  449. { Create and return a new IdentRef object }
  450.  
  451. function NewIdent(Key: Pointer): TreeNodePtr;
  452. var
  453.   P: IdentRefPtr;
  454. begin
  455.   New(P, Init(IdentPtr(Key)^));
  456.   P^.Lines.Append(New(LineRefPtr, Init(LineCount)));
  457.   NewIdent := P;
  458. end;
  459.  
  460. {$F-}
  461.  
  462. { Process input file and print listing }
  463.  
  464. procedure ProcessFile;
  465. var
  466.   Ch: Char;
  467.  
  468. { Get next character from input file }
  469.  
  470. procedure GetChar;
  471.  
  472. begin
  473.   if Eof then Ch := EndOfFile else
  474.   begin
  475.     if Ch = EndOfLine then
  476.     begin
  477.       Inc(LineCount);
  478.       Write(LineCount: LineNoWidth, ': ');
  479.     end;
  480.     if not Eoln then
  481.     begin
  482.       Read(Ch);
  483.       Write(Ch);
  484.       if (Ch >= 'a') and (Ch <= 'z') then Dec(Ch, 32);
  485.     end else
  486.     begin
  487.       ReadLn;
  488.       WriteLn;
  489.       Ch := EndOfLine;
  490.     end;
  491.   end;
  492. end;
  493.  
  494. { Get next token from input file }
  495.  
  496. procedure GetToken;
  497.  
  498. { Get identifier from input file and enter into tree }
  499.  
  500. procedure GetIdent;
  501. var
  502.   Name: Ident;
  503.   P: LineRefPtr;
  504. begin
  505.   Name := '';
  506.   repeat
  507.     if Length(Name) < MaxIdentLen then
  508.     begin
  509.       Inc(Name[0]);
  510.       Name[Length(Name)] := Ch;
  511.     end;
  512.     GetChar;
  513.   until ((Ch < '0') or (Ch > '9')) and
  514.  
  515.     ((Ch < 'A') or (Ch > 'Z')) and (Ch <> '_');
  516.   with IdentRefPtr(Idents.Search( Name, NewIdent))^ do
  517.     if not Lines.Empty then
  518.       if LineRefPtr(Lines.Last)^.LineNo <> LineCount then
  519.         Lines.Append(New(LineRefPtr, Init(LineCount)));
  520. end;
  521.  
  522. begin { GetToken }
  523.   case Ch of
  524.     'A'..'Z', '_':
  525.       GetIdent;
  526.     '''':
  527.       repeat
  528.         repeat
  529.           GetChar;
  530.         until (Ch = '''') or (Ch = EndOfFile);
  531.         GetChar;
  532.       until (Ch <> '''');
  533.     '$':
  534.       repeat
  535.         GetChar;
  536.  
  537.       until ((Ch < '0') or (Ch > '9')) and
  538.             ((Ch < 'A') or (Ch > 'F'));
  539.     '{':
  540.       begin
  541.         repeat
  542.           GetChar;
  543.         until (Ch = '}') or (Ch = EndOfFile);
  544.         GetChar;
  545.       end;
  546.     '(':
  547.       begin
  548.         GetChar;
  549.         if Ch = '*' then
  550.         begin
  551.           GetChar;
  552.           repeat
  553.             while (Ch <> '*') and (Ch <> EndOfFile) do GetChar;
  554.             GetChar;
  555.           until (Ch = ')') or (Ch = EndOfFile);
  556.           GetChar;
  557.         end;
  558.  
  559.       end;
  560.   else
  561.     GetChar;
  562.   end;
  563. end;
  564.  
  565. begin { ProcessFile }
  566.   Ch := EndOfLine;
  567.   GetChar;
  568.   while (Ch <> EndOfFile) do GetToken;
  569.   Write(FormFeed, EndOfLine);
  570. end;
  571.  
  572. {$F+}
  573.  
  574. { Print a LineRef object }
  575.  
  576. procedure PrintLine(N: ListNodePtr);
  577. begin
  578.   if RefCount = RefPerLine then
  579.   begin
  580.  
  581.     WriteLn;
  582.     Write(' ': MaxIdentLen + 1);
  583.     RefCount := 0;
  584.   end;
  585.   Inc(RefCount);
  586.   Write(LineRefPtr(N)^.LineNo: LineNoWidth);
  587. end;
  588.  
  589. { Print an IdentRef object }
  590.  
  591. procedure PrintRef(N: TreeNodePtr);
  592. begin
  593.   with IdentRefPtr(N)^ do if not Lines.Empty then
  594.   begin
  595.     Write(Name^, ' ': MaxIdentLen + 1 - Length(Name^));
  596.     RefCount := 0;
  597.     Lines.ForEach(PrintLine);
  598.     WriteLn;
  599.   end;
  600. end;
  601.  
  602.  
  603. {$F-}
  604.  
  605. { Print identifier tree }
  606.  
  607. procedure PrintIdents;
  608. begin
  609.   Idents.ForEach(PrintRef);
  610.   Write(FormFeed, EndOfLine);
  611. end;
  612.  
  613. begin { CrossRef }
  614.   Idents.Init;
  615.   LineCount := 0;
  616.   if Pos('.', ParamStr(1)) = 0 then
  617.     Assign(Input, ParamStr(1) + '.PAS')
  618.   else
  619.     Assign(Input, ParamStr(1));
  620.   Reset(Input);
  621.   SetTextBuf(Input, InputBuffer);
  622.   SetTextBuf(Output, OutputBuffer);
  623.   InsertKeyWord(1, KeyWordCount);
  624.   ProcessFile;
  625.   PrintIdents;
  626.   Idents.Done;
  627. end.
  628.