Advertisement
Guest User

PasParser/PasLexer

a guest
Mar 6th, 2015
476
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 55.51 KB | None | 0 0
  1.  
  2. (********************************************************)
  3. (*                                                      *)
  4. (*  Codebot Class Library @ www.codebot.org/delphi      *)
  5. (*                                                      *)
  6. (*  1.00.01 Open Source Released 2006                   *)
  7. (*                                                      *)
  8. (********************************************************)
  9.  
  10. unit PasParser;
  11.  
  12. {$I CODEBOT.INC}
  13.  
  14. interface
  15.  
  16. uses
  17.   Classes, SysUtils, BaseTypes;
  18.  
  19. const
  20.   CR              = #13;
  21.   LF              = #10;
  22.   CRLF            = [CR, LF];
  23.   ASCII           = [#0..#255];
  24.   Whitespace      = [#0..#32];
  25.   Alpha           = ['A'..'Z', 'a'..'z', '_'];
  26.   Numeric         = ['0'..'9'];
  27.   AlphaNumeric    = Alpha + Numeric;
  28.   Space           = ASCII - AlphaNumeric;
  29.  
  30. type
  31.   TTextBufferArray = array of PChar;
  32.  
  33.   TTextLines = class
  34.   private
  35.     FLines: TTextBufferArray;
  36.     FCount: Integer;
  37.     function GetLine(Index: Integer): string;
  38.     function GetOrigin(Index: Integer): PChar;
  39.   protected
  40.     procedure Add(Buffer: PChar);
  41.     function LineFromOrigin(Buffer: PChar): Integer;
  42.   public
  43.     property Count: Integer read FCount;
  44.     property Line[Index: Integer]: string read GetLine; default;
  45.     property Origin[Index: Integer]: PChar read GetOrigin;
  46.   end;
  47.  
  48. { The following parsed token kinds are not reserved words:
  49.  
  50.   TypeKind                     Example
  51.   -----------------------      -------------------------
  52.   tkIdentifier                 TForm1
  53.   tkNumber                     1234
  54.   tkText                       'Hello World'
  55.   tkComma                      ,
  56.   tkPoint                      .
  57.   tkEqual                      =
  58.   tkLessThan                   <
  59.   tkLessThanOrEqual            <=
  60.   tkGreaterThan                >
  61.   tkGreaterThanOrEqual         >=
  62.   tkGets                       :=
  63.   tkColon                      :
  64.   tkSemiColon                  ;
  65.   tkOperator                   + - / *
  66.   tkAddressOf                  @
  67.   tkPointerTo                  ^
  68.   tkLeftParenthesis            (
  69.   tkRightParenthesis           )
  70.   tkLeftBracket                [ (.
  71.   tkRightBracket               ] .)
  72.   tkRange                      ..
  73.   tkSpecialSymbol              # $
  74.   tkAnsiComment                //
  75.   tkCComment                   (*
  76.   tkPascalComment              {
  77.   tkGarbage                    ~ \ % ! | `
  78.   tkNull                       End of buffer }
  79.  
  80.   TPascalTokenKind = (tkAnd, tkArray, tkAs, tkAsm, tkBegin, tkCase, tkClass, tkConst,
  81.     tkConstructor, tkDestructor, tkDispinterface, tkDiv, tkDo, tkDownto, tkElse,
  82.     tkEnd, tkExcept, tkExports, tkFile, tkFinalization, tkFinally, tkFor,
  83.     tkFunction, tkGoto, tkIf, tkImplementation, tkIn, tkInherited,
  84.     tkInitialization, tkInline, tkInterface, tkIs, tkLabel, tkLibrary, tkMod,
  85.     tkNil, tkNot, tkObject, tkOf, tkOr, tkOut, tkPacked, tkProcedure, tkProgram,
  86.     tkProperty, tkRaise, tkRecord, tkRepeat, tkResourcestring, tkSet, tkShl,
  87.     tkShr, tkString, tkThen, tkThreadvar, tkTo, tkTry, tkType, tkUnit, tkUntil,
  88.     tkUses, tkVar, tkWhile, tkWith, tkXor, tkIdentifier, tkNumber, tkText,
  89.     tkComma, tkPoint, tkEqual, tkLessThan, tkLessThanOrEqual, tkGreaterThan,
  90.     tkGreaterThanOrEqual, tkGets, tkColon, tkSemiColon, tkOperator, tkAddressOf,
  91.     tkPointerTo, tkLeftParenthesis, tkRightParenthesis, tkLeftBracket,
  92.     tkRightBracket, tkRange, tkSpecialSymbol, tkAnsiComment, tkCComment,
  93.     tkPascalComment, tkDirective, tkGarbage, tkNull);
  94.   TPascalTokenKinds = set of TPascalTokenKind;
  95.  
  96.   TPascalDirectiveKind = (dkAbsolute, dkAbstract, dkAssembler, dkAutomated,
  97.     dkCdecl, dkContains, dkDefault, dkDispid, dkDynamic, dkExport, dkExternal,
  98.     dkFar, dkForward, dkImplements, dkIndex, dkMessage, dkName, dkNear,
  99.     dkNodefault, dkOverload, dkOverride, dkPackage, dkPascal, dkPrivate,
  100.     dkProtected, dkPublic, dkPublished, dkRead, dkReadonly, dkRegister,
  101.     dkReintroduce, dkRequires, dkResident, dkSafecall, dkStdcall, dkStored,
  102.     dkVirtual, dkWrite,  dkWriteonly, dkNone);
  103.   TPascalDirectiveKinds = set of TPascalDirectiveKind;
  104.  
  105. { TBasePascalToken class }
  106.  
  107.   TPascalParser = class;
  108.  
  109.   TPascalToken = class
  110.   private
  111.     FOwner: TPascalParser;
  112.     FPosition: Integer;
  113.     FLength: Integer;
  114.     FKind: TPascalTokenKind;
  115.     function GetCol: Integer;
  116.     function GetRow: Integer;
  117.     function GetText: string;
  118.     function GetFirst: Boolean;
  119.     function GetLast: Boolean;
  120.   protected
  121.     property Owner: TPascalParser read FOwner;
  122.   public
  123.     constructor Create(AOwner: TPascalParser);
  124.     procedure Copy(Token: TPascalToken);
  125.     property Position: Integer read FPosition;
  126.     property Length: Integer read FLength write FLength;
  127.     property Text: string read GetText;
  128.     property Col: Integer read GetCol;
  129.     property Row: Integer read GetRow;
  130.     property Kind: TPascalTokenKind read FKind;
  131.     property First: Boolean read GetFirst;
  132.     property Last: Boolean read GetLast;
  133.   end;
  134.  
  135. { TPascalTokenList }
  136.  
  137.   TPascalTokenList = class
  138.   private
  139.     FList: TList;
  140.     function GetCount: Integer;
  141.     function GetToken(Index: Integer): TPascalToken;
  142.   public
  143.     constructor Create;
  144.     destructor Destroy; override;
  145.     procedure Add(Token: TPascalToken);
  146.     procedure Clear;
  147.     property Count: Integer read GetCount;
  148.     property Token[Index: Integer]: TPascalToken read GetToken; default;
  149.   end;
  150.  
  151. { EPascalTokenError exception }
  152.  
  153.   EPascalTokenError = class(Exception)
  154.   private
  155.     FToken: TPascalToken;
  156.   public
  157.     constructor CreateFromToken(AToken: TPascalToken);
  158.     property Token: TPascalToken read FToken;
  159.   end;
  160.  
  161. { TPascalParser class }
  162.  
  163.   TPascalParser = class
  164.   private
  165.     FBuffer: PChar;
  166.     FEndOfBuffer: PChar;
  167.     FExceptionTokens: TPascalTokenKinds;
  168.     FOrigin: PChar;
  169.     FToken: TPascalToken;
  170.     FScratchToken: TPascalToken;
  171.     FLines: TTextLines;
  172.     FSize: Integer;
  173.     function GetPosition: Integer;
  174.     procedure SetPosition(Value: Integer);
  175.     procedure SetToken(Value: TPascalToken);
  176.   protected
  177.     property InternalBuffer: PChar read FBuffer;
  178.     property InternalSize: Integer read FSize;
  179.   public
  180.     constructor Create(Buffer: PChar = nil; Size: Integer = 0); virtual;
  181.     destructor Destroy; override;
  182.     procedure Initialize(Buffer: PChar; Size: Integer);
  183.     function CopyText(Index: Integer; Count: Integer): string;
  184.     function Next: TPascalTokenKind;
  185.     function Skip(const SkipKinds: TPascalTokenKinds): TPascalTokenKind;
  186.     function Scan(ScanKinds: TPascalTokenKinds): TPascalTokenKind;
  187.     function Peek(const SkipKinds: TPascalTokenKinds = [];
  188.       ScratchToken: TPascalToken = nil): TPascalTokenKind;
  189.     property ExceptionTokens: TPascalTokenKinds read FExceptionTokens write
  190.       FExceptionTokens;
  191.     property Origin: PChar read FOrigin write FOrigin;
  192.     property Position: Integer read GetPosition write SetPosition;
  193.     property Token: TPascalToken read FToken write SetToken;
  194.     property Lines: TTextLines read FLines;
  195.   end;
  196.  
  197. function SeekToken(P: PChar): PChar;
  198. function SeekWhiteSpace(P: PChar): PChar;
  199.  
  200. const
  201.   ReservedTokens = [tkAnd, tkArray, tkAs, tkAsm, tkBegin, tkCase, tkClass,
  202.     tkConst, tkConstructor, tkDestructor, tkDispinterface, tkDiv, tkDo,
  203.     tkDownto, tkElse, tkEnd, tkExcept, tkExports, tkFile, tkFinalization,
  204.     tkFinally, tkFor, tkFunction, tkGoto, tkIf, tkImplementation, tkIn,
  205.     tkInherited, tkInitialization, tkInline, tkInterface, tkIs, tkLabel,
  206.     tkLibrary, tkMod, tkNil, tkNot, tkObject, tkOf, tkOr, tkOut, tkPacked,
  207.     tkProcedure, tkProgram, tkProperty, tkRaise, tkRecord, tkRepeat,
  208.     tkResourcestring, tkSet, tkShl, tkShr, tkString, tkThen, tkThreadvar, tkTo,
  209.     tkTry, tkType, tkUnit, tkUntil, tkUses, tkVar, tkWhile, tkWith, tkXor];
  210.  
  211.   CommentTokens = [tkAnsiComment, tkCComment, tkPascalComment];
  212.   CallingConventions = [dkCdecl, dkPascal, dkRegister, dkSafecall, dkStdcall];
  213.  
  214. function StrToTokenKind(const Value: string): TPascalTokenKind;
  215. function StrToDirectiveKind(const Value: string): TPascalDirectiveKind;
  216.  
  217. implementation
  218.  
  219. uses
  220.   StrConst;
  221.  
  222. function SeekToken(P: PChar): PChar;
  223. begin
  224.   while CharInSet(P^, [#1..#9, #11, #12, #14..#32]) do
  225.     Inc(P);
  226.   Result := P;
  227. end;
  228.  
  229. function SeekWhiteSpace(P: PChar): PChar;
  230. begin
  231.   while CharInSet(P^, [#33..#255]) do
  232.     Inc(P);
  233.   Result := P;
  234. end;
  235.  
  236. function Hash(const Token: string): Integer;
  237. var
  238.   I: Integer;
  239. begin
  240.   Result := 0;
  241.   for I := 1 to Length(Token) do
  242.     Inc(Result, Ord(Token[I]));
  243. end;
  244.  
  245. function StrToTokenKind(const Value: string): TPascalTokenKind;
  246. var
  247.   Token: string;
  248.   I: Integer;
  249. begin
  250.   Result := tkGarbage;
  251.   Token := UpperCase(Value);
  252.   case Hash(Token) of
  253.     143: if Token = 'IF' then Result := tkIf;
  254.     147: if Token = 'DO' then Result := tkDo;
  255.     148: if Token = 'AS' then Result := tkAs;
  256.     149: if Token = 'OF' then Result := tkOf;
  257.     151: if Token = 'IN' then Result := tkIn;
  258.     156: if Token = 'IS' then Result := tkIs;
  259.     161: if Token = 'OR' then Result := tkOr;
  260.     163: if Token = 'TO' then Result := tkTo;
  261.     211: if Token = 'AND' then Result := tkAnd;
  262.     215: if Token = 'END' then Result := tkEnd;
  263.     224: if Token = 'MOD' then Result := tkMod;
  264.     225: if Token = 'ASM' then Result := tkAsm;
  265.     227: if Token = 'DIV' then Result := tkDiv
  266.       else if Token = 'NIL' then Result := tkNil;
  267.     231: if Token = 'FOR' then Result := tkFor
  268.       else if Token = 'SHL' then Result := tkShl;
  269.     233: if Token = 'VAR' then Result := tkVar;
  270.     236: if Token = 'SET' then Result := tkSet;
  271.     237: if Token = 'SHR' then Result := tkShr;
  272.     241: if Token = 'NOT' then Result := tkNot;
  273.     248: if Token = 'OUT' then Result := tkOut;
  274.     249: if Token = 'XOR' then Result := tkXor;
  275.     255: if Token = 'TRY' then Result := tkTry;
  276.     284: if Token = 'CASE' then Result := tkCase;
  277.     288: if Token = 'FILE' then Result := tkFile;
  278.     297: if Token = 'ELSE' then Result := tkElse;
  279.     303: if Token = 'THEN' then Result := tkThen;
  280.     313: if Token = 'GOTO' then Result := tkGoto;
  281.     316: if Token = 'WITH' then Result := tkWith;
  282.     320: if Token = 'UNIT' then Result := tkUnit
  283.       else if Token = 'USES' then Result := tkUses;
  284.     322: if Token = 'TYPE' then Result := tkType;
  285.     352: if Token = 'LABEL' then Result := tkLabel;
  286.     357: if Token = 'BEGIN' then Result := tkBegin;
  287.     372: if Token = 'RAISE' then Result := tkRaise;
  288.     374: if Token = 'CLASS' then Result := tkClass;
  289.     377: if Token = 'WHILE' then Result := tkWhile;
  290.     383: if Token = 'ARRAY' then Result := tkArray;
  291.     391: if Token = 'CONST' then Result := tkConst;
  292.     396: if Token = 'UNTIL' then Result := tkUntil;
  293.     424: if Token = 'PACKED' then Result := tkPacked;
  294.     439: if Token = 'OBJECT' then Result := tkObject;
  295.     447: if Token = 'INLINE' then Result := tkInline
  296.       else if Token = 'RECORD' then Result := tkRecord;
  297.     449: if Token = 'REPEAT' then Result := tkRepeat;
  298.     457: if Token = 'EXCEPT' then Result := tkExcept;
  299.     471: if Token = 'STRING' then Result := tkString;
  300.     475: if Token = 'DOWNTO' then Result := tkDownto;
  301.     527: if Token = 'FINALLY' then Result := tkFinally;
  302.     533: if Token = 'LIBRARY' then Result := tkLibrary;
  303.     536: if Token = 'PROGRAM' then Result := tkProgram;
  304.     565: if Token = 'EXPORTS' then Result := tkExports;
  305.     614: if Token = 'FUNCTION' then Result := tkFunction;
  306.     645: if Token = 'PROPERTY' then Result := tkProperty;
  307.     657: if Token = 'INTERFACE' then Result := tkInterface;
  308.     668: if Token = 'INHERITED' then Result := tkInherited;
  309.     673: if Token = 'THREADVAR' then Result := tkThreadvar;
  310.     681: if Token = 'PROCEDURE' then Result := tkProcedure;
  311.     783: if Token = 'DESTRUCTOR' then Result := tkDestructor;
  312.     870: if Token = 'CONSTRUCTOR' then Result := tkConstructor;
  313.     904: if Token = 'FINALIZATION' then Result := tkFinalization;
  314.     961: if Token = 'DISPINTERFACE' then Result := tkDispinterface;
  315.     1062: if Token = 'IMPLEMENTATION' then Result := tkImplementation;
  316.     1064: if Token = 'INITIALIZATION' then Result := tkInitialization;
  317.     1087: if Token = 'RESOURCESTRING' then Result := tkResourcestring;
  318.   end;
  319.   if Result = tkGarbage then
  320.     { is valid identifier }
  321.     if CharInSet(Token[1], Alpha) then
  322.     begin
  323.       Result := tkIdentifier;
  324.       for I := 2 to Length(Token) do
  325.       if not CharInSet(Token[I], AlphaNumeric) then
  326.       begin
  327.         Result := tkGarbage;
  328.         Exit;
  329.       end;
  330.     end
  331.     else
  332.     { is valid number }
  333.     for I := 1 to Length(Token) do
  334.     begin
  335.       if not CharInSet(Token[I], Numeric) then
  336.         Exit;
  337.       Result := tkNumber;
  338.     end;
  339. end;
  340.  
  341. function StrToDirectiveKind(const Value: string): TPascalDirectiveKind;
  342. var
  343.   Token: string;
  344. begin
  345.   Result := dkNone;
  346.   Token := UpperCase(Value);
  347.   case Hash(Token) of
  348.     217: if Token = 'FAR' then Result := dkFar;
  349.     284: if Token = 'READ' then Result := dkRead;
  350.     289: if Token = 'NAME' then Result := dkName;
  351.     294: if Token = 'NEAR' then Result := dkNear;
  352.     347: if Token = 'CDECL' then Result := dkCdecl;
  353.     376: if Token = 'INDEX' then Result := dkIndex;
  354.     395: if Token = 'WRITE' then Result := dkWrite;
  355.     436: if Token = 'PASCAL' then Result := dkPascal;
  356.     445: if Token = 'DISPID' then Result := dkDispid;
  357.     447: if Token = 'PUBLIC' then Result := dkPublic;
  358.     465: if Token = 'STORED' then Result := dkStored;
  359.     482: if Token = 'EXPORT' then Result := dkExport;
  360.     492: if Token = 'PACKAGE' then Result := dkPackage;
  361.     517: if Token = 'DEFAULT' then Result := dkDefault
  362.       else if Token = 'DYNAMIC' then Result := dkDynamic
  363.       else if Token = 'MESSAGE' then Result := dkMessage;
  364.     519: if Token = 'STDCALL' then Result := dkStdcall;
  365.     533: if Token = 'FORWARD' then Result := dkForward;
  366.     539: if Token = 'PRIVATE' then Result := dkPrivate;
  367.     551: if Token = 'VIRTUAL' then Result := dkVirtual;
  368.     571: if Token = 'SAFECALL' then Result := dkSafecall;
  369.     596: if Token = 'ABSTRACT' then Result := dkAbstract;
  370.     604: if Token = 'OVERLOAD' then Result := dkOverload;
  371.     606: if Token = 'READONLY' then Result := dkReadonly
  372.       else if Token = 'RESIDENT' then Result := dkResident;
  373.     607: if Token = 'ABSOLUTE' then Result := dkAbsolute
  374.       else if Token = 'CONTAINS' then Result := dkContains;
  375.     608: if Token = 'OVERRIDE' then Result := dkOverride;
  376.     611: if Token = 'EXTERNAL' then Result := dkExternal;
  377.     613: if Token = 'REGISTER' then Result := dkRegister;
  378.     624: if Token = 'REQUIRES' then Result := dkRequires;
  379.     670: if Token = 'ASSEMBLER' then Result := dkAssembler;
  380.     672: if Token = 'PUBLISHED' then Result := dkPublished;
  381.     674: if Token = 'NODEFAULT' then Result := dkNodefault;
  382.     676: if Token = 'AUTOMATED' then Result := dkAutomated;
  383.     682: if Token = 'PROTECTED' then Result := dkProtected;
  384.     717: if Token = 'WRITEONLY' then Result := dkWriteonly;
  385.     766: if Token = 'IMPLEMENTS' then Result := dkImplements;
  386.     836: if Token = 'REINTRODUCE' then Result := dkReintroduce;
  387.   end;
  388. end;
  389.  
  390. { TTextLines }
  391.  
  392. procedure TTextLines.Add(Buffer: PChar);
  393. const
  394.   Delta = 10;
  395. begin
  396.   if (FCount > 0) and (Buffer <= FLines[FCount - 1]) then
  397.     Exit;
  398.   if FCount mod Delta = 0 then
  399.     SetLength(FLines, FCount + 10);
  400.   FLines[FCount] := Buffer;
  401.   Inc(FCount);
  402. end;
  403.  
  404. function TTextLines.LineFromOrigin(Buffer: PChar): Integer;
  405. var
  406.   I: Integer;
  407. begin
  408.   Result := -1;
  409.   if FCount = 0 then
  410.     Exit;
  411.   for I := 0 to FCount - 1 do
  412.   begin
  413.     if FLines[I] > Buffer then
  414.       Break;
  415.     Inc(Result);
  416.   end;
  417. end;
  418.  
  419. function TTextLines.GetLine(Index: Integer): string;
  420. var
  421.   P, Start: PChar;
  422. begin
  423.   Result := '';
  424.   P := GetOrigin(Index);
  425.   if P = nil then
  426.     Exit;
  427.   Start := P;
  428.   while (not CharInSet(P^, CRLF)) and (P^ > #0) do
  429.     Inc(P);
  430.   SetString(Result, Start, P - Start);
  431. end;
  432.  
  433. function TTextLines.GetOrigin(Index: Integer): PChar;
  434. begin
  435.   Result := nil;
  436.   if (Index < 0) or (Index > FCount - 1) then
  437.     Exit;
  438.   Result := FLines[Index];
  439. end;
  440.  
  441. { TPascalToken }
  442.  
  443. constructor TPascalToken.Create(AOwner: TPascalParser);
  444. begin
  445.   FOwner := AOwner;
  446. end;
  447.  
  448. procedure TPascalToken.Copy(Token: TPascalToken);
  449. begin
  450.   FOwner := Token.FOwner;
  451.   FPosition := Token.FPosition;
  452.   FLength := Token.FLength;
  453.   FKind := Token.FKind;
  454. end;
  455.  
  456. function TPascalToken.GetCol: Integer;
  457. var
  458.   P: PChar;
  459. begin
  460.   P := FOwner.FBuffer;
  461.   Inc(P, FPosition);
  462.   Result := FOwner.Lines.LineFromOrigin(P);
  463.   if Result > -1 then
  464.     Result := Integer(P - FOwner.Lines.Origin[Result])
  465.   else
  466.     Result := Integer(P - FOwner.FBuffer);
  467. end;
  468.  
  469. function TPascalToken.GetRow: Integer;
  470. var
  471.   P: PChar;
  472. begin
  473.   P := FOwner.FBuffer;
  474.   Inc(P, FPosition);
  475.   Result := FOwner.Lines.LineFromOrigin(P);
  476.   if Result = -1 then
  477.     Result := 0;
  478. end;
  479.  
  480. function TPascalToken.GetText: string;
  481. var
  482.   PrevPosition: Integer;
  483. begin
  484.   PrevPosition := FOwner.Position;
  485.   FOwner.Position := FPosition;
  486.   SetString(Result, FOwner.Origin, Length);
  487.   FOwner.Position := PrevPosition;
  488. end;
  489.  
  490. function TPascalToken.GetFirst: Boolean;
  491. var
  492.   P: PChar;
  493. begin
  494.   P := FOwner.FBuffer;
  495.   Inc(P, FPosition);
  496.   while P > FOwner.FBuffer do
  497.     if CharInSet(P^, [#10, #13, #33..#255]) then
  498.       Break
  499.     else
  500.       Inc(P);
  501.   Result := (P = FOwner.FBuffer) or CharInSet(P^, CRLF);
  502. end;
  503.  
  504. function TPascalToken.GetLast: Boolean;
  505. var
  506.   P: PChar;
  507. begin
  508.   P := FOwner.FBuffer;
  509.   Inc(P, FPosition + FLength);
  510.   while P^ > #0 do
  511.     if CharInSet(P^, [#10, #13, #33..#255]) then
  512.       Break
  513.     else
  514.       Inc(P);
  515.   Result := CharInSet(P^, [#0, #10, #13]);
  516. end;
  517.  
  518. { TPascalTokenList }
  519.  
  520. constructor TPascalTokenList.Create;
  521. begin
  522.   inherited Create;
  523.   FList := TList.Create;
  524. end;
  525.  
  526. destructor TPascalTokenList.Destroy;
  527. begin
  528.   Clear;
  529.   FList.Free;
  530.   inherited Destroy;
  531. end;
  532.  
  533. procedure TPascalTokenList.Add(Token: TPascalToken);
  534. var
  535.   NewToken: TPascalToken;
  536. begin
  537.   NewToken := TPascalToken.Create(nil);
  538.   NewToken.Copy(Token);
  539.   FList.Add(NewToken);
  540. end;
  541.  
  542. procedure TPascalTokenList.Clear;
  543. var
  544.   I: Integer;
  545. begin
  546.   for I := FList.Count - 1 downto 0 do
  547.     TObject(FList[I]).Free;
  548. end;
  549.  
  550. function TPascalTokenList.GetCount: Integer;
  551. begin
  552.   Result := FList.Count;
  553. end;
  554.  
  555. function TPascalTokenList.GetToken(Index: Integer): TPascalToken;
  556. begin
  557.   Result := TPascalToken(FList[Index]);
  558. end;
  559.  
  560. { EPascalTokenError }
  561.  
  562. constructor EPascalTokenError.CreateFromToken(AToken: TPascalToken);
  563. begin
  564.   FToken := AToken;
  565.   inherited CreateFmt(SUnexpectedToken, [FToken.Position]);
  566. end;
  567.  
  568. { TPascalParser }
  569.  
  570. constructor TPascalParser.Create(Buffer: PChar = nil; Size: Integer = 0);
  571. begin
  572.   inherited Create;
  573.   Initialize(Buffer, Size);
  574. end;
  575.  
  576. destructor TPascalParser.Destroy;
  577. begin
  578.   FLines.Free;
  579.   FToken.Free;
  580.   FScratchToken.Free;
  581.   inherited Destroy;
  582. end;
  583.  
  584. procedure TPascalParser.Initialize(Buffer: PChar; Size: Integer);
  585. begin
  586.   FreeAndNil(FLines);
  587.   FreeAndNil(FToken);
  588.   FreeAndNil(FScratchToken);
  589.   FLines := TTextLines.Create;
  590.   FToken := TPascalToken.Create(Self);
  591.   FScratchToken := TPascalToken.Create(Self);
  592.   FBuffer := Buffer;
  593.   FEndOfBuffer := Buffer;
  594.   FOrigin := Buffer;
  595.   FSize := Size;
  596.   Inc(FEndOfBuffer, Size);
  597. end;
  598.  
  599. function TPascalParser.GetPosition: Integer;
  600. begin
  601.   Result := FOrigin - FBuffer;
  602. end;
  603.  
  604. procedure TPascalParser.SetToken(Value: TPascalToken);
  605. begin
  606.   if Value.FOwner = Self then
  607.     with FToken do
  608.     begin
  609.       Copy(Value);
  610.       Self.Position := Position + Length;
  611.     end
  612.     else
  613.       raise EPascalTokenError.Create(SInvalidPropertyValue);
  614. end;
  615.  
  616. procedure TPascalParser.SetPosition(Value: Integer);
  617. begin
  618.   if Value <> Position then
  619.   begin
  620.     FOrigin := FBuffer;
  621.     Inc(FOrigin, Value)
  622.   end;
  623. end;
  624.  
  625. function TPascalParser.CopyText(Index: Integer; Count: Integer): string;
  626. var
  627.   P: PChar;
  628. begin
  629.   P := FBuffer;
  630.   Inc(P, Index);
  631.   SetString(Result, P, Count);
  632. end;
  633.  
  634.  
  635. function TPascalParser.Next: TPascalTokenKind;
  636.  
  637.   function GetCommentLength: Integer;
  638.   var
  639.     P: PChar;
  640.   begin
  641.     P := FOrigin;
  642.     case FToken.Kind of
  643.       tkAnsiComment:
  644.       repeat
  645.         Inc(P)
  646.       until (P = FEndOfBuffer) or CharInSet(P[0], CRLF);
  647.       tkCComment:
  648.       begin
  649.         Inc(P);
  650.         if @P[1] < FEndOfBuffer then
  651.         begin
  652.           repeat
  653.             Inc(P);
  654.           until (@P[1] = FEndOfBuffer) or ((P[0] = '*') and (P[1] = ')'));
  655.           if @P[1] < FEndOfBuffer then
  656.             Inc(P, 2)
  657.           else
  658.             Inc(P);
  659.         end;
  660.       end;
  661.       tkPascalComment:
  662.       begin
  663.         repeat
  664.           Inc(P);
  665.         until (P = FEndOfBuffer) or (P[0] = '}');
  666.         if P < FEndOfBuffer then
  667.           Inc(P);
  668.       end;
  669.     end;
  670.     Result := P - FOrigin;
  671.   end;
  672.  
  673. var
  674.   P: PChar;
  675.   S: string;
  676. begin
  677.   if FLines.Count = 0 then
  678.     FLines.Add(FOrigin);
  679.   while (FOrigin < FEndOfBuffer) and CharInSet(FOrigin[0], Whitespace) do
  680.     if (FOrigin[0] = #13) and (FOrigin[1] = #10) then
  681.     begin
  682.       Inc(FOrigin, 2);
  683.       FLines.Add(FOrigin);
  684.     end
  685.     else
  686.       Inc(FOrigin);
  687.   if FOrigin < FEndOfBuffer then
  688.   case FOrigin[0] of
  689.     { tkText }
  690.     '''':
  691.     begin
  692.       P := FOrigin;
  693.       FToken.FKind := tkText;
  694.       repeat
  695.         Inc(P);
  696.         while (P < FEndOfBuffer) and (P[0] = '''') and (P[1] = '''') do
  697.           Inc(P, 2);
  698.       until (P = FEndOfBuffer) or (P[0] = '''') or CharInSet(P[0], CRLF);
  699.       if (P < FEndOfBuffer) and (P[0] = '''') then
  700.         Inc(P)
  701.       else
  702.         FToken.FKind := tkGarbage;
  703.       FToken.FLength := P - FOrigin;
  704.     end;
  705.     { tkComma }
  706.     ',':
  707.     begin
  708.       FToken.FKind := tkComma;
  709.       FToken.FLength := 1;
  710.     end;
  711.     { tkPoint, tkRightBracket, tkRange }
  712.     '.':
  713.     if @FOrigin[1] < FEndOfBuffer then
  714.     case FOrigin[1] of
  715.       ')':
  716.       begin
  717.         FToken.FKind := tkRightBracket;
  718.         FToken.FLength := 2;
  719.       end;
  720.       '.':
  721.       begin
  722.         FToken.FKind := tkRange;
  723.         FToken.FLength := 2;
  724.       end;
  725.       else
  726.       begin
  727.         FToken.FKind := tkPoint;
  728.         FToken.FLength := 1;
  729.       end;
  730.     end
  731.     else
  732.     begin
  733.       FToken.FKind := tkPoint;
  734.       FToken.FLength := 1;
  735.     end;
  736.     { tkEqual }
  737.     '=':
  738.     begin
  739.       FToken.FKind := tkEqual;
  740.       FToken.FLength := 1;
  741.     end;
  742.     { tkLessThan, tkLessThanOrEqual }
  743.     '<':
  744.     if (@FOrigin[1] < FEndOfBuffer) and (Origin[1] = '=') then
  745.     begin
  746.       FToken.FKind := tkLessThanOrEqual;
  747.       FToken.FLength := 2;
  748.     end
  749.     else
  750.     begin
  751.       FToken.FKind := tkLessThan;
  752.       FToken.FLength := 1;
  753.     end;
  754.     { tkGreaterThan, tkGreaterThanOrEqual }
  755.     '>':
  756.     if (@FOrigin[1] < FEndOfBuffer) and (Origin[1] = '=') then
  757.     begin
  758.       FToken.FKind := tkGreaterThanOrEqual;
  759.       FToken.FLength := 2;
  760.     end
  761.     else
  762.     begin
  763.       FToken.FKind := tkGreaterThan;
  764.       FToken.FLength := 1;
  765.     end;
  766.     { tkGets, tkColon }
  767.     ':':
  768.     if (@FOrigin[1] < FEndOfBuffer) and (Origin[1] = '=') then
  769.     begin
  770.       FToken.FKind := tkGets;
  771.       FToken.FLength := 2;
  772.     end
  773.     else
  774.     begin
  775.       FToken.FKind := tkColon;
  776.       FToken.FLength := 1;
  777.     end;
  778.     { tkSemiColon }
  779.     ';':
  780.     begin
  781.       FToken.FKind := tkSemiColon;
  782.       FToken.FLength := 1;
  783.     end;
  784.     { tkAnsiComment, tkOperator }
  785.     '+', '-', '/', '*':
  786.     if (@FOrigin[1] < FEndOfBuffer) and (Origin[0] = '/') and (Origin[1] = '/') then
  787.     begin
  788.       FToken.FKind := tkAnsiComment;
  789.       FToken.FLength := GetCommentLength;
  790.     end
  791.     else
  792.     begin
  793.       FToken.FKind := tkOperator;
  794.       FToken.FLength := 1;
  795.     end;
  796.     { tkAddressOf }
  797.     '@':
  798.     begin
  799.       FToken.FKind := tkAddressOf;
  800.       FToken.FLength := 1;
  801.     end;
  802.     { tkPointerTo }
  803.     '^':
  804.     begin
  805.       FToken.FKind := tkPointerTo;
  806.       FToken.FLength := 1;
  807.     end;
  808.     { tkLeftBracket, tkCComment, tkLeftParenthesis }
  809.     '(':
  810.     if @FOrigin[1] < FEndOfBuffer then
  811.     case FOrigin[1] of
  812.       '.':
  813.       begin
  814.         FToken.FKind := tkLeftBracket;
  815.         FToken.FLength := 2;
  816.       end;
  817.       '*':
  818.       begin
  819.         FToken.FKind := tkCComment;
  820.         if FOrigin[2] = '$' then
  821.         begin
  822.           FToken.FLength := GetCommentLength;
  823.           FToken.FKind := tkDirective;
  824.         end
  825.         else
  826.           FToken.FLength := GetCommentLength;
  827.       end;
  828.       else
  829.       begin
  830.         FToken.FKind := tkLeftParenthesis;
  831.         FToken.FLength := 1;
  832.       end;
  833.     end
  834.     else
  835.     begin
  836.       FToken.FKind := tkLeftParenthesis;
  837.       FToken.FLength := 1;
  838.     end;
  839.     { tkRightParenthesis }
  840.     ')':
  841.     begin
  842.       FToken.FKind := tkRightParenthesis;
  843.       FToken.FLength := 1;
  844.     end;
  845.     { tkLeftBracket }
  846.     '[':
  847.     begin
  848.       FToken.FKind := tkLeftBracket;
  849.       FToken.FLength := 1;
  850.     end;
  851.     { tkRightBracket }
  852.     ']':
  853.     begin
  854.       FToken.FKind := tkRightBracket;
  855.       FToken.FLength := 1;
  856.     end;
  857.     { tkSpecialSymbol }
  858.     '#', '$':
  859.     begin
  860.       FToken.FKind := tkSpecialSymbol;
  861.       FToken.FLength := 1;
  862.     end;
  863.     { tkPascalComment }
  864.     '{':
  865.     begin
  866.       FToken.FKind := tkPascalComment;
  867.       if FOrigin[1] = '$' then
  868.       begin
  869.         FToken.FLength := GetCommentLength;
  870.         FToken.FKind := tkDirective;
  871.       end
  872.       else
  873.         FToken.FLength := GetCommentLength;
  874.     end;
  875.     { token in the range of tkAnd..tkNumber, tkGarbage }
  876.     else
  877.     begin
  878.       P := FOrigin;
  879.       repeat
  880.         Inc(P);
  881.       until (P = FEndOfBuffer) or CharInSet(P[0], Space);
  882.       SetString(S, FOrigin, P - FOrigin);
  883.       FToken.FKind := StrToTokenKind(S);
  884.       FToken.FLength := Length(S);
  885.     end;
  886.   end
  887.   { token is tkNull }
  888.   else
  889.   begin
  890.     FOrigin := FEndOfBuffer;
  891.     FToken.FKind := tkNull;
  892.     FToken.FLength := 0;
  893.   end;
  894.   FToken.FPosition := Position;
  895.   Inc(FOrigin, FToken.FLength);
  896.   Result := FToken.FKind;
  897. end;
  898.  
  899. function TPascalParser.Skip(const SkipKinds: TPascalTokenKinds):
  900.   TPascalTokenKind;
  901. begin
  902.   repeat
  903.     Result := Next;
  904.     if Result in FExceptionTokens then
  905.       raise EPascalTokenError.CreateFmt(SInvalidToken, [Token.Row, Token.Col]);
  906.   until (not (Result in SkipKinds)) or (Result = tkNull);
  907. end;
  908.  
  909. function TPascalParser.Scan(ScanKinds: TPascalTokenKinds): TPascalTokenKind;
  910. begin
  911.   repeat
  912.     Result := Next;
  913.     if Result in FExceptionTokens then
  914.       raise EPascalTokenError.CreateFmt(SInvalidToken, [Token.Row, Token.Col]);
  915.   until (Result in ScanKinds) or (Result = tkNull);
  916. end;
  917.  
  918. function TPascalParser.Peek(const SkipKinds: TPascalTokenKinds = [];
  919.   ScratchToken: TPascalToken = nil): TPascalTokenKind;
  920. var
  921.   P: PChar;
  922. begin
  923.   P := FOrigin;
  924.   FScratchToken.Copy(Token);
  925.   repeat
  926.     Result := Next;
  927.   until (Result = tkNull) or (not (Result in SkipKinds));
  928.   if ScratchToken <> nil then
  929.     ScratchToken.Copy(FToken);
  930.   FToken.Copy(FScratchToken);
  931.   FOrigin := P;
  932. end;
  933.  
  934. end.
  935.  
  936.  
  937.  
  938. (********************************************************)
  939. (*                                                      *)
  940. (*  Codebot Class Library @ www.codebot.org/delphi      *)
  941. (*                                                      *)
  942. (*  1.00.01 Open Source Released 2006                   *)
  943. (*                                                      *)
  944. (********************************************************)
  945.  
  946. unit PasLexer;
  947.  
  948. interface
  949.  
  950. {$I CODEBOT.INC}
  951.  
  952. uses
  953.   Classes, SysUtils, PasParser, WinTools, SysTools;
  954.  
  955. { The TPascalLexer class is a basic lexical analysis tool. When used in
  956.   conjunction with a source code file, it is assumed that the source is in a
  957.   perfect state. That is to say, the source file MUST conform exactly to Object
  958.   Pascal grammer before being handed off to the TPascalLexer class. The result
  959.   of a less than perfect source file could lead to an endless looping condition. }
  960.  
  961. type
  962.   TSourceKind = (skArray, skClass, skClassReference, skConstant, skConstructor,
  963.     skDestructor, skEnumeration, skEvent, skField, skFunction, skFunctionEvent,
  964.     skFunctionInterfaceMethod, skFunctionMethod, skFunctionPointer, skInterface,
  965.     skInterfaceMethod, skMember, skMethod, skProcedure, skProcedureEvent,
  966.     skProcedureInterfaceMethod, skProcedureMethod, skProcedurePointer, skProperty,
  967.     skRecord, skResourceString, skSet, skThreadVariable, skType, skVariable, skUses);
  968.   TSourceKinds = set of TSourceKind;
  969.  
  970. const
  971.   AllSourceKinds: TSourceKinds = [skArray, skClass, skClassReference, skConstant, skConstructor,
  972.     skDestructor, skEnumeration, skEvent, skField, skFunction, skFunctionEvent,
  973.     skFunctionInterfaceMethod, skFunctionMethod, skFunctionPointer, skInterface,
  974.     skInterfaceMethod, skMember, skMethod, skProcedure, skProcedureEvent,
  975.     skProcedureInterfaceMethod, skProcedureMethod, skProcedurePointer, skProperty,
  976.     skRecord, skResourceString, skSet, skThreadVariable, skType, skVariable, skUses];
  977.  
  978. type
  979.   TRoutineKind = (rkConstructor, rkDestructor, rkFunction, rkProcedure);
  980.   TCallingConvention = (ccDefault, ccCdecl, ccPascal, ccRegister, ccStdcall,
  981.     ccSafecall);
  982.  
  983.   TMemberVisibility = (mvPrivate, mvProtected, mvPublic, mvPublished);
  984.   TMemberVisibilities = set of TMemberVisibility;
  985.  
  986.   TPropertyAccess = set of (paRead, paWrite);
  987.   TVirtualKind = (vkStatic, vkDynamic, vkMessage, vkOverride, vkVirtual, vkReintroduce);
  988.  
  989.   TSourceInfo = packed record
  990.     Line: Integer;
  991.     Column: Integer;
  992.     Name: ShortString;
  993.     Kind: TSourceKind;
  994.     case TSourceKind of
  995.       skClass: (
  996.         ClassParent: ShortString;
  997.         InterfaceCount: Integer);
  998.       skFunction, skProcedure: (
  999.         RoutineKind: TRoutineKind;
  1000.         RoutineConvention: TCallingConvention);
  1001.       skInterface: (
  1002.         InterfaceParent: ShortString);
  1003.       skInterfaceMethod: (
  1004.         InterfaceName: ShortString;
  1005.         InterfaceMethodKind: TRoutineKind;
  1006.         InterfaceMethodConvention: TCallingConvention);
  1007.       skMember: (
  1008.         ClassName: ShortString;
  1009.         Visibility: TMemberVisibility;
  1010.         case TSourceKind of
  1011.           skMethod: (
  1012.             ClassMethod: Boolean;
  1013.             ClassMethodKind: TRoutineKind;
  1014.             VirtualKind: TVirtualKind;
  1015.             Abstracted: Boolean;
  1016.             Reintroduced: Boolean;
  1017.             Overloaded: Boolean;
  1018.             ClassMethodConvention: TCallingConvention);
  1019.           skProperty: (
  1020.             { todo: fix }
  1021.                     Promoted: Boolean;
  1022.                         Event: Boolean;
  1023.             Access: TPropertyAccess;
  1024.             Default: Boolean);
  1025.           skField: (
  1026.             ));
  1027.   end;
  1028.  
  1029.   TLexicalClassEvent = procedure(Sender: TObject; const Body: string;
  1030.     const Info: TSourceInfo; const InheritedName: string;
  1031.     InterfaceList: TStrings) of object;
  1032.   TLexicalCommentEvent = procedure(Sender: TObject; const Comment: string) of object;
  1033.   TLexicalEvent = procedure(Sender: TObject; const Body: string;
  1034.     const Info: TSourceInfo) of object;
  1035.   TLexicalInterfaceEvent = procedure(Sender: TObject; const Body: string;
  1036.     const Info: TSourceInfo; const InheritedName: string) of object;
  1037.   TLexicalUsesEvent = procedure(Sender: TObject; UsesList: TStrings) of object;
  1038.  
  1039.   TPascalLexer = class(TPascalParser)
  1040.   private
  1041.     FFileName: string;
  1042.     FIdentifier: TPascalToken;
  1043.     FInterfaceList: TStrings;
  1044.     FMap: TMemoryMappedFile;
  1045.     FScratchToken: TPascalToken;
  1046.     FSection: TPascalTokenKind;
  1047.     FUnitIdent: string;
  1048.     FUnitPath: string;
  1049.     FOnArray: TLexicalEvent;
  1050.     FOnClass: TLexicalClassEvent;
  1051.     FOnClassReference: TLexicalEvent;
  1052.     FOnMethod: TLexicalEvent;
  1053.     FOnComment: TLexicalCommentEvent;
  1054.     FOnConstant: TLexicalEvent;
  1055.     FOnField: TLexicalEvent;
  1056.     FOnFunction: TLexicalEvent;
  1057.     FOnEnumeration: TLexicalEvent;
  1058.     FOnEvent: TLexicalEvent;
  1059.     FOnInterface: TLexicalInterfaceEvent;
  1060.     FOnInterfaceMethod: TLexicalEvent;
  1061.     FOnProcedure: TLexicalEvent;
  1062.     FOnProperty: TLexicalEvent;
  1063.     FOnRecord: TLexicalEvent;
  1064.     FOnRoutinePointer: TLexicalEvent;
  1065.     FOnSet: TLexicalEvent;
  1066.     FOnType: TLexicalEvent;
  1067.     FOnUses: TLexicalUsesEvent;
  1068.     FOnVariable: TLexicalEvent;
  1069.     procedure ReadArray;
  1070.     function ReadCallingConvention: TCallingConvention;
  1071.     procedure ReadClass;
  1072.     procedure ReadClassReference;
  1073.     procedure ReadComment;
  1074.     procedure ReadConstant;
  1075.     procedure ReadEnumeration;
  1076.     procedure ReadInterface;
  1077.     procedure ReadRecord;
  1078.     procedure ReadRoutine;
  1079.     procedure ReadRoutinePointer(Kind: TRoutineKind);
  1080.     procedure ReadSet;
  1081.     procedure ReadType;
  1082.     procedure ReadUses;
  1083.     procedure ReadVariable;
  1084.     procedure SetFileName(Value: string);
  1085.   protected
  1086.     procedure InvokeEvent(var SourceInfo: TSourceInfo; Event: TLexicalEvent);
  1087.     procedure StandardEvent(Kind: TSourceKind; Event: TLexicalEvent);
  1088.     property Identifier: TPascalToken read FIdentifier;
  1089.     property Section: TPascalTokenKind read FSection;
  1090.   public
  1091.     constructor Create(Buffer: PChar = nil; Size: Integer = 0); override;
  1092.     destructor Destroy; override;
  1093.     procedure Analyze;
  1094.     procedure Reset;
  1095.     property FileName: string read FFileName write SetFileName;
  1096.     property UnitIdent: string read FUnitIdent;
  1097.     property UnitPath: string read FUnitPath;
  1098.     property OnArray: TLexicalEvent read FOnArray write FOnArray;
  1099.     property OnClass: TLexicalClassEvent read FOnClass write FOnClass;
  1100.     property OnClassReference: TLexicalEvent read FOnClassReference write FOnClassReference;
  1101.     property OnComment: TLexicalCommentEvent read FOnComment write FOnComment;
  1102.     property OnConstant: TLexicalEvent read FOnConstant write FOnConstant;
  1103.     property OnField: TLexicalEvent read FOnField write FOnField;
  1104.     property OnFunction: TLexicalEvent read FOnFunction write FOnFunction;
  1105.     property OnEvent: TLexicalEvent read FOnEvent write FOnEvent;
  1106.     property OnEnumeration: TLexicalEvent read FOnEnumeration write FOnEnumeration;
  1107.     property OnInterface: TLexicalInterfaceEvent read FOnInterface write FOnInterface;
  1108.     property OnInterfaceMethod: TLexicalEvent read FOnInterfaceMethod write FOnInterfaceMethod;
  1109.     property OnMethod: TLexicalEvent read FOnMethod write FOnMethod;
  1110.     property OnProcedure: TLexicalEvent read FOnProcedure write FOnProcedure;
  1111.     property OnProperty: TLexicalEvent read FOnProperty write FOnProperty;
  1112.     property OnRecord: TLexicalEvent read FOnRecord write FOnRecord;
  1113.     property OnRoutinePointer: TLexicalEvent read FOnRoutinePointer write FOnRoutinePointer;
  1114.     property OnSet: TLexicalEvent read FOnSet write FOnSet;
  1115.     property OnType: TLexicalEvent read FOnType write FOnType;
  1116.     property OnUses: TLexicalUsesEvent read FOnUses write FOnUses;
  1117.     property OnVariable: TLexicalEvent read FOnVariable write FOnVariable;
  1118.   end;
  1119.  
  1120. const
  1121.   ClassMembers = [skConstructor, skDestructor, skFunctionMethod,
  1122.     skProcedureMethod, skProperty];
  1123.   InterfaceMembers = [skFunctionInterfaceMethod, skProcedureInterfaceMethod];
  1124.  
  1125. function SourceKindToString(SourceKind: TSourceKind): string;
  1126.  
  1127. implementation
  1128.  
  1129. uses
  1130.   StrConst;
  1131.  
  1132. function KindToRoutine(Kind: TPascalTokenKind): TRoutineKind;
  1133. begin
  1134.   case Kind of
  1135.     tkConstructor:
  1136.       Result := rkConstructor;
  1137.     tkDestructor:
  1138.       Result := rkDestructor;
  1139.     tkFunction:
  1140.       Result := rkFunction;
  1141.   else
  1142.     Result := rkProcedure;
  1143.   end;
  1144. end;
  1145.  
  1146. const
  1147.   SourceKinds: array[TSourceKind] of TIdentMapEntry = (
  1148.     (Value: Ord(skArray); Name: 'array'),
  1149.     (Value: Ord(skClass); Name: 'class'),
  1150.     (Value: Ord(skClassReference); Name: 'class reference'),
  1151.     (Value: Ord(skConstant); Name: 'constant'),
  1152.     (Value: Ord(skConstructor); Name: 'constructor'),
  1153.     (Value: Ord(skDestructor); Name: 'destructor'),
  1154.     (Value: Ord(skEnumeration); Name: 'enumeration'),
  1155.     (Value: Ord(skEvent); Name: 'event'),
  1156.     (Value: Ord(skField); Name: 'field'),
  1157.     (Value: Ord(skFunction); Name: 'function'),
  1158.     (Value: Ord(skFunctionEvent); Name: 'function event'),
  1159.     (Value: Ord(skFunctionInterfaceMethod); Name: 'function interface method'),
  1160.     (Value: Ord(skFunctionMethod); Name: 'function method'),
  1161.     (Value: Ord(skFunctionPointer); Name: 'function pointer'),
  1162.     (Value: Ord(skInterface); Name: 'interface'),
  1163.     (Value: Ord(skInterfaceMethod); Name: 'interface method'),
  1164.     (Value: Ord(skMember); Name: 'member'),
  1165.     (Value: Ord(skMethod); Name: 'method'),
  1166.     (Value: Ord(skProcedure); Name: 'procedure'),
  1167.     (Value: Ord(skProcedureEvent); Name: 'procedure event'),
  1168.     (Value: Ord(skProcedureInterfaceMethod); Name: 'procedure interface method'),
  1169.     (Value: Ord(skProcedureMethod); Name: 'procedure method'),
  1170.     (Value: Ord(skProcedurePointer); Name: 'procedure pointer'),
  1171.     (Value: Ord(skProperty); Name: 'property'),
  1172.     (Value: Ord(skRecord); Name: 'record'),
  1173.     (Value: Ord(skresourceString); Name: 'resource string'),
  1174.     (Value: Ord(skSet); Name: 'set'),
  1175.     (Value: Ord(skThreadVariable); Name: 'thread variable'),
  1176.     (Value: Ord(skType); Name: 'type'),
  1177.     (Value: Ord(skVariable); Name: 'variable'),
  1178.     (Value: Ord(skUses); Name: 'uses'));
  1179.  
  1180. function SourceKindToString(SourceKind: TSourceKind): string;
  1181. begin
  1182.   IntToIdent(Ord(SourceKind), Result, SourceKinds);
  1183. end;
  1184.  
  1185. { TPascalLexer }
  1186.  
  1187. constructor TPascalLexer.Create(Buffer: PChar; Size: Integer);
  1188. begin
  1189.   inherited Create(Buffer, Size);
  1190.   ExceptionTokens := [tkImplementation, tkNull];
  1191.   FIdentifier := TPascalToken.Create(Self);
  1192.   FInterfaceList := TStringList.Create;
  1193.   FScratchToken := TPascalToken.Create(Self);
  1194.   FSection := tkNull;
  1195. end;
  1196.  
  1197. destructor TPascalLexer.Destroy;
  1198. begin
  1199.   FIdentifier.Free;
  1200.   FInterfaceList.Free;
  1201.   FScratchToken.Free;
  1202.   FileName := '';
  1203.   inherited Destroy;
  1204. end;
  1205.  
  1206. procedure TPascalLexer.Reset;
  1207. begin
  1208.   Initialize(InternalBuffer, InternalSize);
  1209.   FSection := tkNull;
  1210. end;
  1211.  
  1212. procedure TPascalLexer.Analyze;
  1213. var
  1214.   InterfaceSection: Boolean;
  1215. begin
  1216.   if Position <> 0 then
  1217.     Reset;
  1218.   InterfaceSection := False;
  1219.   repeat
  1220.     Next;
  1221.     case Token.Kind of
  1222.       tkConst, tkResourcestring, tkThreadvar, tkType, tkVar: FSection := Token.Kind;
  1223.       tkIdentifier:
  1224.         Identifier.Copy(Token);
  1225.       tkArray: ReadArray;
  1226.       tkFunction, tkProcedure:
  1227.         if Peek(CommentTokens) = tkIdentifier then
  1228.         begin
  1229.           FSection := Token.Kind;
  1230.           ReadRoutine;
  1231.         end
  1232.         else
  1233.           ReadRoutinePointer(KindToRoutine(Token.Kind));
  1234.       tkLeftParenthesis:
  1235.         ReadEnumeration;
  1236.       tkRecord:
  1237.         ReadRecord;
  1238.       tkSet:
  1239.         ReadSet;
  1240.       tkEqual:
  1241.         case FSection of
  1242.           tkConst, tkResourcestring: ReadConstant;
  1243.           tkType:
  1244.             if (Peek(CommentTokens + [tkPointerTo]) in [tkIdentifier, tkString, tkType]) then
  1245.               ReadType;
  1246.         end;
  1247.       tkColon:
  1248.         if (FSection in [tkConst, tkResourcestring, tkThreadvar,  tkVar]) and
  1249.           (Peek(CommentTokens) in [tkIdentifier,  tkString]) then
  1250.           case FSection of
  1251.             tkConst, tkResourcestring:
  1252.               ReadConstant;
  1253.             tkThreadvar, tkVar:
  1254.               ReadVariable;
  1255.           end;
  1256.       tkClass:
  1257.         case Peek(CommentTokens) of
  1258.           tkSemiColon:
  1259.             Scan([tkSemiColon]);
  1260.           tkOf:
  1261.             ReadClassReference;
  1262.         else
  1263.           ReadClass;
  1264.         end;
  1265.       tkInterface:
  1266.         if InterfaceSection then
  1267.           case Peek(CommentTokens) of
  1268.             tkSemiColon:
  1269.               Scan([tkSemiColon]);
  1270.           else
  1271.             ReadInterface;
  1272.           end
  1273.         else
  1274.           InterfaceSection := True;
  1275.       tkAnsiComment, tkCComment, tkPascalComment:
  1276.         ReadComment;
  1277.       tkUses:
  1278.         ReadUses;
  1279.     end;
  1280.   until Token.Kind in [tkImplementation, tkNull];
  1281. end;
  1282.  
  1283. procedure TPascalLexer.InvokeEvent(var SourceInfo: TSourceInfo;
  1284.   Event: TLexicalEvent);
  1285. var
  1286.   Body: string;
  1287. begin
  1288.   case FSection of
  1289.     tkConst:
  1290.       begin
  1291.         SourceInfo.Kind := skConstant;
  1292.         Event := FOnConstant;
  1293.       end;
  1294.     tkResourceString:
  1295.       begin
  1296.         SourceInfo.Kind := skResourceString;
  1297.         Event := FOnVariable;
  1298.       end;
  1299.     tkThreadVar:
  1300.       begin
  1301.         SourceInfo.Kind := skThreadVariable;
  1302.         Event := FOnVariable;
  1303.       end;
  1304.     tkVar:
  1305.       begin
  1306.         SourceInfo.Kind := skVariable;
  1307.         Event := FOnVariable;
  1308.       end;
  1309.   end;
  1310.   if Assigned(Event) then
  1311.   begin
  1312.     Body := CopyText(Identifier.Position, Token.Position + Token.Length -
  1313.       Identifier.Position);
  1314.     with SourceInfo do
  1315.     begin
  1316.       Line := Identifier.Row;
  1317.       Column := Identifier.Col;
  1318.       Name := Identifier.Text;
  1319.     end;
  1320.     Event(Self, Body, SourceInfo);
  1321.   end;
  1322. end;
  1323.  
  1324. procedure TPascalLexer.StandardEvent(Kind: TSourceKind; Event: TLexicalEvent);
  1325. var
  1326.   SourceInfo: TSourceInfo;
  1327.   I: Integer;
  1328. begin
  1329.   I := 0;
  1330.   repeat
  1331.     case Scan([tkEnd, tkRecord, tkLeftParenthesis, tkRightParenthesis,
  1332.       tkSemiColon]) of
  1333.       tkLeftParenthesis:
  1334.         Inc(I);
  1335.       tkRightParenthesis:
  1336.         Dec(I);
  1337.       tkEnd:
  1338.         begin
  1339.           Scan([tkSemiColon]);
  1340.           Dec(I)
  1341.         end;
  1342.       tkRecord:
  1343.         Inc(I);
  1344.     end;
  1345.   until (I = 0) and (Token.Kind = tkSemiColon);
  1346.   SourceInfo.Kind := Kind;
  1347.   InvokeEvent(SourceInfo, Event);
  1348. end;
  1349.  
  1350. procedure TPascalLexer.ReadArray;
  1351. var
  1352.   SourceInfo: TSourceInfo;
  1353.   I: Integer;
  1354. begin
  1355.   I := 0;
  1356.   repeat
  1357.     case Scan([tkLeftParenthesis, tkRightParenthesis, tkSemiColon]) of
  1358.       tkLeftParenthesis:
  1359.         Inc(I);
  1360.       tkRightParenthesis:
  1361.         Dec(I);
  1362.     end;
  1363.   until (I = 0) and (Token.Kind = tkSemiColon);
  1364.   SourceInfo.Kind := skArray;
  1365.   InvokeEvent(SourceInfo, FOnArray);
  1366. end;
  1367.  
  1368. function TPascalLexer.ReadCallingConvention: TCallingConvention;
  1369. begin
  1370.   Result := ccDefault;
  1371.   if (Peek(CommentTokens, FScratchToken) = tkIdentifier) then
  1372.     case StrToDirectiveKind(FScratchToken.Text) of
  1373.       dkCdecl: Result := ccCdecl;
  1374.       dkPascal: Result := ccPascal;
  1375.       dkRegister: Result := ccRegister;
  1376.       dkSafecall: Result := ccSafecall;
  1377.       dkStdcall: Result := ccStdcall;
  1378.     end;
  1379.   if Result <> ccDefault then
  1380.     Scan([tkSemiColon]);
  1381. end;
  1382.  
  1383. procedure TPascalLexer.ReadClass;
  1384. var
  1385.   Name: string;
  1386.   InheritedName: string;
  1387.   Visibility: TMemberVisibility;
  1388.   ClassMethod: Boolean;
  1389.  
  1390.   procedure ReadMethod;
  1391.   var
  1392.     SourceInfo: TSourceInfo;
  1393.     StartToken: TPascalToken;
  1394.     Start: Integer;
  1395.     Body: string;
  1396.   begin
  1397.     Start := 0;
  1398.     if Assigned(FOnMethod) then
  1399.     begin
  1400.       SourceInfo.ClassMethod := ClassMethod;
  1401.       if ClassMethod then
  1402.         StartToken := FScratchToken
  1403.       else
  1404.         StartToken := Token;
  1405.       SourceInfo.Line := StartToken.Row;
  1406.       SourceInfo.Column := StartToken.Col;
  1407.       Start := StartToken.Position;
  1408.       SourceInfo.ClassMethodKind := KindToRoutine(Token.Kind);
  1409.       case SourceInfo.ClassMethodKind of
  1410.         rkConstructor:
  1411.           SourceInfo.Kind := skConstructor;
  1412.         rkDestructor:
  1413.           SourceInfo.Kind := skDestructor;
  1414.         rkFunction:
  1415.           SourceInfo.Kind := skFunctionMethod;
  1416.         rkProcedure:
  1417.           SourceInfo.Kind := skProcedureMethod;
  1418.       end;
  1419.       Scan([tkIdentifier]);
  1420.       SourceInfo.Name := Token.Text;
  1421.       SourceInfo.ClassName := Name;
  1422.       SourceInfo.Visibility := Visibility;
  1423.       SourceInfo.Abstracted := False;
  1424.       SourceInfo.Reintroduced := False;
  1425.       SourceInfo.Overloaded := False;
  1426.     end;
  1427.     if Peek(CommentTokens) = tkLeftParenthesis then
  1428.       Scan([tkRightParenthesis]);
  1429.     Scan([tkSemiColon]);
  1430.     SourceInfo.VirtualKind := vkStatic;
  1431.     while Peek(CommentTokens, FScratchToken) = tkIdentifier do
  1432.       case StrToDirectiveKind(FScratchToken.Text) of
  1433.         dkAbstract:
  1434.           begin
  1435.             SourceInfo.Abstracted := True;
  1436.             Scan([tkSemiColon]);
  1437.           end;
  1438.         dkDynamic:
  1439.           begin
  1440.             SourceInfo.VirtualKind := vkDynamic;
  1441.             Scan([tkSemiColon]);
  1442.           end;
  1443.         dkMessage:
  1444.           begin
  1445.             SourceInfo.VirtualKind := vkMessage;
  1446.             Scan([tkSemiColon]);
  1447.           end;
  1448.         dkOverride:
  1449.           begin
  1450.             SourceInfo.VirtualKind := vkOverride;
  1451.             Scan([tkSemiColon]);
  1452.           end;
  1453.         dkVirtual:
  1454.           begin
  1455.             SourceInfo.VirtualKind := vkVirtual;
  1456.             Scan([tkSemiColon]);
  1457.           end;
  1458.         dkReintroduce:
  1459.           begin
  1460.             SourceInfo.Reintroduced := True;
  1461.             Scan([tkSemiColon]);
  1462.           end;
  1463.         dkOverload:
  1464.           begin
  1465.             SourceInfo.Overloaded := True;
  1466.             Scan([tkSemiColon]);
  1467.           end;
  1468.       else
  1469.         Break;
  1470.       end;
  1471.     if Token.Kind <> tkSemiColon then
  1472.       Scan([tkSemiColon]);
  1473.     SourceInfo.ClassMethodConvention := ReadCallingConvention;
  1474.     if Assigned(FOnMethod) then
  1475.     begin
  1476.       Body := CopyText(Start, Token.Position + Token.Length - Start);
  1477.       FOnMethod(Self, Body, SourceInfo);
  1478.     end;
  1479.   end;
  1480.  
  1481.   procedure ReadProperty;
  1482.   var
  1483.     Start: Integer;
  1484.     SourceInfo: TSourceInfo;
  1485.     ColonFound: Boolean;
  1486.     Body: string;
  1487.     I: Integer;
  1488.   begin
  1489.     Start := 0;
  1490.     if Assigned(FOnProperty) then
  1491.     begin
  1492.       Start := Token.Position;
  1493.       SourceInfo.Line :=  Token.Row;
  1494.       SourceInfo.Column := Token.Col;
  1495.       Scan([tkIdentifier]);
  1496.       SourceInfo.Name := Token.Text;
  1497.       SourceInfo.Kind := skProperty;
  1498.       SourceInfo.ClassName := Name;
  1499.       SourceInfo.Visibility := Visibility;
  1500.       SourceInfo.Access := [];
  1501.     end;
  1502.     ColonFound := False;
  1503.     I := 0;
  1504.     repeat
  1505.       case Scan([tkLeftBracket, tkRightBracket, tkIdentifier, tkColon,
  1506.         tkSemicolon]) of
  1507.         tkLeftBracket:
  1508.           Inc(I);
  1509.         tkRightBracket:
  1510.           Dec(I);
  1511.         tkIdentifier:
  1512.           if ColonFound and Assigned(FOnProperty) then
  1513.             case StrToDirectiveKind(Token.Text) of
  1514.               dkRead:
  1515.                 Include(SourceInfo.Access, paRead);
  1516.               dkWrite:
  1517.                 Include(SourceInfo.Access, paWrite);
  1518.             end;
  1519.         tkColon:
  1520.           if I = 0 then
  1521.            ColonFound := True;
  1522.       end;
  1523.     until (I = 0) and (Token.Kind = tkSemicolon);
  1524.     if ColonFound then
  1525.     begin
  1526.       SourceInfo.Default := False;
  1527.       if Peek(CommentTokens, FScratchToken) = tkIdentifier then
  1528.         SourceInfo.Default := StrToDirectiveKind(FScratchToken.Text) = dkDefault;
  1529.       if SourceInfo.Default then
  1530.         Scan([tkSemiColon]);
  1531.     end;
  1532.     if Assigned(FOnProperty) then
  1533.     begin
  1534.       SourceInfo.Promoted := not ColonFound;
  1535.       Body := CopyText(Start, Token.Position + Token.Length - Start);
  1536.       FOnProperty(Self, Body, SourceInfo);
  1537.     end;
  1538.   end;
  1539.  
  1540.   procedure ReadIdentifier;
  1541.   var
  1542.     Start: Integer;
  1543.     SourceInfo: TSourceInfo;
  1544.     Body: string;
  1545.   begin
  1546.     Start := 0;
  1547.     if Assigned(FOnField) then
  1548.     begin
  1549.       Start := Token.Position;
  1550.       SourceInfo.Line :=  Token.Row;
  1551.       SourceInfo.Column := Token.Col;
  1552.       SourceInfo.Name := Token.Text;
  1553.       SourceInfo.Kind := skField;
  1554.       SourceInfo.ClassName := Name;
  1555.       SourceInfo.Visibility := Visibility;
  1556.     end;
  1557.     Scan([tkSemiColon]);
  1558.     if Assigned(FOnField) then
  1559.     begin
  1560.       Body := CopyText(Start, Token.Position + Token.Length - Start);
  1561.       FOnField(Self, Body, SourceInfo);
  1562.     end;
  1563.   end;
  1564.  
  1565. var
  1566.   SourceInfo: TSourceInfo;
  1567.   Body: string;
  1568.   I: Integer;
  1569. const
  1570.   ClassTokens = [tkIdentifier, tkProperty, tkClass, tkConstructor, tkDestructor,
  1571.     tkFunction, tkProcedure, tkRecord, tkEnd];
  1572. begin
  1573.   Name := Identifier.Text;
  1574.   InheritedName := 'TObject';
  1575.   FInterfaceList.Clear;
  1576.   if Peek(CommentTokens) = tkLeftParenthesis then
  1577.   begin
  1578.     Scan([tkIdentifier]);
  1579.     InheritedName := Token.Text;
  1580.     while Scan([tkIdentifier, tkRightParenthesis]) = tkIdentifier do
  1581.       FInterfaceList.Add(Token.Text);
  1582.   end;
  1583.   ClassMethod := False;
  1584.   Visibility := mvPublished;
  1585.   I := 1;
  1586.   if Peek(CommentTokens) = tkSemiColon then
  1587.   begin
  1588.     Scan([tkSemiColon]);
  1589.     Dec(I);
  1590.   end;
  1591.   while I > 0 do
  1592.   begin
  1593.     case Scan(ClassTokens) of
  1594.       tkIdentifier:
  1595.         case StrToDirectiveKind(Token.Text) of
  1596.           dkPrivate:
  1597.             Visibility := mvPrivate;
  1598.           dkProtected:
  1599.             Visibility := mvProtected;
  1600.           dkPublic:
  1601.             Visibility := mvPublic;
  1602.           dkPublished:
  1603.             Visibility := mvPublished;
  1604.         else            
  1605.           ReadIdentifier;
  1606.         end;
  1607.       tkClass:
  1608.         begin
  1609.           ClassMethod := True;
  1610.           FScratchToken.Copy(Token);
  1611.           Continue;
  1612.         end;
  1613.       tkConstructor, tkDestructor, tkFunction, tkProcedure: ReadMethod;
  1614.       tkProperty: ReadProperty;
  1615.       tkRecord:
  1616.         Inc(I);
  1617.       tkEnd:
  1618.         begin
  1619.           Scan([tkSemiColon]);
  1620.           Dec(I);
  1621.         end;
  1622.     end;
  1623.     ClassMethod := False;
  1624.   end;
  1625.   if Assigned(FOnClass) then
  1626.   begin
  1627.     Body := CopyText(Identifier.Position, Token.Position + Token.Length -
  1628.       Identifier.Position);
  1629.     with SourceInfo do
  1630.     begin
  1631.       Line := Identifier.Row;
  1632.       Column := Identifier.Col;
  1633.       Name := Identifier.Text;
  1634.       Kind := skClass;
  1635.       ClassParent := InheritedName;
  1636.       InterfaceCount := FInterfaceList.Count;
  1637.     end;
  1638.     FOnClass(Self, Body, SourceInfo, InheritedName, FInterfaceList);
  1639.   end;
  1640. end;
  1641.  
  1642. procedure TPascalLexer.ReadComment;
  1643. begin
  1644.   if Assigned(FOnComment) then
  1645.     FOnComment(Self, Token.Text);
  1646. end;
  1647.  
  1648. procedure TPascalLexer.ReadConstant;
  1649. var
  1650.   SourceInfo: TSourceInfo;
  1651.   I: Integer;
  1652. begin
  1653.   I := 0;
  1654.   repeat
  1655.     case Scan([tkLeftParenthesis, tkRightParenthesis, tkSemiColon]) of
  1656.       tkLeftParenthesis:
  1657.         Inc(I);
  1658.       tkRightParenthesis:
  1659.         Dec(I);
  1660.     end;
  1661.   until (I = 0) and (Token.Kind = tkSemiColon);
  1662.   SourceInfo.Kind := skConstant;
  1663.   InvokeEvent(SourceInfo, FOnConstant);
  1664. end;
  1665.  
  1666. procedure TPascalLexer.ReadInterface;
  1667. var
  1668.   Name: string;
  1669.   InheritedName: string;
  1670.  
  1671.   procedure ReadInterfaceMethod;
  1672.   var
  1673.     SourceInfo: TSourceInfo;
  1674.     Start: Integer;
  1675.     Body: string;
  1676.   begin
  1677.     Start := 0;
  1678.     if Assigned(FOnInterfaceMethod) then
  1679.     begin
  1680.       SourceInfo.Line := Token.Row;
  1681.       SourceInfo.Column := Token.Col;
  1682.       Start := Token.Position;
  1683.       SourceInfo.InterfaceName := Name;
  1684.       SourceInfo.InterfaceMethodKind := KindToRoutine(Token.Kind);
  1685.       case SourceInfo.InterfaceMethodKind of
  1686.         rkFunction:
  1687.           SourceInfo.Kind := skFunctionInterfaceMethod;
  1688.         rkProcedure:
  1689.           SourceInfo.Kind := skProcedureInterfaceMethod;
  1690.       end;
  1691.       Scan([tkIdentifier]);
  1692.       SourceInfo.Name := Token.Text;
  1693.     end;
  1694.     if Peek(CommentTokens) = tkLeftParenthesis then
  1695.       Scan([tkRightParenthesis]);
  1696.     Scan([tkSemiColon]);
  1697.     SourceInfo.InterfaceMethodConvention := ReadCallingConvention;
  1698.     if Assigned(FOnInterfaceMethod) then
  1699.     begin
  1700.       Body := CopyText(Start, Token.Position + Token.Length - Start);
  1701.       FOnInterfaceMethod(Self, Body, SourceInfo);
  1702.     end;
  1703.   end;
  1704.  
  1705. var
  1706.   SourceInfo: TSourceInfo;
  1707.   Body: string;
  1708.   I: Integer;
  1709. const
  1710.   ClassTokens = [tkIdentifier, tkProperty, tkClass, tkFunction, tkProcedure,
  1711.     tkRecord, tkEnd];
  1712. begin
  1713.   Name := Identifier.Text;
  1714.   InheritedName := 'IUnknown';
  1715.   if Peek(CommentTokens) = tkLeftParenthesis then
  1716.   begin
  1717.     Scan([tkIdentifier]);
  1718.     InheritedName := Token.Text;
  1719.     Scan([tkRightParenthesis]);
  1720.   end;
  1721.   I := 1;
  1722.   if Peek(CommentTokens) = tkSemiColon then
  1723.   begin
  1724.     Scan([tkSemiColon]);
  1725.     Dec(I);
  1726.   end;
  1727.   while I > 0 do
  1728.     case Scan(ClassTokens) of
  1729.       tkFunction, tkProcedure: ReadInterfaceMethod;
  1730.       tkEnd:
  1731.         begin
  1732.           Scan([tkSemiColon]);
  1733.           Dec(I);
  1734.         end;
  1735.     end;
  1736.   if Assigned(FOnInterface) then
  1737.   begin
  1738.     Body := CopyText(Identifier.Position, Token.Position + Token.Length -
  1739.       Identifier.Position);
  1740.     with SourceInfo do
  1741.     begin
  1742.       Line := Identifier.Row;
  1743.       Column := Identifier.Col;
  1744.       Name := Identifier.Text;
  1745.       Kind := skInterface;
  1746.       InterfaceParent := InheritedName;
  1747.     end;
  1748.     FOnInterface(Self, Body, SourceInfo, InheritedName);
  1749.   end;
  1750. end;
  1751.  
  1752. procedure TPascalLexer.ReadClassReference;
  1753. var
  1754.   SourceInfo: TSourceInfo;
  1755. begin
  1756.   Scan([tkSemiColon]);
  1757.   SourceInfo.Kind := skClassReference;
  1758.   InvokeEvent(SourceInfo, FOnClassReference);
  1759. end;
  1760.  
  1761. procedure TPascalLexer.ReadEnumeration;
  1762. var
  1763.   SourceInfo: TSourceInfo;
  1764. begin
  1765.   Scan([tkSemiColon]);
  1766.   SourceInfo.Kind := skEnumeration;
  1767.   InvokeEvent(SourceInfo, FOnEnumeration);
  1768. end;
  1769.  
  1770. procedure TPascalLexer.ReadRecord;
  1771. var
  1772.   SourceInfo: TSourceInfo;
  1773.   I: Integer;
  1774. begin
  1775.   I := 1;
  1776.   while I > 0 do
  1777.     case Scan([tkEnd, tkRecord]) of
  1778.       tkEnd:
  1779.         begin
  1780.           Scan([tkSemiColon]);
  1781.           Dec(I)
  1782.         end;
  1783.       tkRecord:
  1784.         Inc(I);
  1785.     end;
  1786.   SourceInfo.Kind := skRecord;
  1787.   InvokeEvent(SourceInfo, FOnRecord);
  1788. end;
  1789.  
  1790. procedure TPascalLexer.ReadRoutine;
  1791. var
  1792.   SourceInfo: TSourceInfo;
  1793.   Event: TLexicalEvent;
  1794.   Start: Integer;
  1795. begin
  1796.   SourceInfo.RoutineKind := KindToRoutine(Section);
  1797.   Event := nil;
  1798.   case SourceInfo.RoutineKind of
  1799.     rkFunction:
  1800.       begin
  1801.         SourceInfo.Kind := skFunction;
  1802.         Event := FOnFunction;
  1803.       end;
  1804.     rkProcedure:
  1805.       begin
  1806.         SourceInfo.Kind := skProcedure;
  1807.         Event := FOnProcedure;
  1808.       end;
  1809.   end;
  1810.   if Assigned(Event) then
  1811.   begin
  1812.     Start := Token.Position;
  1813.     SourceInfo.Line := Token.Row;
  1814.     SourceInfo.Column := Token.Col;
  1815.   end
  1816.   else
  1817.     Start := 0;
  1818.   Scan([tkIdentifier]);
  1819.   if Assigned(Event) then
  1820.     SourceInfo.Name := Token.Text;
  1821.   if Peek(CommentTokens) = tkLeftParenthesis then
  1822.     Scan([tkRightParenthesis]);
  1823.   Scan([tkSemiColon]);
  1824.   SourceInfo.RoutineConvention := ReadCallingConvention;
  1825.   if Assigned(Event) then
  1826.     Event(Self, CopyText(Start, Token.Position + Token.Length - Start),
  1827.       SourceInfo);
  1828. end;
  1829.  
  1830. procedure TPascalLexer.ReadRoutinePointer(Kind: TRoutineKind);
  1831. var
  1832.   SourceInfo: TSourceInfo;
  1833.   MethodPointer: Boolean;
  1834. begin
  1835.   if Peek(CommentTokens) = tkLeftParenthesis then
  1836.     Scan([tkRightParenthesis]);
  1837.   MethodPointer := Scan([tkOf, tkSemiColon]) = tkOf;
  1838.   SourceInfo.RoutineKind := Kind;
  1839.   if MethodPointer then
  1840.   begin
  1841.     Scan([tkSemiColon]);
  1842.     case Kind of
  1843.       rkFunction: SourceInfo.Kind := skFunctionEvent;
  1844.       rkProcedure: SourceInfo.Kind := skProcedureEvent;
  1845.     end;
  1846.     SourceInfo.RoutineConvention := ReadCallingConvention;
  1847.     InvokeEvent(SourceInfo, FOnEvent);
  1848.   end
  1849.   else
  1850.   begin
  1851.     case Kind of
  1852.       rkFunction: SourceInfo.Kind := skFunctionPointer;
  1853.       rkProcedure: SourceInfo.Kind := skProcedurePointer;
  1854.     end;
  1855.     SourceInfo.RoutineConvention := ReadCallingConvention;
  1856.     InvokeEvent(SourceInfo, FOnRoutinePointer);
  1857.   end;
  1858. end;
  1859.  
  1860. procedure TPascalLexer.ReadSet;
  1861. var
  1862.   SourceInfo: TSourceInfo;
  1863. begin
  1864.   Scan([tkImplementation, tkNull, tkSemiColon]);
  1865.   SourceInfo.Kind := skSet;
  1866.   InvokeEvent(SourceInfo, FOnSet);
  1867. end;
  1868.  
  1869. procedure TPascalLexer.ReadType;
  1870. begin
  1871.   StandardEvent(skType, FOnType);
  1872. end;
  1873.  
  1874. procedure TPascalLexer.ReadUses;
  1875. var
  1876.   UsesList: TStrings;
  1877. begin
  1878.   if Assigned(FOnUses) then
  1879.   begin
  1880.     UsesList := TStringList.Create;
  1881.     try
  1882.       while Scan([tkIdentifier, tkSemiColon]) = tkIdentifier do
  1883.         UsesList.Add(Token.Text);
  1884.       FOnUses(Self, UsesList);
  1885.     finally
  1886.       UsesList.Free;
  1887.     end;
  1888.   end;
  1889. end;
  1890.  
  1891. procedure TPascalLexer.ReadVariable;
  1892. begin
  1893.   StandardEvent(skVariable, FOnVariable);
  1894. end;
  1895.  
  1896. procedure TPascalLexer.SetFileName(Value: string);
  1897. begin
  1898.   FMap.Free;
  1899.   if Value = '' then
  1900.     FMap := nil
  1901.   else
  1902.   begin
  1903.     FMap := TMemoryMappedFile.Create(Value);
  1904.     Initialize(PChar(FMap.ViewStart), Integer(FMap.ViewEnd - FMap.ViewStart));
  1905.     Scan([tkUnit]);
  1906.     Scan([tkIdentifier]);
  1907.     FUnitPath := Value;
  1908.     FUnitIdent := Token.Text;
  1909.   end;
  1910. end;
  1911.  
  1912. { root
  1913.    + units
  1914.    |  + name1
  1915.    |  |  + path
  1916.    |  |  + uses
  1917.    |  |     + unit1
  1918.    |  |     + unit2 ...
  1919.    |  |  + classes
  1920.    |  |     + class1
  1921.    |  |     + class2 ...
  1922.    |  + name2 ...
  1923.    + unknown ...
  1924.    }
  1925.  
  1926. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement