Press enter to see results or esc to cancel.

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;