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

📄 usinglefileparser.pas

📁 DelphiDoc is a program for automatic generation of documentation on a Delphi-Project. At the momen
💻 PAS
📖 第 1 页 / 共 2 页
字号:
const     TopWordsFunctions = [1, 3, 4, 8, 12];
//reserved word for exporting of identifiers
//4: exports
const     TopWordsExports = 6;
//all reserved words, that end the file/a part of the file
//6: interface, implementation, initialization, finalization, begin, end.
const     TopWordsFileParts = [0, 5, 7, 9, 10, 11];
//all reserved words, that end the file
//4: initialization, finalization, begin, end.
const     TopWordsFileEnds = TopWordsFileParts - [9, 11];


          //list of possible kinds of declarations
type      TDefType = (
            dtNone,             //no kind of declarations set
            dtType,             //type declarations follow
            dtResString,        //resource strings follow
            dtConst,            //constants follow
            dtVar,              //variables follow
            dtThreadVar);       //thread variables follow

var       DefType          :TDefType;  //current kind of declarations
          //number of identifiers when a new block of type declarations is
          TypeStartIndex   :Integer;   //started (for forward references)

 {Changes the kind of following declarations. Handles the parsing of forward
  references when a block of type declarations is started or ended
 ~param NewDefType the new kind of declarations }
 procedure ChangeDefType(NewDefType: TDefType);
 begin
  if DefType = dtType then                 //old kind was type?
   TypeBlockHasEnded(TypeStartIndex);        //parse the block
  DefType := NewDefType;                   //set new kind
  if DefType = dtType then                 //new kind is type?
   TypeStartIndex := FActualIdents.Count;    //save number of identifiers
 end;


var       Token            :String;        //a token
          Index            :Integer;       //index of token in array TopWords
          //if the end of the content that should be parsed has been reached
          Finished         :Boolean;

          BeforeStartIndex :Integer;       //the number of declared identifiers

          IsClassFunc      :Boolean;       //class function found?
          FunctionKind     :TFunctionKind; //kind of function found
