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;