⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uicdeclarationassembler.pas

📁 DelphiDoc is a program for automatic generation of documentation on a Delphi-Project. At the momen
💻 PAS
📖 第 1 页 / 共 3 页
字号:






{Assembles the declaration of the identifier.
~param Identifier the identifier to assemble the declaration of }
procedure TICDeclarationAssembler.GetDeclaration(Identifier: TIdentifier);
begin
 PrepareAssembling;                     //create new, empty declaration

 inherited GetDeclaration(Identifier);  //assemble the declaration

 CheckText;                             //check for any cached/buffered text
end;

{Assembles the declaration of a part of an identifier.
~param Identifier the identifier to assemble the declaration of
~param Expr       an expression as part of the declaration of the identifier }
procedure TICDeclarationAssembler.GetDeclarationPart(Identifier: TIdentifier;
                                                     const Expr: String);
begin
 PrepareAssembling;                     //create new, empty declaration

 SetSourceIdentifier(Identifier);       //set the identifier
 ExprText(Expr);                        //assemble the expression

 CheckText;                             //check for any cached/buffered text
end;



{Will be called for all reserved words.
~param Word a string of one ore more reserved words }
procedure TICDeclarationAssembler.ReservedWord(const Word: String);
begin
 AddPascalToken(Word, icpcReservedWord);     //add a node for the reserved word
end;

{Will be called for all texts of identifiers.
~param Text a text with an identifier (or multiple separated by ".") }
procedure TICDeclarationAssembler.IdentifierText(const Text: String);
begin
 AddPascalToken(Text, icpcIdentifier);       //add name of the identifier
end;

{Will be called for all names of identifier-type identifiers. This means it
 will be called by the class ~[linkClass TIdentType] for any known type
 identifier. Normally a link on the identifier should be generated with the
 text Ident.~[link TIdentifier.Name Name].
~param Ident a type identifier to that a link should be generated }
procedure TICDeclarationAssembler.TypeIdentifierText(Ident: TIdentifier);
begin
 CreateLink(Ident);                          //add link to the type
end;

(*
{Will be called for a text of a type identifier. If the identifier is known it
 will call ~[link TypeIdentifierText] instead. Because the type is not known
 only it name could be shown.
~param TypeStr the text of the type identifier }
procedure TICDeclarationAssembler.TypeText(TypeStr: String);
begin
 IdentifierText(TextStr);            //treat as normal unknown identifier
end;
*)

{Will be called for all expressions, for instance like used as the index of an
 array or the value of a constant. The text should be parsed and identifiers
 should be underlaid with a link to their declaration if possible.
~param ExprStr the text of the expression
~todo reimplement, I'm not really happy with it, but it does work in most
      cases
~todo FileGiven has to check for Unit-Aliases! }
procedure TICDeclarationAssembler.ExprText(const ExprStr: String);
var       SourceRec    :TRecordType;     //current record-like type
          State        :(                //general state in the expression
                         sNo,            //after operator or similar character
                         sIdent,         //after an identifier (or dot)
                         sBrace,         //after a opening brace or bracket
                         sString);       //after a string

          Parser       :TTokenParser;    //parser of the expression
          Token        :String;          //a token in the expression
          Next         :String;          //the next token after an identifier
          FileGiven    :Boolean;         //file of identifier was given

          Position     :TPosition;       //position to start search
          Ident        :TIdentifier;     //identifiers in the expression
          dot          :Integer;         //index of a "." in the token

          //file of record-like type to search identifiers in
          RecIdent     :TRecordType;     //used record-like type
          IdentName    :String;          //a used member of a record-like type
