Processing Used Units

Every Turbo Pascal module (program or unit) can use other units. Processing them is one of the trickiest parts of Turbo Pascal compiler.
Procedure SetModuleFlagsAndProcessUsedUnits;
begin
  ModuleHeadingEnded := True;
  If not (DebugInformation in ModuleCompilerSwitches) then Exclude (ModuleCompilerSwitches, LocalDebugSymbols);
  If not (LocalDebugSymbols in ModuleCompilerSwitches) then Exclude (ModuleCompilerSwitches, CompilerDirective_Y);
  With PUnitHeader (Ptr (MainSymbolTable.Segment, 0))^ do
    begin
      Flags := ModuleUnitFlags;
      If OverlaysAllowed in ModuleCompilerSwitches then Include (Flags, ufOverlaysAllowed);
      If Instructions80286 in ModuleCompilerSwitches then Include (Flags, ufInstructions80286);
    end;
  ProcessUsedUnits;
end;
Each unit listed in the Uses statement is added to the symbol table and linked in a list of used units.
Procedure ProcessUsedUnits;
Var IdLen: Byte;
    UsesClause: Boolean;
    CurrentUnit: PUnitHeader;
    UnitIdentifierData: PUnitIdentifierData;

  Procedure AddUnitNameIdentifierToList;
  Var UnitIdentifierData: PUnitIdentifierData;
      UnitIdentifier: PIdentifier;
  begin
    UnitIdentifierData := StoreNewIdentifierToSymbolTable (9, UnitIdentifier);
    UnitIdentifier^.Token := Token_UnitIdentifier;
    PUnitIdentifierData (Ptr (Seg (UnitIdentifier^), LastUnitIdentifierData))^.NextUnitIdentifier :=
      Ofs (UnitIdentifier^);
    LastUnitIdentifierData := Ofs (UnitIdentifierData^);
    UnitIdentifierData^.CurrentUsedUnitIdentifier := LastUsedUnitIdentifier;
    LastUsedUnitIdentifier := Ofs (UnitIdentifier^);
    If SourceType = stUnitInterface then UnitIdentifierData^.UnitIdentifierFlags := [UsedInInterface];
  end;

  Procedure CreatePrivateIdentifiersList;
  Var Hash: Byte;
      UnitHeader: PUnitHeader;
      IdentifierList: PIdentifierList;
      IdentifierOffset: Word;

  begin
    UnitHeader := Ptr (MainSymbolTable.Segment, 0);
    IdentifierList := Ptr (MainSymbolTable.Segment, UnitHeader^.PublicIdentifiersListOffset);
    UnitHeader^.PrivateIdentifiersListOffset := Ofs (IncreaseSymbolTable (stMain, IdentifierList^.Mask + 4)^);
    Move (IdentifierList^, Ptr (Seg (UnitHeader^), UnitHeader^.PrivateIdentifiersListOffset)^, IdentifierList^.Mask + 4);
    For Hash := 0 to IdentifierList^.Mask div 2 do
      begin
        IdentifierOffset := Ofs (IdentifierList^.Offset [Hash]);
        Repeat
          IdentifierOffset := PIdentifier (Ptr (Seg (UnitHeader^), IdentifierOffset))^.Next;
        until IdentifierOffset < IdListOffsetBeforeImplementationUsedUnits;
        IdentifierList^.Offset [Hash] := IdentifierOffset;
      end;
  end;

begin
  CurrentUnit := Ptr (MainSymbolTable.Segment, 0);
  IdLen := PIdentifier (Ptr (MainSymbolTable.Segment, CurrentUnit^.UnitNameIdentifierOffset))^.Name.Len;
  UnitIdentifierData := Ptr (MainSymbolTable.Segment, CurrentUnit^.UnitNameIdentifierOffset + IdLen + 4);
  LastUsedUnitIdentifier := UnitIdentifierData^.CurrentUsedUnitIdentifier;
  IdListOffsetBeforeImplementationUsedUnits := MainSymbolTable.UsedSize;
  If not SystemUnitCompilation and (SourceType <> stUnitImplementation) then
    begin
      CopyStringToCurrentIdentifier (_System.Text);
      AddUnitNameIdentifierToList;
    end;
  UsesClause := False;
  If CheckAndGetNextToken (Token_USES) then
    begin
      UsesClause := True;
      Repeat
        ExpectIdentifier;
        AddUnitNameIdentifierToList;
        GetNextToken;
      until not CheckAndGetNextToken (Token_Comma);
    end;
  If SourceType = stUnitImplementation then CreatePrivateIdentifiersList;
  LoadUsedUnits;
  If UsesClause then ExpectTokenAndGetNext (Token_Semicolon);

  CurrentUnit := Ptr (MainSymbolTable.Segment, 0);
  IdLen := PIdentifier (Ptr (MainSymbolTable.Segment, CurrentUnit^.UnitNameIdentifierOffset))^.Name.Len;
  UnitIdentifierData := Ptr (MainSymbolTable.Segment, CurrentUnit^.UnitNameIdentifierOffset + IdLen + 4);

  UnitIdentifierData^.CurrentUsedUnitIdentifier := LastUsedUnitIdentifier;
  If not SystemUnitCompilation then
    begin
      IdLen := PIdentifier (Ptr (MainSymbolTable.Segment, UnitIdentifierData^.NextUnitIdentifier))^.Name.Len;
      UnitIdentifierData := Ptr (MainSymbolTable.Segment, UnitIdentifierData^.NextUnitIdentifier + IdLen + 4);
    end;
  SystemUnitSegment := UnitIdentifierData^.UnitSegment;
end;

 
 
 
© 2017 Turbo Pascal | Privacy Policy