Processing Typed Constants
This procedure processes and stores the value of typed constants. For complex types like Arrays
, Records
and Objects
recursion is used to process elements and fields.
Procedure ProcessTypedConstant (ConstantTypeDef: PTypeDefinition);
Var Expression: TExpression;
IntermediateCodeSizeBeforeExpression: Word;
OffsetOf_VMT_Offset, ReferencedBlockRecord, ReferencedSegment: Word;
Flags: TReferenceFlagSet;
ReferencedOffset: Word;
{ btArray }
ArrayTypeDefinition: PArrayTypeDefinition absolute ConstantTypeDef;
IndexElements: Word;
StringLen: Byte;
StrConst: PString;
SetTypeDefinition: PSetTypeDefinition absolute ConstantTypeDef;
SetSize, SetDataOffset: Byte; { btSet }
{ btRecord, btObject }
RecordTypeDefinition: PObjectTypeDefinition absolute ConstantTypeDef;
ObjectTypeDefinition: PObjectTypeDefinition absolute ConstantTypeDef;
CurrentRecordValueOffset: Word;
FieldDataPtr: PVariableIdentifierData;
FieldToken: TToken;
FieldIdOffset: Word;
Procedure CopyInitialValueToTypedConstant (Source: Pointer; ActualSize: Word);
begin
Move (Source^, Ptr (SymbolTable [stTypedConstants].Segment, CurrentTypedConstantValueOffset)^, ActualSize);
Inc (CurrentTypedConstantValueOffset, ConstantTypeDef^.Size);
end;
begin
Case ConstantTypeDef^.BaseType of
btUntyped,
btFile,
btText: Error (FileTypesAreNotAllowedHere);
btArray: begin
If Token = Token_LeftParenthesis then
begin
ExpectTokenAndGetNext (Token_LeftParenthesis);
With POrdinalTypeDefinition (PointerFromOffsets (ArrayTypeDefinition^.IndexTypeOffset))^ do
IndexElements := UpperLimit - LowerLimit + 1;
Repeat
ProcessTypedConstant (PointerFromOffsets (ArrayTypeDefinition^.ElementTypeOffset));
Dec (IndexElements);
If IndexElements <> 0 then ExpectTokenAndGetNext (Token_Comma);
until IndexElements = 0;
ExpectTokenAndGetNext (Token_RightParenthesis);
end else begin
If ExtendedSyntax in ModuleCompilerSwitches then
begin
If not PArrayTypeDefinition (ConstantTypeDef)^.IsZeroBasedCharacterArray then
If not ArrayTypeDefinition^.IsCharacterArrayCompatibleWithString (StringLen) then
ExpectTokenAndGetNext (Token_LeftParenthesis);
end else If not ArrayTypeDefinition^.IsCharacterArrayCompatibleWithString (StringLen) then
ExpectTokenAndGetNext (Token_LeftParenthesis);
StrConst := ExpectStringConstant;
If Length (StrConst^) > ConstantTypeDef^.Size then Error (StringLengthMismatch);
If (Length (StrConst^) < ConstantTypeDef^.Size) and not (ExtendedSyntax in ModuleCompilerSwitches)
then Error (StringLengthMismatch);
CopyInitialValueToTypedConstant (@StrConst^ [1], Length (StrConst^));
end;
end;
btRecord,
btObject: begin
CurrentRecordValueOffset := CurrentTypedConstantValueOffset;
OffsetOf_VMT_Offset :=$FFFF;
If (ConstantTypeDef^.BaseType = btObject) and (ObjectTypeDefinition^.VMT_Size <> 0) then
begin
AddReferenceRecordForTypedConstant (Seg (ConstantTypeDef^),
ObjectTypeDefinition^.VMT_TypedConstantsBlockRecordOffset,
[rfDataSegment, rfConstant, rfOffset], 0,
CurrentTypedConstantValueOffset + ObjectTypeDefinition^.OffsetOf_VMT_Offset);
OffsetOf_VMT_Offset := ObjectTypeDefinition^.OffsetOf_VMT_Offset;
end;
ExpectTokenAndGetNext (Token_LeftParenthesis);
If Token <> Token_RightParenthesis then
Repeat
If CurrentTypedConstantValueOffset - CurrentRecordValueOffset = OffsetOf_VMT_Offset then
Inc (CurrentTypedConstantValueOffset, 2);
If not IsCurrentIdentifierDeclaredAsMemberInRecordOrObject (RecordTypeDefinition, FieldDataPtr,
FieldToken, FieldIdOffset) or
(FieldToken <> Token_VariableIdentifier) then Error (FieldIdentifierExpected);
GetNextToken;
If CurrentTypedConstantValueOffset - CurrentRecordValueOffset <> FieldDataPtr^.W1.Ofs then
Error (InvalidOrderingOfFields);
ExpectTokenAndGetNext (Token_Colon);
ProcessTypedConstant (PointerFromOffsets (FieldDataPtr^.UnitTypeOffsets));
until not CheckAndGetNextToken (Token_Semicolon);
ExpectTokenAndGetNext (Token_RightParenthesis);
CurrentTypedConstantValueOffset := CurrentRecordValueOffset + ConstantTypeDef^.Size;
end;
btSet: begin
Expression.ExpectConstantExpression;
Expression.CheckTypeCompatibility (ConstantTypeDef);
SetSize := SetTypeDefinition^.GetSetSizeAndLowestElementDataOffset (SetDataOffset);
CopyInitialValueToTypedConstant (Ptr (DSeg, Expression.Value.Word + SetDataOffset), SetSize);
end;
btString: begin
StrConst := ExpectStringConstant;
If Length (StrConst^) > (ConstantTypeDef^.Size - 1) then
StrConst^ [0] := Char (ConstantTypeDef^.Size - 1);
CopyInitialValueToTypedConstant (StrConst, Length (StrConst^) + 1);
end;
else begin
IntermediateCodeSizeBeforeExpression := SymbolTable [stIntermediateCode].UsedSize;
With Expression do
begin
CalculateExpressionWithType (ConstantTypeDef);
AdjustExpressionToType (ConstantTypeDef);
CheckTypeCompatibility (ConstantTypeDef);
CheckRange (ConstantTypeDef);
end;
If IntermediateCodeSizeBeforeExpression <> SymbolTable [stIntermediateCode].UsedSize then
Error (CannotEvaluateThisExpression);
Case Expression.Location of
elConstant: begin
If ConstantTypeDef^.BaseType = btExtended then
ConvertExtendedToOtherFloatingPointTypes (ConstantTypeDef^.DataType, Expression.Value);
CopyInitialValueToTypedConstant (@Expression.Value, ConstantTypeDef^.Size);
end;
elPointerToMemory: begin
If Expression.LocationData.Flags * [ofsDI, ofsBP, segES, segSS] <> [] then
Error (CannotEvaluateThisExpression);
ReferencedSegment := Expression.Value.Segment;
ReferencedBlockRecord := Expression.Value.BlockRecord;
ReferencedOffset := Expression.Value.Offset;
If segDS in Expression.LocationData.Flags then
begin
Flags := [rfDataSegment];
If efTypedConstant in Expression.LocationData.Flags then
Flags := [rfDataSegment, rfConstant];
end else begin
Flags := [];
If segCS in Expression.LocationData.Flags then Flags := [rfConstant];
end;
If efSegment in Expression.LocationData.Flags then Include (Flags, rfSegment)
else begin
Include (Flags, rfOffset);
If it32Bit in Expression.DataType then Include (Flags, rfSegment);
end;
AddReferenceRecordForTypedConstant (ReferencedSegment, ReferencedBlockRecord, Flags,
ReferencedOffset, CurrentTypedConstantValueOffset);
Inc (CurrentTypedConstantValueOffset, ConstantTypeDef^.Size);
end;
else Error (CannotEvaluateThisExpression);
end;
end;
end;
end;
Procedure AddReferenceRecordForTypedConstant (UnitSegment, BlockRecord: Word; ReferenceFlags: TReferenceFlagSet;
DX, TypedConstantOffset: Word);
Var ReferencedUnitRec: Word;
begin
ReferencedUnitRec := AddReferencedModule (UnitSegment);
With PReferencesBlockRecord (IncreaseSymbolTable (stTypedConstantsReferences, SizeOf (TReferencesBlockRecord)))^ do
begin
ReferencedUnitRecord := ReferencedUnitRec or Word (ReferenceFlags);
ReferencedBlockRecordOffset := BlockRecord;
ReferencedOffset := DX;
PositionOfReference := TypedConstantOffset - LastTypedConstantsSize;
end;
end;