begin
 FActualIdents := FThisFile.Idents;        //add identifiers to the globals
 FActualScopeIdents := FActualIdents;      //also enumeration items
 DefType := dtNone;                        //no kind of declaration set

 BeforeStartIndex := FActualIdents.Count;  //save number of identifiers

 Finished := False;
 while not Finished and GetToken(Token) do //while the end has not been reached
  begin
   if IsWordIn(Token, TopWords, Index) then  //found a reserved word?
    begin
     if Index in TopWordsDeclType then        //sets the kind of declarations?
      case Index of
        2:   ChangeDefType(dtConst);
        13:  ChangeDefType(dtResString);
        14:  ChangeDefType(dtThreadVar);
        15:  ChangeDefType(dtType);
        17:  ChangeDefType(dtVar);
      else
        raise SysUtils.Exception.CreateFmt('Invalid Word-Index: %d; change and recompile DelphiDoc!',
                                           [Index]);
      end
     else
      begin
       ChangeDefType(dtNone);                 //no declarations follow
       if Index in TopWordsFunctions then     //function declaration?
        begin
         IsClassFunc := Index = 1;              //is a class function?
         if IsClassFunc then
          if not GetToken(Token) or not IsWordIn(Token, TopWords, Index) or
             not (Index in [8, 12]) then          //get next token
           Exception(etSyntax,
                     'Expected "function" or "procedure" after "class"; failed!');

         case Index of                          //set kind of function
           3:   FunctionKind := fkConstructor;
           4:   FunctionKind := fkDestructor;
           8:   FunctionKind := fkFunction;
           12:  FunctionKind := fkProcedure;
         else
           raise SysUtils.Exception.CreateFmt('Invalid Word-Index: %d; change and recompile DelphiDoc!', [Index]);
         end;

         if not InterfacePart then
          begin
           AfterDefinition(BeforeStartIndex);   //parse all new identifiers
           BeforeStartIndex := FActualIdents.Count;
          end;

         //parse the function
         ParseFunction(FunctionKind, IsClassFunc, FScope = sInterface);


         if not InterfacePart then
          begin
           AfterDefinition(BeforeStartIndex);   //parse all new identifiers
           BeforeStartIndex := FActualIdents.Count;
          end;

         SkipSemicolon;
        end
       else
        if Index = TopWordsExports then         //is export clause?
         ParseExportsClause
        else
         if Index in TopWordsFileParts then //end of a part of the file reached?
          begin
           if Index = 9 then                  //implementation found?
            begin
             FScope := sImplementation;       //set scope
             //save position
             FThisFile.ImplementationStart := AbsoluteLastTokenStartPos;
             TestReadUsesClause(fpMain);      //read implementation uses-clause
             Finished := True;                //and finish parsing (this part)
            end
           else
            if Index in TopWordsFileEnds then //end/begin/initialization found
             begin
              //parse everything after initialization, finalization or begin
              if Index <> 5 then
               begin
                AfterDefinition(BeforeStartIndex); //parse all new identifiers
                BeforeStartIndex := FActualIdents.Count;
                ParseEndOfFileSections(Token);     //parse up to the end.
               end;
              //the end has to be followed by the final .
              if not GetToken(Token) or (Token <> '.') then
               Exception(etSyntax,
                         '"." after "end" expected at end of file, failed!');
              Finished := True;               //and finish parsing the file
              if GetToken(Token) then
               WarningMessage(etSyntax, 'Tokens found after final "end."!');
             end;
          end
         else
          if Index = 16 then                  //uses found?
           Exception(etSyntax,
                     '"uses" found not at the beginning of the part of the file.')
          else
           raise SysUtils.Exception.CreateFmt('Invalid Word-Index: %d; change and recompile DelphiDoc!',
                                              [Index]);
      end;
    end
   else
    begin
     case DefType of                                //an identifier is declared
      dtType:      Token := ParseTypeIdentifier(Token);
      dtResString: Token := ParseResourceString(Token);
      dtConst:     Token := ParseConstant(Token);
      dtVar,
      dtThreadVar: Token := ParseVariable(Token, DefType = dtThreadVar);
     else
      Exception(etSyntax,
                'Unknown word "' + Token + '" or identifier not in a declaration block!');
     end;
     if Token <> ';' then
      Exception(etSyntax, '";" expected after declaration, failed');
    end;
  end;
 if not InterfacePart then
  AfterDefinition(BeforeStartIndex);         //parse all new identifiers

{$IFOPT C+}
 assert(PositionStackEmpty);
{$ENDIF}
end;























{Recognizes the kind of the file and parses the first uses clause. If it is a
 package ~[link DoParsePackage] is called to parse the whole file. }
procedure TSingleFileParser.ParseFirstUsesClause;
var       Token            :String;        //a token
          FileName         :String;        //name of the file
          Index            :Integer;       //index of the word
          BothClauses      :TUsesClauses;  //to set the uses clauses
begin
 DoCheckParseState(psUninitialized);  //check if correct state of parsing

 PushPosition;                        //save position in case no kind of file
 if not GetToken(Token) then
  ExceptionAtStart(etSyntax, 'File to parse is empty!');

 if IsWordIn(Token, FileStartWords, Index) then //kind of file specified?
  begin
   LosePosition;                        //delete saved position
   //set kind of file
   FThisFile.FileType := FileStartWordTypes[TSourceFileType(Index)];

   //get internal name of the file
   if not GetIdentWithPointsToken(FileName) { or
      not IsValidIdentifierName(FileName)   } then
    Exception(etSyntax,
              'Missing or invalid name of file after "' + Token + '"!');

   FThisFile.InternalFileName := FileName;

   if FThisFile.FileType = sftUnit then //is a unit?
    begin
     Token := LowerCase(FileName);
     BothClauses := FThisFile.UsesClauses;
     if Token = 'system' then             //check, if it is a default unit
