Press enter to see results or esc to cancel.

Processing Non-object Types

This procedure processes all types except Objects and creates type definition records. One one hand objects need different and more complex processing and on the other hand they can not be declared anywhere else as in the program, interface or implementation part. This procedure is used also to process types in variable declarations, ordinal types and it is also used recursively for Array and File elements. Multi-dimensional arrays are created as arrays of simple arrays as Pascal language defines.

Function ProcessNonObjectTypeDeclaration: PTypeDefinition;

  Function ProcessPointerType: PTypeDefinition;
  Var PointerTypeDefinition: PPointerTypeDefinition;
      TemporaryTableRecordOffset: Word;
      PointerBaseTypeUnitTypeOffsets: TUnitOffsets;

    Procedure CreatePointerToSystemType (SystemTypeOffset: Word);
    begin
      GetTypeAndUnitIdentifierOffsets (Ptr (SystemUnitSegment, SystemTypeOffset), PointerBaseTypeUnitTypeOffsets);
      PointerTypeDefinition := CreateTypeDefinition (SizeOf (TPointerTypeDefinition), 4, itLongInt, btPointer);
      PointerTypeDefinition^.PointerBaseTypeOffset := PointerBaseTypeUnitTypeOffsets;
      GetNextToken;
    end;

  begin
    GetNextToken;
    Case Token of
      Token_STRING: CreatePointerToSystemType (String_TypeOffset);
      Token_FILE: CreatePointerToSystemType (File_TypeOffset);
      else begin
            TemporaryTableRecordOffset := SymbolTable [stTemporary].NextRecordOffset;
            StoreNextIdentifierToTemporaryBlock;
            PointerTypeDefinition :=
              CreateTypeDefinition (SizeOf (TPointerTypeDefinition), 4, itLongInt, btPointer);
            With PointerTypeDefinition^.PointerBaseTypeOffset do
              begin
                PreviousPointerToTypeDefinitionOffset := LastPointerToTypeDefinitionOffset;
                TemporarySymbolTableRecordOffset := TemporaryTableRecordOffset;
              end;
            LastPointerToTypeDefinitionOffset := Ofs (PointerTypeDefinition^);
          end;
    end;
    ProcessPointerType := Pointer (PointerTypeDefinition);
  end;

  Function ProcessArrayType: PTypeDefinition;
  Var IndexCounter: Word;
      TypeDef: PTypeDefinition;
      ArrayTypeDefinition: PArrayTypeDefinition;
      ArrayElementUnitTypeOffsets,
      ArrayIndexUnitTypeOffsets: TUnitOffsets;
      ArraySize: LongRec;
      TypeDefinition: PTypeDefinition;
  begin
    GetNextToken;
    ExpectTokenAndGetNext (Token_LeftBracket);
    IndexCounter := 0;
    Repeat
      TypeDef := ExpectOrdinalType;
      Asm
        PUSH  WORD PTR TypeDef + 2
        PUSH  WORD PTR TypeDef
      end;
      Inc (IndexCounter);
    until not CheckAndGetNextToken (Token_Comma);
    ExpectTokenAndGetNext (Token_RightBracket);
    ExpectTokenAndGetNext (Token_OF);
    TypeDef := ProcessNonObjectTypeDeclaration;         { Base array element type }
    Repeat
      GetTypeAndUnitIdentifierOffsets (TypeDef, ArrayElementUnitTypeOffsets);{ Array element type }
      ArraySize.Long := TypeDef^.Size;                  { Array element size }
      Asm
        POP   WORD PTR TypeDef                          { Array index TyepDef }
        POP   WORD PTR TypeDef + 2
      end;
      With POrdinalTypeDefinition (TypeDef)^ do
        begin
          If UpperLimit - LowerLimit = $FFFF then Error (StructureTooLarge);
          ArraySize.Long := ArraySize.Long * (UpperLimit - LowerLimit + 1);
        end;
      If ArraySize.WordH <> 0 then Error (StructureTooLarge);
      GetTypeAndUnitIdentifierOffsets (TypeDef, ArrayIndexUnitTypeOffsets);
      ArrayTypeDefinition := CreateTypeDefinition (SizeOf (TArrayTypeDefinition), ArraySize.WordL, [], btArray);
      With ArrayTypeDefinition^ do
        begin
          IndexTypeOffset := ArrayIndexUnitTypeOffsets;
          ElementTypeOffset := ArrayElementUnitTypeOffsets
        end;
      TypeDef := ArrayTypeDefinition;
      Dec (IndexCounter);
    until IndexCounter = 0;
    ProcessArrayType := ArrayTypeDefinition;
  end;

  Function ProcessRecordType: PTypeDefinition;
  Var RecordTypeDefinition: PRecordTypeDefinition;
      SavedLastPointerToTypeDefinitionOffset: Word;
      Saved_OffsetToNextMemberOffset: Word;
      SavedFirstDeclaredVariableIdentifierOffset: Word;
      SavedNumberOfDeclaredVariableIdentifiers: Word;

    Function ProcessRecordFieldsBetweenTokens (StartToken, EndToken: TToken): PTypeDefinition;
    Var TempToken: TToken;
        DataOfs,
        RecordSizeBeforeCase,
        LargestRecordSize: Word;
        IdDataPtr: Pointer;
        RecordTypePtr: PTypeDefinition;
        DummyTypeDef: PTypeDefinition;
        Expression: TExpression;
    begin
      ExpectTokenAndGetNext (StartToken);
      Repeat
        Case Token of
          Token_Identifier:
            begin
              ProcessCommaSeparatedFieldsAndType;
              CalculateVariableOffsets;
              If CheckAndGetNextToken (EndToken) then Exit;
              ExpectTokenAndGetNext (Token_Semicolon);
            end;
          Token_CASE:
            begin
              GetNextToken;
              ExpectIdentifier;
              If (not FindCurrentIdentifier (TempToken, DataOfs, IdDataPtr)) or (TempToken <> Token_TypeIdentifier) then
                  begin
                    ProcessCommaSeparatedFieldsAndType;
                    CalculateVariableOffsets;
                  end else GetNextToken;
              ExpectTokenAndGetNext (Token_OF);
              RecordTypePtr := Ptr (SymbolTable [stMain].Segment, CurrentRecordOrObjectTypeDefinitionOffset);
              RecordSizeBeforeCase := RecordTypePtr^.Size;
              Repeat
                LargestRecordSize := RecordTypePtr^.Size;
                RecordTypePtr^.Size := RecordSizeBeforeCase;
                Repeat
                  Expression.ExpectConstantExpression;
                Until not CheckAndGetNextToken (Token_Comma);
                ExpectTokenAndGetNext (Token_Colon);
                DummyTypeDef := ProcessRecordFieldsBetweenTokens (Token_LeftParenthesis, Token_RightParenthesis);
                If RecordTypePtr^.Size < LargestRecordSize then RecordTypePtr^.Size := LargestRecordSize;
                If CheckAndGetNextToken (EndToken) then Exit;
                ExpectTokenAndGetNext (Token_Semicolon);
                If CheckAndGetNextToken (EndToken) then Exit;
              until False;
            end;
          else begin
                 ExpectTokenAndGetNext (EndToken);
                 Exit;
               end;
        end;
      until False;
    end;

  begin
    SavedLastPointerToTypeDefinitionOffset := LastPointerToTypeDefinitionOffset;
    Saved_OffsetToNextMemberOffset := OffsetToNextMemberOffset;
    SavedFirstDeclaredVariableIdentifierOffset := FirstDeclaredVariableIdentifierOffset;
    SavedNumberOfDeclaredVariableIdentifiers := NumberOfDeclaredVariableIdentifiers;
    RecordTypeDefinition := CreateTypeDefinition (SizeOf (TRecordTypeDefinition), 0, [], btRecord);
    CurrentRecordOrObjectTypeDefinitionOffset := Ofs (RecordTypeDefinition^);
    RecordTypeDefinition^.FieldsListOffset := SymbolTable [stMain].NextRecordOffset;
    RecordTypeDefinition^.W0A := 0;
    OffsetToNextMemberOffset := Ofs (RecordTypeDefinition^.W0A);
    CreateSymbolTable (4);
    ProcessRecordFieldsBetweenTokens (Token_RECORD, Token_END);
    CurrentRecordOrObjectTypeDefinitionOffset := 0;
    NumberOfDeclaredVariableIdentifiers := SavedNumberOfDeclaredVariableIdentifiers;
    FirstDeclaredVariableIdentifierOffset := SavedFirstDeclaredVariableIdentifierOffset;
    OffsetToNextMemberOffset := Saved_OffsetToNextMemberOffset;
    LastPointerToTypeDefinitionOffset := SavedLastPointerToTypeDefinitionOffset;
    ProcessRecordType := RecordTypeDefinition;
  end;

  Function ProcessStringType: PTypeDefinition;
  Var StringLength: LongRec;
      CharUnitTypeOffsets, OrdinalUnitTypeOffsets: TUnitOffsets;
      LongIntUnitTypeOffsets: TUnitOffsets absolute OrdinalUnitTypeOffsets;
      OrdinalTypeDefinition: POrdinalTypeDefinition;
      StringTypeDefinition: PStringTypeDefinition;
  begin
    GetNextToken;
    If not CheckAndGetNextToken (Token_LeftBracket) then
      begin
        ProcessStringType := Ptr (SystemUnitSegment, String_TypeOffset);
        Exit;
      end;
    StringLength.Long := ExpectIntegerConstant;
    If StringLength.WordH <> 0 then Error (InvalidStringLength);
    If StringLength.Byte1 <> 0 then Error (InvalidStringLength);
    If StringLength.Byte0 = 0 then Error (InvalidStringLength);
    GetTypeAndUnitIdentifierOffsets (Ptr (SystemUnitSegment, LongInt_TypeOffset), LongIntUnitTypeOffsets);
    OrdinalTypeDefinition := CreateTypeDefinition (SizeOf (TOrdinalTypeDefinition), 1, [itUnsigned], btInteger);
    With OrdinalTypeDefinition^ do
      begin
        OrdinalType := LongIntUnitTypeOffsets;
        LowerLimit := 0;
        UpperLimit := StringLength.Byte0;
      end;
    GetTypeAndUnitIdentifierOffsets (Pointer (OrdinalTypeDefinition), OrdinalUnitTypeOffsets);
    GetTypeAndUnitIdentifierOffsets (Ptr (SystemUnitSegment, Char_TypeOffset), CharUnitTypeOffsets);
    StringTypeDefinition := CreateTypeDefinition (SizeOf (TStringTypeDefinition), StringLength.Byte0 + 1, [], btString);
    With StringTypeDefinition^ do
      begin
        ElementTypeOffset := CharUnitTypeOffsets;
        IndexTypeOffset := OrdinalUnitTypeOffsets;
      end;
    ProcessStringType := StringTypeDefinition;
    ExpectTokenAndGetNext (Token_RightBracket);
  end;

  Function ProcessFileType: PTypeDefinition;
  Var FileElementType: PTypeDefinition;
      FileTypeDefinition: PFileTypeDefinition;
      FileElementTypeUnitTypeOffsets: TUnitOffsets;
  begin
    GetNextToken;
    If not CheckAndGetNextToken (Token_OF) then
      begin
        ProcessFileType := Ptr (SystemUnitSegment, File_TypeOffset);
        Exit;
      end;
    FileElementType := ProcessNonObjectTypeDeclaration;
    Case FileElementType^.BaseType of
      btObject,
      btFile,
      btText: Error (FileComponentsMayNotBeFilesOrObjects);
    end;
    GetTypeAndUnitIdentifierOffsets (FileElementType, FileElementTypeUnitTypeOffsets);
    FileTypeDefinition := CreateTypeDefinition (SizeOf (TFileTypeDefinition), $80, [], btFile);
    FileTypeDefinition^.BaseFileTypeOffset := FileElementTypeUnitTypeOffsets;
    ProcessFileType := Pointer (FileTypeDefinition);
  end;

  Function ProcessSetType: Pointer;
  Var SetBaseType: POrdinalTypeDefinition;
      SetTypeDefinition: PSetTypeDefinition;
      SetBaseTypeUnitTypeOffsets: TUnitOffsets;
      SetSize: Byte;
      IntType: TIntegerTypeSet;
  begin
    GetNextToken;
    ExpectTokenAndGetNext (Token_OF);
    SetBaseType := Pointer (ExpectOrdinalType);
    With SetBaseType^ do
      begin
        If (LowerLimit or UpperLimit) and $FF00 <> 0 then Error (SetBaseTypeOutOfRange);
        SetSize := (UpperLimit - LowerLimit) shr 3 + 1;
        IntType := [it32Bytes];
        If LowerLimit = 0 then
          Case SetSize of
            1: IntType := [itUnsigned];
            2: IntType := [itUnsigned, it16Bit];
          end;
      end;
    GetTypeAndUnitIdentifierOffsets (Pointer (SetBaseType), SetBaseTypeUnitTypeOffsets);
    SetTypeDefinition := CreateTypeDefinition (SizeOf (TSetTypeDefinition), SetSize, IntType, btSet);
    SetTypeDefinition^.BaseSetTypeOffset := SetBaseTypeUnitTypeOffsets;
    ProcessSetType := Pointer (SetTypeDefinition);
  end;

  Function ProcessEnumeratedType: PTypeDefinition;
  Var EnumerationType: POrdinalTypeDefinition;
      SetTypeDefinition: PSetTypeDefinition;
      EnumerationIdData: PConstantIdentifierData;
      EnumerationId: PIdentifier;
      Counter: Word;
      EnumerationUnitTypeOffsets: TUnitOffsets;
  begin
    GetNextToken;
    EnumerationType := CreateTypeDefinition (SizeOf (TOrdinalTypeDefinition), 0, [], btEnumeration);
    GetTypeAndUnitIdentifierOffsets (Pointer (EnumerationType), EnumerationUnitTypeOffsets);
    EnumerationType^.OrdinalType := EnumerationUnitTypeOffsets;
    SetTypeDefinition := CreateTypeDefinition (SizeOf (TSetTypeDefinition), 32, [it32Bytes], btSet);
    SetTypeDefinition^.BaseSetTypeOffset := EnumerationUnitTypeOffsets;
    Counter := 0;
    Repeat
      EnumerationId := ExpectAndStoreIdentifier (8, Pointer (EnumerationIdData));
      EnumerationId^.Token := Token_ConstantIdentifier;
      With EnumerationIdData^ do
        begin
          UnitTypeOffsets := EnumerationUnitTypeOffsets;
          OrdinalValue := Counter;
          W2 := 0;
        end;
      Inc (Counter);
    until not CheckAndGetNextToken (Token_Comma);
    Dec (Counter);
    ExpectTokenAndGetNext (Token_RightParenthesis);
    With EnumerationType^ do
      begin
        LowestIntegerType (Counter, DataType);
        Size := 1;
        If it16Bit in DataType then Size := 2;
        LowerLimit := 0;
        UpperLimit := Counter;
      end;
    SetTypeDefinition^.W06_ := 0;
    ProcessEnumeratedType := Pointer (EnumerationType);
  end;

  Function ProcessFunctionProcedureType: PTypeDefinition;
  Var SavedTemporaryBlockSize: Word;
      ProcToken: TToken;
  begin
    ProcToken := Token;
    GetNextToken;
    SavedTemporaryBlockSize := SymbolTable [stTemporary].UsedSize;
    ProcessFunctionProcedureType := ProcessProcedureHeader (ProcToken);
    SymbolTable [stTemporary].UsedSize := SavedTemporaryBlockSize;
  end;

  Function ProcessSubrangeType: PTypeDefinition;
  Var LowerLimitExpression, UpperLimitExpression: TExpression;
      CommonOrdinalType: TIntegerTypeSet;
      UnitTypeOffsets: TUnitOffsets;
      Size: Byte;
      SubRangeType: POrdinalTypeDefinition;
      LowerLimitLowestIntegerType, UpperLimitLowestIntegerType: TIntegerTypeSet;
  begin
   LowerLimitExpression.ExpectConstantExpression;
    If LowerLimitExpression.TypeDefPtr^.BaseType < btInteger then Error (InvalidSubrangeBaseType);
    ExpectTokenAndGetNext (Token_PeriodPeriod);
   UpperLimitExpression.ExpectConstantExpression;
    If LowerLimitExpression.TypeDefPtr <> UpperLimitExpression.TypeDefPtr then Error (TypeMismatch);
    If LowerLimitExpression.Value.LongInt > UpperLimitExpression.Value.LongInt then
      Error (LowerBoundGreaterThanUpperBound);
    LowestIntegerType (LowerLimitExpression.Value.LongInt, LowerLimitLowestIntegerType);
    LowestIntegerType (UpperLimitExpression.Value.LongInt, UpperLimitLowestIntegerType);
    SetLowestCommonIntegerType (LowerLimitLowestIntegerType, UpperLimitLowestIntegerType, CommonOrdinalType);
    Size := 1;
    If it16Bit in CommonOrdinalType then
      begin
        Size := 2;
        If it32Bit in CommonOrdinalType then Size := 4;
      end;
    GetTypeAndUnitIdentifierOffsets (LowerLimitExpression.TypeDefPtr, UnitTypeOffsets);
    SubRangeType := CreateTypeDefinition (20, Size, CommonOrdinalType, LowerLimitExpression.TypeDefPtr^.BaseType);
    With SubRangeType^ do
      begin
        LowerLimit := LowerLimitExpression.Value.LongInt;
        UpperLimit := UpperLimitExpression.Value.LongInt;
        OrdinalType := UnitTypeOffsets;
      end;
    ProcessSubrangeType := Pointer (SubRangeType);
  end;

