Press enter to see results or esc to cancel.

Converting Boolean Expressions

Turbo Pascal uses a very interesting way of dealing with boolean expressions. Each boolean expression contains a conditional opcode to jump if the expression evaluates to True and two linked lists of jumps. One list contains jumps to code which executes when the expression evaluates to True while the other list contains jumps to code which executes when expression evaluates to False. Those lists are very convenient when the code needs to jump to one or another branch like in short-circuit expression evaluation.

Procedure TExpression.SetExpressionToBooleanJump (OpCode: Word);
begin
  Location := elBoolean;
  DataType := [];
  LocationData.JumpIfTrueOpCode := OpCode;
  Value.LastJumpToTrue := 0;
  Value.LastJumpToFalse := 0;
  TypeDefPtr := Ptr (SystemUnitSegment, Boolean_TypeOffset);
end;

This procedure converts a numerical value into boolean expression. It uses OR or CMP with 0 instruction and JNE jump.

Procedure TExpression.ConvertExpressionToBooleanJump;
begin
  If Location <> elBoolean then
    begin
      Calculate;
      Case Location of
        elMemory: Case it32Bit in DataType of
                    True: begin
                            Exclude (DataType, it16Bit);
                            LoadExpressionToRegister (rAX);
                            Inc (Value.Offset, 2);
                            GenerateArithmeticInstructionWith_ACC (OR_Operations);
                            Include (UsedRegisters, urAX);
                          end;
                    else begin
                           Case it16Bit in DataType of
                             True: GenerateInstructionWithExpressionInMemOrReg (
                               ArithmeticOp_16Bit_reg__mod_rm, mod_CMP_rm);
                             else GenerateInstructionWithExpressionInMemOrReg (
                               ArithmeticOperation, mod_CMP_rm);
                           end;
                           GenerateInstruction_Byte ($00);
                         end;
                  end;
        else begin
               If Location <> elRegister then LoadExpressionToRegisters (urDX_AX);
               If it32Bit in DataType then GenerateInstruction_TwoBytes (OR_16Bit, AX_DX) else
                 If it16Bit in DataType then GenerateInstruction_TwoBytes (OR_16Bit, AX_AX) else
                                                    GenerateInstruction_TwoBytes (OR_Operations, AL_AL);
             end;
      end;
      EndIntermediateCodeSubroutine;
      Location := elBoolean;
      DataType := [];
      LocationData.JumpIfTrueOpCode := JNE;
      Value.ShortCircuitJumps := 0;
    end;
end;

This procedure converts boolean expresion which evaluates to True to 1 and boolean expresion which evaluates to False to 0. First the jumps are converted into integer value and then normalized.

Procedure TExpression.ConvertToBooleanByte;
begin
  If TypeDefPtr^.BaseType = btBoolean then
    begin
      ConvertBooleanJumpToByteValue;
      Case Location of
        elConstant: If Value.LongInt <> 0 then Value.LongInt := 1;
        else begin
               If DataType = [] then Exit;
               Calculate;
               LoadExpressionToRegisters (urDX_AX);
               If it32Bit in DataType then GenerateInstruction_TwoBytes (OR_16Bit, AX_DX);
               Case it16Bit in DataType of
                 True: GenerateInstruction_Word (NEG_AX);
                 else GenerateInstruction_Word (NEG_AL);
               end;
               GenerateInstruction_Word (SBB_AL_AL);
               GenerateInstruction_Word (NEG_AL);
               EndIntermediateCodeSubroutine;
             end;
      end;
      DataType := [];
    end;
end;

This procedure converts boolean jumps into integer value in AL. If there are no short-circuit jumps the jump-if-true opcode is inverted (xor 1) to skip incrementing the value in AL if the expression evaluates to false.

Procedure TExpression.ConvertBooleanJumpToByteValue;
begin
  If Location = elBoolean then
    begin
      Calculate;
      Case Value.ShortCircuitJumps <> 0 of
        True: begin
                GenerateCodeForNearJump (Value.LastJumpToTrue, LocationData.JumpIfTrueOpCode);
                GenerateLabelAndSetJumpsToIt (Value.LastJumpToFalse);
                GenerateInstruction_TwoBytes (MOV_AL_Immediate, 0);
                GenerateInstruction_TwoBytes (JMP_ShortDirect, 2);
                GenerateLabelAndSetJumpsToIt (Value.LastJumpToTrue);
                GenerateInstruction_TwoBytes (MOV_AL_Immediate, 1);
              end;
        else begin
               GenerateInstruction_TwoBytes (MOV_AL_Immediate, 0);
               GenerateInstruction_TwoBytes (LocationData.JumpIfTrueOpCode xor 1, 1);
               GenerateInstruction_Byte (INC_AX);
             end;
      end;
      EndIntermediateCodeSubroutine;
      Location := elRegister;
      Include (UsedRegisters, urAX);
      LocationData.Register := rAX;
    end;
end;

This procedure sets expression to constant boolean value.

Procedure TExpression.SetConstantBooleanExpression (BoolValue: Boolean);
begin
  Location := elConstant;
  DataType := [];
  UsedRegisters := [];
  Value.LongInt := LongInt (BoolValue);
  TypeDefPtr := Ptr (SystemUnitSegment, Boolean_TypeOffset);
end;