Press enter to see results or esc to cancel.

FOR Statement

This procedure processes For statement. It expects assignable variable and loop limits. It generates intermediate code to assign lower limit to control variable, code to increment control variable and code to check for upper limit taking into account Break and Continue jumps.

Procedure TStatement.Process_FOR_Statement;
Type TForStatementData = Record
                           NoLoopComparisonOperation: TCalcOperation;
                           IntegerOpCode,
                           LongIntOpCode_Lo,
                           LongIntOpCode_Hi: Byte;
                         end;

Const ForStatementData_TO: TForStatementData     = (NoLoopComparisonOperation: Calc_IsGreater;
                                                    IntegerOpCode: $00;
                                                    LongIntOpCode_Lo: mod_ADD_rm;
                                                    LongIntOpCode_Hi: mod_ADC_rm);
      ForStatementData_DOWNTO: TForStatementData = (NoLoopComparisonOperation: Calc_IsLower;
                                                    IntegerOpCode: $08;
                                                    LongIntOpCode_Lo: mod_SUB_rm;
                                                    LongIntOpCode_Hi: mod_SBB_rm);

Var SavedLastJumpOutOfBlock, SavedLastJumpToNextBlockIteration: Word;
    JumpToLoopStatement: Word;
    ForStatementData: TForStatementData;
    FOR_Variable, StartValue, EndValue, LoopRepeatComparison, NoLoopComparison, TempStartValue: TExpression;
    LoopStatement: TStatement;

  Procedure Expect_FOR_LoopLimit (Var Expression: TExpression);
  begin
    With Expression do
      begin
        ExpectOrdinalExpression;
        CheckTypeCompatibility (FOR_Variable.TypeDefPtr);
        CheckRange (FOR_Variable.TypeDefPtr);
      end;
  end;

  Procedure Compare_FOR_Variable (Operation: TCalcOperation; Var LeftExpression: TExpression; RightExpression: TExpression);
  begin
    RightExpression.IntermediateCodeOffset := 0;
    CalculateOperation (Operation, LeftExpression, RightExpression);
    With LeftExpression do If Location <> elConstant then
      begin
        Calculate;
        GenerateCodeForNearJump (Value.LastJumpToTrue, LocationData.JumpIfTrueOpCode);
        GenerateLabelAndSetJumpsToIt (Value.LastJumpToFalse);
        EndIntermediateCodeSubroutine
      end;
  end;

  Procedure Next_FOR_VariableValue;
  begin
    With FOR_Variable do
      If it32Bit in DataType then
        begin
          GenerateArithmeticInstructionWithImmediateValue (1, ForStatementData.LongIntOpCode_Lo);
          Inc (FOR_Variable.Value.Offset, 2);
          GenerateArithmeticInstructionWithImmediateValue (0, ForStatementData.LongIntOpCode_Hi);
          Dec (Value.Offset, 2);
        end else GenerateInstruction_8_16_bit ($FE, ForStatementData.IntegerOpCode);
  end;

begin
  SavedLastJumpOutOfBlock := LastJumpOutOfBlock;
  SavedLastJumpToNextBlockIteration := LastJumpToNextBlockIteration;
  LastJumpOutOfBlock := 0;
  LastJumpToNextBlockIteration := 0;
  GetNextToken;
  JumpToLoopStatement := 0;
  With FOR_Variable do
    begin
      ExpectAssignableVariableReferenceExceptProcedureOrFunction;
      If TypeDefPtr^.BaseType < btInteger then Error (Invalid_FOR_ControlVariable);
      If (LocationData.Flags * [segSS, segDS] = []) or (ofsDI in LocationData.Flags) then Error (Invalid_FOR_ControlVariable);
    end;
  ExpectTokenAndGetNext (Token_Assignment);
  Expect_FOR_LoopLimit (StartValue);
  Case Token of
    Token_TO: ForStatementData := ForStatementData_TO;
    Token_DOWNTO: ForStatementData := ForStatementData_DOWNTO;
    else Error (TO_Or_DOWNTO_Expected);
  end;
  GetNextToken;
  Expect_FOR_LoopLimit (EndValue);
  If not ((StartValue.Location = elConstant) and (EndValue.Location = elConstant)) then
    begin
      With StartValue do
        begin
          Calculate;
          LoadExpressionToRegisters (urDX_AX);
          EndIntermediateCodeSubroutine;
        end;
      With EndValue do If Location <> elConstant then
        begin
          StoreIntegerToStackFrame;
          UsedRegisters := [];
        end;
    end;
  ExpectTokenAndGetNext (Token_DO);
  LoopStatement.ProcessStatement;
  NoLoopComparison := StartValue;
  NoLoopComparison.IntermediateCodeOffset := 0;
  Compare_FOR_Variable (ForStatementData.NoLoopComparisonOperation, NoLoopComparison, EndValue);
  LoopRepeatComparison := FOR_Variable;
  LoopRepeatComparison.IntermediateCodeOffset := 0;
  Compare_FOR_Variable (Calc_IsNotEqual, LoopRepeatComparison, EndValue);
  TempStartValue := StartValue;
  TempStartValue.IntermediateCodeOffset := 0;
  GenerateAssignmentIntermediateCode (FOR_Variable, TempStartValue);
  If NoLoopComparison.Location = elConstant then
    begin
      If NoLoopComparison.Value.Byte = 0 then NoLoopComparison.Value.LastJumpToTrue := 0
        else begin
               LastJumpOutOfBlock := SavedLastJumpOutOfBlock;
               LastJumpToNextBlockIteration := SavedLastJumpToNextBlockIteration;
               StatementCode := 0;
               Exit;
             end;
    end;
  StoreCode_icGoSub (EndValue.IntermediateCodeOffset);
  StoreCode_icGoSub (StartValue.IntermediateCodeOffset);
  StoreCode_icGoSub (NoLoopComparison.IntermediateCodeOffset);
  StoreCode_icGoSub (FOR_Variable.IntermediateCodeOffset);
  GenerateCodeForNearJump (JumpToLoopStatement, JMP_ShortDirect);
  GenerateLabelAndSetJumpsToIt (LoopRepeatComparison.Value.LastJumpToTrue);
  Next_FOR_VariableValue;
  GenerateLabelAndSetJumpsToIt (JumpToLoopStatement);
  StoreCode_icGoSub (LoopStatement.StatementCode);
  GenerateLabelAndSetJumpsToIt (LastJumpToNextBlockIteration);
  StoreCode_icGoSub (LoopRepeatComparison.IntermediateCodeOffset);
  JoinJumpsOfBothExpressions (LastJumpOutOfBlock, NoLoopComparison.Value.LastJumpToTrue);
  GenerateLabelAndSetJumpsToIt (LastJumpOutOfBlock);
  StatementCode := EndSubroutine;
  LastJumpOutOfBlock := SavedLastJumpOutOfBlock;
  LastJumpToNextBlockIteration := SavedLastJumpToNextBlockIteration;
end;