begin
  CheckAndGetNextToken (Token_PACKED);
  CheckForDeclaredIdentifier;
  Case Token of
    Token_TypeIdentifier:     ProcessNonObjectTypeDeclaration := ProcessTypeIdentifier;
    Token_ARRAY:              ProcessNonObjectTypeDeclaration := ProcessArrayType;
    Token_RECORD:             ProcessNonObjectTypeDeclaration := ProcessRecordType;
    Token_Caret:              ProcessNonObjectTypeDeclaration := ProcessPointerType;
    Token_STRING:             ProcessNonObjectTypeDeclaration := ProcessStringType;
    Token_FILE:               ProcessNonObjectTypeDeclaration := ProcessFileType;
    Token_SET:                ProcessNonObjectTypeDeclaration := ProcessSetType;
    Token_LeftParenthesis:    ProcessNonObjectTypeDeclaration := ProcessEnumeratedType;
    Token_PROCEDURE:          ProcessNonObjectTypeDeclaration := ProcessFunctionProcedureType;
    Token_FUNCTION:           ProcessNonObjectTypeDeclaration := ProcessFunctionProcedureType;
    Token_Constant:           ProcessNonObjectTypeDeclaration := ProcessSubrangeType;
    Token_ConstantIdentifier: ProcessNonObjectTypeDeclaration := ProcessSubrangeType;
    Token_Minus:              ProcessNonObjectTypeDeclaration := ProcessSubrangeType;
    Token_Plus:               ProcessNonObjectTypeDeclaration := ProcessSubrangeType;
    Token_SystemFunction:     ProcessNonObjectTypeDeclaration := ProcessSubrangeType;
    Token_NOT:                ProcessNonObjectTypeDeclaration := ProcessSubrangeType;
    else Error (ErrorInType);
  end;
end;

Function ExpectOrdinalType: PTypeDefinition;
Var TypeDef: PTypeDefinition;
begin
  CheckForStringConstantWithControlCharacter;
  TypeDef := ProcessNonObjectTypeDeclaration;
  If TypeDef^.BaseType < btInteger then Error (OrdinalTypeExpected);
  If TypeDef^.Size > 2 then Error (OrdinalTypeExpected);
  ExpectOrdinalType := TypeDef;
end;