begin
 Assert(Assigned(SourceIdent));
 Assert(Assigned(SourceIdent.InFile));

 if SourceIdent is TRecordType then       //get current record-like type
  SourceRec := TRecordType(SourceIdent)     //is is one, use it
 else
  SourceRec := SourceIdent.MemberOf;        //use its record-like type

 if Assigned(SourceIdent) then           //get position to search from
  begin
   if SourceIdent is TRecordType then      //if it is a record-like type
    Position := SourceIdent.Position         //use its position
   else
    Position := SourceIdent.ForwardDefPos;   //use always the first declaration
  end
 else
  begin
   Position.Row := -1;                     //search from the beginning
   Position.Column := 1;
  end;


 Parser := TTokenParser.Create;          //create tokenizer
 try
   Parser.PascalDialect := SourceIdent.InFile.PascalDialect;

   Parser.ParseString(ExprStr);          //parse expression text

   State := sNo;                         //begin without a special state
   while Parser.GetIdentWithPointsToken(Token) do //parse each token
    begin                                  //is an identifier?
     if (Token <> '') and (Token[1] in StartIdentifierChars) then
      begin
       State := sIdent;                      //next token is after identifier
       if LowerCase(Token) = 'nil' then      //is nil?
        AddPascalToken(Token, icpcReservedWord) //just add to the expression
       else
        begin
         Text(' ');                            //add a space before it

         Parser.PushPosition;
         Parser.GetToken(Next);                //preview the following token
         Parser.PopPosition;
         //not initialization of a record, i.e. a field of the record?
         if Next <> ':' then
          begin
           dot := Pos('.', Token);

           if Assigned(SourceRec) then            //is in a record-like type?
            begin
             if dot = 0 then
              dot := Length(Token) + 1;

             //search the identifier in it by this name
             Ident := SourceRec.IdentList.GetIdentByName(copy(Token, 1,
                                                              dot - 1));
             if Assigned(Ident) then
              begin
               CreateLink(Ident);                     //add link to it
               Delete(Token, 1, dot);                 //remove identifier
              end
             else
              dot := Pos('.', Token);
            end
           else
            Ident := nil;                           //not found so far

           if not Assigned(Ident) then
            begin
             //search the identifier by this name (globally)
             Ident := FGenerator.FindIdentifier(Token, SourceIdent.InFile,
                                                Position);

             if Assigned(Ident) then               //the identifier found?
              begin
               FileGiven := (dot <> 0) and           //file name given?
                            (Length(Ident.InFile.InternalFileName) =
                             dot - 1) and
                            (CompareText(Ident.InFile.InternalFileName,
                                         Copy(Token, 1, dot - 1)) = 0);
               if dot = 0 then          //get full length of identifier or file
                dot := Length(Token) + 1;


               CreateLink(Ident, FileGiven);        //create link to identifier

               if FileGiven then                     //if file given
                begin
                 Delete(Token, 1, dot);                //delete it
                 dot := Pos('.', Token);
                 if dot = 0 then
                  dot := Length(Token);
                end;
               Delete(Token, 1, dot);                //delete the identifier
              end;
            end;

           if Assigned(Ident) then               //something found?
            begin
             //while members follow
             while (Token <> '') and (Ident is TRecordType) do
              begin
               dot := Pos('.', Token);
               if dot = 0 then                       //get next member
                IdentName := Token
               else
                IdentName := Copy(Token, 1, dot - 1);

               RecIdent := TRecordType(Ident);       //search the member
               Ident := RecIdent.FindMember(IdentName, SourceIdent.InFile,
                                            False);
               if Assigned(Ident) then               //member found?
                begin
                 if dot = 0 then                       //delete it
                  Token := ''
                 else
                  Delete(Token, 1, dot);

                 Text('.');
                 CreateLink(Ident);                    //append a link to it
                end;
              end; //while Token <> '' and Ident is TRecordType

             if Token <> '' then                   //add any unknown members
              begin
               Text('.');
               IdentifierText(Token);                //add the text
              end;
            end //if assigned(Ident)
           else
            IdentifierText(Token); //append text
          end //if Next <> ':'   //record-field initialization?
         else
          //link on field of record would be nice, but would have to know the
          //record, hard if its an array of record or record of array etc.
          IdentifierText(Token);
        end //if not 'nil'
      end //if identifier or reserved word
     else
      begin
       if (State <> sBrace) and              //no space after opening brace
          ((Length(Token) <> 1) or           //not a single special character?
           (not (Token[1] in [',', '.', '(', ')', ']']) and
            ((Token[1] <> '[') or (State <> sIdent)))) and
          //no spaces between parts of strings
          ((State <> sString) or not (Token[1] in ['''', '#', '^'])) then
        Text(' ');                                  //add a separating space

       if Token[1] = '''' then               //is a string?
        AddPascalToken(Token, icpcString)      //add formatted as string
       else
        Text(Token);                           //add text

       //get state of the expression after this last token
       if Token[1] in ['(', '['] then
        State := sBrace
       else
        if (Token[1] in ['''', '#']) or
           ((Token[1] = '^') and (State <> sIdent)) then
         State := sString
        else
         if Token[1] in [')', ']', '.', '^'] then
          State := sIdent
         else
          State := sNo;

       //needs a second token?

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -