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