Assignment Statement and Procedure Call
This procedure processes assignment statements and procedure/function calls. It first checks for variable expression, then if the token is procedure or function it generates code to call procedure (or function), for functions it processes qualifiers in a loop and stops if it finds assignment token. For assignments it first calculates value expression, it adjusts type if necessary, checks type compatibility and range and generates intermediate code for assignment.
Procedure TStatement.ProcessAssignmentStatementOrProcedureCall;
Var VarExpression, ValueExpression: TExpression;
Label AssignmentFinished;
Procedure ExpectVariableExpression;
Var FunctionType: PTypeDefinition;
FunctionResultOffset: Integer;
VarFlags: TVarFlagsSet;
begin
If (Token = Token_ProcedureIdentifier) and FunctionAsResult (FunctionType, FunctionResultOffset) then
With VarExpression do
begin
TypeDefPtr := FunctionType;
Value.Word := FunctionResultOffset;
DataType := FunctionType^.DataType;
Location := elMemory;
UsedRegisters := [];
VarFlags := [];
If Value.Integer >= 0 then VarFlags := [vfVar];
VarExpression.LoadAddressOfLocalVariable (VarFlags, CurrentIdentifierOffset);
VarExpression.EndIntermediateCodeSubroutine;
GetNextToken;
end else VarExpression.ExpectVariableIdentifier;
end;
begin
ExpectVariableExpression;
With VarExpression do
begin
Repeat
If TypeDefPtr^.BaseType = btFunctionProcedure then
begin
Repeat
If (Location <> elProcedure) and (Token = Token_Assignment) then Break;
CallProcedure;
If PProcedureTypeDefinition (TypeDefPtr)^.ResultTypeOffset.TypeOffset = 0 then GoTo AssignmentFinished;
SetExpressionToFunctionResult;
until not VarExpression.ProcessQualifiers;
If not (ExtendedSyntax in ModuleCompilerSwitches) then Break;
If Token = Token_Assignment then Break;
RemoveFunctionResultFromStack;
GoTo AssignmentFinished;
end;
until not VarExpression.ProcessQualifiers;
If (Location <> elMemory) or (efSegment in LocationData.Flags) then Error (InvalidVariableReference);
Case TypeDefPtr^.BaseType of
btUntyped,
btFile,
btText: Error (IllegalAssignment);
end;
ExpectTokenAndGetNext (Token_Assignment);
ValueExpression.CalculateExpressionWithType (TypeDefPtr);
ValueExpression.AdjustExpressionToType (TypeDefPtr);
ValueExpression.CheckTypeCompatibility (TypeDefPtr);
ValueExpression.CheckRange (TypeDefPtr);
GenerateAssignmentIntermediateCode (VarExpression, ValueExpression);
AssignmentFinished:
StatementCode := IntermediateCodeOffset;
end;
end;
This procedure generates assignment intermediate code.
Procedure GenerateAssignmentIntermediateCode (Var VarExpression, ValueExpression: TExpression);
Procedure CallSystemProcedure (AX, DX: Word);
begin
ConvertToPointerAndPushBothExpressions (ValueExpression, VarExpression);
CalculateBothExpressions (ValueExpression, VarExpression);
GenerateCodeToPushWord (DX);
GenerateInstruction_CALL_FAR (AX);
VarExpression.EndIntermediateCodeSubroutine
end;
Procedure GenerateCodeForSimpleAssignment;
begin
If ValueExpression.Location <> elConstant then
begin
ValueExpression.Calculate;
ValueExpression.Save (VarExpression.UsedRegisters);
VarExpression.Calculate;
ValueExpression.PopToRegisters ([]);
VarExpression.GenerateInstruction_MOV_Memory_Register (ValueExpression.LocationData.Register);
VarExpression.EndIntermediateCodeSubroutine;
Exit;
end;
If (ValueExpression.Value.LongInt = 0) and (it16Bit in VarExpression.DataType) then
begin
VarExpression.Calculate;
GenerateInstruction_Word (XOR_AX_AX);
VarExpression.GenerateInstruction_16bit_MOV_Memory_Register (rAX);
If it32Bit in VarExpression.DataType then
begin
Inc (VarExpression.Value.Offset, 2);
VarExpression.GenerateInstruction_16bit_MOV_Memory_Register (rAX);
Dec (VarExpression.Value.Offset, 2);
end;
Include (VarExpression.UsedRegisters, urAX);
VarExpression.EndIntermediateCodeSubroutine;
Exit;
end;
VarExpression.Calculate;
VarExpression.GenerateInstruction_MOV_Memory_Immediate (ValueExpression.Value.Word);
If it32Bit in VarExpression.DataType then
begin
Inc (VarExpression.Value.Offset, 2);
VarExpression.GenerateInstruction_MOV_Memory_Immediate (ValueExpression.Value.LongRec.WordH);
Dec (VarExpression.Value.Offset, 2);
end;
VarExpression.EndIntermediateCodeSubroutine;
end;
Procedure GenerateCodeForComplexAssignment;
begin
ValueExpression.SetDataTypeForSimpleType;
If VarExpression.SetDataTypeForSimpleType then GenerateCodeForSimpleAssignment
else CallSystemProcedure (SysProc_BlockMove, VarExpression.TypeDefptr^.Size);
end;
Procedure GenerateCodeForObjectAssignment;
begin
If PObjectTypeDefinition (VarExpression.TypeDefPtr)^.VMT_Size = 0 then GenerateCodeForComplexAssignment
else CallSystemProcedure (SysProc_CopyObject, PObjectTypeDefinition (VarExpression.TypeDefPtr)^.OffsetOf_VMT_Offset);
end;
Procedure GenerateCodeForSetAssignment;
Var SetSize, SetElementLowerLimit_div_8: Byte;
begin
If it32Bytes in VarExpression.DataType then
begin
ValueExpression.ExpandSetToStackFrameAndPushPointer (32);
ConvertToPointerAndPushBothExpressions (ValueExpression, VarExpression);
CalculateBothExpressions (ValueExpression, VarExpression);
SetSize :=
PSetTypeDefinition (VarExpression.TypeDefPtr)^.GetSetSizeAndLowestElementDataOffset (SetElementLowerLimit_div_8);
GenerateCodeToPushWord (SetElementLowerLimit_div_8 shl 8 or SetSize);
GenerateInstruction_CALL_FAR (SysProc_ZStore);
VarExpression.EndIntermediateCodeSubroutine;
end else GenerateCodeForSimpleAssignment;
end;
Procedure GeneratoCodeForStringAssignment;
begin
If (ValueExpression.Location = elConstant) and (PString (Ptr (DSeg, ValueExpression.Value.Offset))^ = '') then
begin
VarExpression.Calculate;
VarExpression.GenerateInstructionWithExpressionInMemOrReg (MOV_RegisterOrMemory_Immediate, 0);
GenerateInstruction_Byte (0);
end else begin
VarExpression.PushArrayPointerAndHighestIndex;
ValueExpression.StoreStringConstantToCodeBlock;
ValueExpression.ConvertToPointerAndPush;
CalculateBothExpressions (ValueExpression, VarExpression);
GenerateInstruction_CALL_FAR (SysProc_SStore);
end;
VarExpression.EndIntermediateCodeSubroutine;
end;
Procedure GenerateCodeForExtendedAssignment;
begin
ValueExpression.LoadExpressionToFPU;
CalculateBothExpressions (ValueExpression, VarExpression);
With VarExpression do
begin
Case fpExtended in DataType of
True: VarExpression.GenerateFPUInstructionWithExpressionInMemory ($D9 or Byte (DataType), $38);
else VarExpression.GenerateFPUInstructionWithExpressionInMemory ($D9 or Byte (DataType), $18);
end;
GenerateInstruction_TwoBytes ($CD, $3D);
VarExpression.EndIntermediateCodeSubroutine;
end;
end;
Procedure GenerateCodeForRealAssignment;
begin
With VarExpression do
begin
Case ValueExpression.Location of
elConstant: begin
VarExpression.Calculate;
VarExpression.GenerateInstruction_MOV_Memory_Immediate (ValueExpression.Value.Real1);
Inc (Value.Offset, 2);
VarExpression.GenerateInstruction_MOV_Memory_Immediate (ValueExpression.Value.Real2);
Inc (Value.Offset, 2);
VarExpression.GenerateInstruction_MOV_Memory_Immediate (ValueExpression.Value.Real3);
end;
else begin
ValueExpression.Calculate;
ValueExpression.LoadRealExpressionToRegisterSet (rAX_BX_DX);
If UsedRegisters <> [] then
begin
GenerateInstruction_TwoBytes (PUSH_DX, PUSH_BX);
GenerateInstruction_Byte (PUSH_AX);
end;
VarExpression.Calculate;
If UsedRegisters <> [] then
begin
GenerateInstruction_Byte (PUSH_AX);
GenerateInstruction_TwoBytes (POP_BX, POP_DX );
end;
VarExpression.GenerateInstruction_16bit_MOV_Memory_Register (rAX);
Inc (Value.Offset, 2);
VarExpression.GenerateInstruction_16bit_MOV_Memory_Register (rBX);
Inc (Value.Offset, 2);
VarExpression.GenerateInstruction_16bit_MOV_Memory_Register (rDX);
end;
end;
Dec (Value.Offset, 4);
VarExpression.EndIntermediateCodeSubroutine;
end;
end;
begin
Case VarExpression.TypeDefPtr^.BaseType of
btUntyped,
btArray,
btRecord,
btFile,
btText: GenerateCodeForComplexAssignment;
btObject: GenerateCodeForObjectAssignment;
btFunctionProcedure,
btPointer,
btInteger,
btBoolean,
btChar,
btEnumeration: GenerateCodeForSimpleAssignment;
btSet: GenerateCodeForSetAssignment;
btString: GeneratoCodeForStringAssignment;
btExtended: GenerateCodeForExtendedAssignment;
btReal: GenerateCodeForRealAssignment;
end;
end;
This function checks if function name is used as a variable to store function’s result value.
Function FunctionAsResult (Var TypeDef: PTypeDefinition; Var FuncResultOffset: Integer): Boolean;
Var ProceduresBlockRecord: PProceduresBlockRecord;
ProcedureIdentifierData: PProcedureIdentifierData absolute CurrentIdentifierDataPtr;
begin
FunctionAsResult := False;
If Seg (CurrentIdentifierDataPtr^) <> SymbolTable [stMain].Segment then Exit;
If ProcedureIdentifierData^.ProcedureTypeDefinition.ResultTypeOffset.TypeOffset = 0 then Exit;
ProceduresBlockRecord := Ptr (SymbolTable [stProcedures].Segment, ProcedureIdentifierData^.ProceduresRecordOffset);
If ProceduresBlockRecord^.ProgramCodeBlockRecordOffset <> $FFFE then Exit;
TypeDef := PointerFromOffsets (ProcedureIdentifierData^.ProcedureTypeDefinition.ResultTypeOffset);
With TypeDef^ do
begin
FuncResultOffset := - Size;
If BaseType = btString then SizeOfPushedParameters (CurrentIdentifierDataPtr, FuncResultOffset);
end;
FunctionAsResult := True;
end;