WITH Statement
This procedure processes With
statement. It expects Record
or Object
variable and stores its data to a linked list. The calculated address is stored on the stack frame for further use. Turbo Pascal generates intermediate code which can be optimized for redundant ES:DI
address loadings. Therefore, this procedure generates appropriate instructions to mark the address that is loaded into ES:DI
register pair.
Procedure TStatement.Process_WITH_Statement;
Var VariableReference: TExpression;
WithStatement: TStatement;
Saved_LastWithRecord, SaveAddressSubroutine: Word;
IntermediateCodeOffsets: TIntermediateCodeOffsets;
VariableReferenceSegment: Byte;
IntermediateCodeRecord: PIntermediateCodeRecord;
WithRecord: PWithRecord;
begin
GetNextToken;
Saved_LastWithRecord := LastWithRecord;
IntermediateCodeOffsets.NumberOfStatements := 0;
Repeat
VariableReference.ExpectVariableReference;
Case VariableReference.TypeDefPtr^.BaseType of
btRecord,
btObject:
else Error (RecordOrObjectVariableExpected);
end;
Asm
SUB SP, TYPE TWithRecord;
end;
WithRecord := Ptr (SSeg, SPtr);
WithRecord^.PreviousWithRecord := LastWithRecord;
LastWithRecord := Ofs (WithRecord^);
WithRecord^.RecordTypeDefinition := PRecordTypeDefinition (VariableReference.TypeDefPtr);
With VariableReference, WithRecord^ do
If (LocationData.Flags * [segSS, segDS] <> []) and not (ofsDI in LocationData.Flags) then
begin
RecordType := 1;
ExpressionFlags := LocationData.Flags;
AddressOffset := Value.Offset;
BlockRecord := Value.BlockRecord;
AddressSegment := Value.Segment;
end else begin
RecordType := 2;
ExpressionFlags := LocationData.Flags * [efSegment] + [ofsDI, segES];
AddressOffset := CreateTempStackFrameSpace (4);
GenerateInstructionForStackFrameDisplacement (MOV_16Bit, SS_BP_Displacement_DI, AddressOffset);
GenerateInstructionForStackFrameDisplacement ($8C, $06, AddressOffset + 2);
SaveAddressSubroutine := EndSubroutine;
Calculate;
VariableReferenceSegment := Load_DI_AndReturnSegment;
If VariableReferenceSegment <> Segment_ES then
GenerateInstruction_TwoBytes (VariableReferenceSegment or $06, $07);
IntermediateCodeRecord := IncreaseSymbolTable (stIntermediateCode, 10);
BlockRecord := Ofs (IntermediateCodeRecord^);
With IntermediateCodeRecord^ do
begin
RecordType := icSkippedGoSubSaveAddress;
SaveAddress := SaveAddressSubroutine;
end;
Inc (PChar (IntermediateCodeRecord), 3);
With IntermediateCodeRecord^ do
begin
RecordType := ic_ES_DI_Loaded;
DestinationProcedure := CurrentProcedureIdentifier;
Displacement := AddressOffset;
SaveAddressCode := 0;
end;
AddCallToIntermediateCodeSubroutine (IntermediateCodeOffsets, EndSubroutine);
end;
until not CheckAndGetNextToken (Token_Comma);
ExpectTokenAndGetNext (Token_DO);
WithStatement.ProcessStatement;
AddCallToIntermediateCodeSubroutine (IntermediateCodeOffsets, WithStatement.StatementCode);
LastWithRecord := Saved_LastWithRecord;
Generate_icGoSub_ForEachSubroutine (IntermediateCodeOffsets);
StatementCode := EndSubroutine;
end;