Press enter to see results or esc to cancel.

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.

Each unit listed in the Uses statement is added to the symbol table and linked in a list of used units.

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;
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;