//      BothClauses[fpInterface] := 'SysInit , '
     else
      if Token = 'sysinit' then
       BothClauses[fpInterface] := 'System , '
      else
       //add the default units to the uses clause
       BothClauses[fpInterface] := 'System , SysInit , ';
     FThisFile.UsesClauses := BothClauses;
    end
   else
    if FThisFile.FileType <> sftPackage then  //is a program or library?
     begin
      BothClauses := FThisFile.UsesClauses;
      //add the units to the uses clause
      BothClauses[fpInterface] := 'System , SysInit , ';
      FThisFile.UsesClauses := BothClauses;
     end;


   PushPosition;                         //save current position
   Token := ReadOwnPortabilityIssues;    //read portability issues
   if Token = '(' then                   //parameters for program?
    begin
     PopPosition;                          //return to position

     if FThisFile.FileType <> sftProgram then //is a program?
      WarningMessage(etSyntax,
                     'Parameters found for file, but is no program!');

     repeat                                //skip all directives
       GetBalancedToken(Token);             //and read the parameters
       assert(Token <> '');
     until Token[1] = '(';

     FThisFile.ProgramParameters := Token; //save parameters

     Token := ReadOwnPortabilityIssues;    //read following directives
    end
   else
    LosePosition;

   if Token <> ';' then
    Exception(etSyntax, 'Expected ";" after first statement of the file!');

  end
 else                                 //no type of file given
  begin
   FThisFile.FileType := sftProgram;    //it's a program
   //internal name (seems to be the default)
   FThisFile.InternalFileName := 'program';

   PopPosition;                         //restore save position

   BothClauses := FThisFile.UsesClauses;
   //add the units to the uses clause
   BothClauses[fpInterface] := 'System , SysInit , ';
   FThisFile.UsesClauses := BothClauses;
  end;


 if FThisFile.FileType = sftPackage then     //if it is a package
  DoParsePackage                               //parse it
 else
  if FThisFile.FileType = sftUnit then         //if it is a unit
   begin                                         //read interface
    if not GetToken(Token) or (LowerCase(Token) <> 'interface') then
     Exception(etSyntax, 'Expected "interface" at start of "unit"-file!');
    FScope := sInterface;                        //set scope

    PreParseThisUnit;                            //before parsing it ...
    TestReadUsesClause(fpInterface);             //read the uses-clause
   end
  else
   begin
    FScope := sImplementation;                   //set default scope
    TestReadUsesClause(fpMain);                  //read the uses-clause
   end;
 FGlobalScope := FScope;                     //set also the global scope

 FParseState := psInterfaceUsesClauseParsed; //set new state of parsing
end;


{The interface section is parsed if it is a unit. Nothing is done if it is not
 a unit.}
procedure TSingleFileParser.ParseInterface;
begin
 DoCheckParseState(psInterfaceUnitsParsed); //check if correct state of parsing

 if FThisFile.FileType = sftUnit then       //it is a unit?
  DoParseFile(True);                  //parse the interface-section of the unit

 FParseState := psInterfaceParsed;          //set new state of parsing
end;

{Parses the implementation section of units and the contents of program or
 library files. If it is a package nothing is done. }
procedure TSingleFileParser.ParseImplementations;
begin
 //check if correct state of parsing
 DoCheckParseState(psInterfaceClassHierarchyChecked);

 //if it is a package, it has already been parsed completely
 if FThisFile.FileType <> sftPackage then   //if it is not,
  DoParseFile(False);              //parse the code in the remnant of the file

 FParseState := psImplementationParsed;     //set new state of parsing
end;


{Checks if correct state while parsing and raises an error if not. This is
 more like a debug check.
~param DemandedState the state the parsing should have reached at the moment
~exception SysUtils.Exception if the state should be checked and doesn't match
                              the demanded state }
procedure TSingleFileParser.DoCheckParseState(DemandedState: TParseState);
begin
 //should be checked, and is not correct state?
 if FCheckParseState and (DemandedState <> FParseState) then
  //raise this error
  raise SysUtils.Exception.CreateFmt('DelphiDoc internal error! Change and recompile DelphiDoc: Invalid state while parsing: expected %d, is %d!',
                                     [ord(DemandedState), ord(FParseState)]);
end;


end.

⌨️ 快捷键说明

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