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;