Copyright 1980, 1982, 1983, owned by the United States Government as represented by the Under Secretary of Defense, Research and Engineering. All rights resrved. Provided that notice of copyright is included on the first page, this document may be copied in its entirety without alteration or as altered by (1) adding text that is clearly marked as an insertion; (2) shading or alteration or highlighting existing text; (3) deleting examples. Permission to publish other excerpts should be obtained from the Ada Joint Program Office, OUSDRE(R&AT), The Pentagon, Washington, D.C. 20301, U.S.A. ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ 13.1 Representation Clauses and Implementation-Dependent Features This chapter describes representation clauses, certain implementation- dependent features, and other features that are used in system programming. 13.1 Representation Clauses Representation clauses specify how the types of the language are to be mapped onto the underlying machine. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware). representation_clause ::= type_representation_clause | address_clause type_representation_clause ::= length_clause | enumeration_representation_clause |record_representation_clause A type representation clause applies either to a type or to a first named subtype (that is, to a subtype declared by a type declaration, the base type being therefore anonymous). Such a representation clause applies to all objects that have this type or this first named subtype. At most one enumeration or record representation clause is allowed for a given type: an enumeration representation clause is only allowed for an enumeration type; a record representation clause, only for a record type. (On the other hand, more than one length clause can be provided for a given type; moreover, both a length clause and an enumeration or record representation clause can be provided.) A length clause is the only form of representation clause allowed for a type derived from a parent type that has (user-defined) derivable subprograms. An address clause applies either to an object; to a subprogram, package, or task unit; or to an entry. At most one address clause is allowed for any of these entities. A representation clause and declaration of the entity to which the clause applies must both occur immediately within the same declarative part, package specification, or task specification; the declaration must occur before the clause. In the absence of a representation clause for a given declaration, a default representation of this declaration is determined by the implementation. Such a default determination occurs no later than the end of the immediately enclosing declarative part, package specification, or task specification. For a declaration given in a declarative part, this default determination occurs before any enclosed body. In the case of a type, certain occurrences of its name imply that the representation of the type must already have been determined. Consequently these occurrences force the default determination of any aspect of the representation not already determined by a prior type representation clause. This default determination is also forced by similar occurrences of the name of a subtype of the type, or of the name of any type or subtype that has subcomponents of the type. A forcing occurence is any occurrence other than in a type or subtype declaration, a subprogram specification, an entry declaration, a deferred constant declaration, a pragma, or a representation clause for the type itself. In any case, an occurrence within an expression is always forcing.  A representation clause for a given entity must not appear after an occurrence of the name of the entity if this occurrence forces a default determination of representation for the entity. Similar restrictions exist for address clauses. For an object, any occurrence of its name (after the object declaration) is a forcing occurrence. For a subprogram, package, task unit, or entry, any occurrence of a representation attribute of such an entity is a forcing occurrence. The effect of the elaboration of a representation clause is to define the corresponding aspects of the representation. The interpretation of some of the expressions that appear in representation clauses is implementation_dependent, for example, expressions specifying addresses. An implementation may limit its acceptance of representation clauses to those that can be handled simply by the underlying hardware. If a representation clause is accepted by an implementation, the compiler must guarantee that the net effect of the program is not changed by the presence of the clause, except for address clauses and for parts of the program that interrogate representation attributes. If a program contains a representation clause that is not accepted, the program is illegal. For each implementation, the allowed representation clauses, and the conventions used for implementation- dependent expressions, must be documented in Appendix F of the reference manual. Whereas a representation clause is used to impose certain characteristics of the mapping of an entity onto the underlying machine, pragmas can be used to provide an implementation, with criteria for its selection of such a mapping. The pragma PACK specifies that storage minimization should be the main criterion when selecting the representation of a record or array type. Its form is as follows: pragma PACK (type_simple_name); Packing means that gaps between the storage areas allocated to consecutive components should be minimized. It need not, however, affect the mapping of each component onto storage. This mapping can itself be influenced by a pragma (or controlled by a representation clause) for the component or component type. The position of a PACK pragma, and the restrictions on the named type, are governed by the same rules as for a representation clause; in particular, the pragma must appear before any use of a representation attribute of the packed entity. The pragma PACK is the only language-defied representation pragma. Additional representation pragmas may be provided by an implementation; these must be documented in Appendix F. (in contrast to representation clauses, a pragma that is not accepted by the implementation is ignored). Note: No representation clause is allowed for a generic formal type. References: address clause 13.5, allow 1.6, body 3.9, component 3.3, declaration 3.1, declarative part 3.9, default expression 3.2.1, deferred constant declaration 7.4, derivable subprogram 3.4, derived type 3.4, entity 3.1, entry 9.5, enumeration representation clause 13.3, expression 4.4, generic formal type 12.1.2, illegal 1.6, length clause 13.2, must 1.6, name 4.1, object 3.2, occur immediately within 8.1, package 7, package specification 7.1, parent type 3.4, pragma 2.8, record representation clause 13.4, representation attribute 13.7.2, 13.7.3, subcomponent 3.3, subprogram 6, subtype 3.3, subtype declaration 3.3.2, task specification 9.1, task unit 9, type 3.3, type declaration 3.3.1  13.2 Length Clauses A length clause specifies an amount of storage associated with a type. length_clause ::= for attribute use simple_expression; The expression must be of some numeric type and is evaluated during the elaboration of the length clause (unless it is a static expression). The prefix of the attribute must denote either a type or a first named subtype. The prefix is called T in what follows. The only allowed attribute designators in a length clause are SIZE, STORAGE_SIZE, and SMALL. The effect of the length clause depends on the attribute designator: (a) Size specification: T'SIZE The expression must be a static expression of some integer type. The value of the expression specifies an upper bound for the number of bits to be allocated to objects of the type or first named subtype T. The size specification must allow for enough storage space to accommodate every allowable value of these objects. A size specification for a composite type may affect the size of the gaps between the storage areas allocated to consecutive components. On the other hand, it need not affect the size of the storage area allocated to each component. The size specification is only allowed if the constraints on T and on its subcomponents (if any) are static. In the case of an unconstrained array type, the index subtypes must also be static. (b) Specification of collection size: T'STORAGE_SIZE The prefix T must denote an access type. The expression must be of some integer type (but need not be static); its value specifies the number of storage units to be reserved for the collection, that is, the storage space needed to contain all objects designated by values of the access type and by values of other types derived form the access type, directly or indirectly. This form of length clause is not allowed for a type derived from an access type. (c) Specification of storage for a task activation: T'STORAGE _SIZE The prefix T must denote a task type. The expression must be of some integer type (but need not be static); its value specifies the number of storage units to be reserved for an activation (not the code) of a task of the type. (d) Specification of small for a fixed point type: T'SMALL The prefix T must denote the first named subtype of a fixed point type. The expression must be a static expression of some real type; its value must be greater than the delta of the first named subtype. The effect of the length clause is to use this value of small for the representation of values of the fixed point base type. (The length clause thereby also affects the amount of storage for objects that have this type). Notes: A size specification is allowed for an access, task, or fixed point type, whether or not another form of length clause is also given for the type. What is considered to be part of the storage reserved for a collection or for an activation of a task is implementation-dependent. The control afforded by length clauses is therefore relative to the implementation conventions. For example, the language does not define whether the storage reserved for an activation of a task includes any storage needed for the collection associated with an access type declared within the task body. Neither does it define the method of allocation for objects denoted by values of an access type. For example, the space allocated could be on a stack; alternatively, a general dynamic aliocation scheme or fixed storage could be used. The objects allocated in a collection need not have the same size if the designated type is an unconstrained array type or an unconstrained type with discriminants. Note also that the allocator itself may require some space for internal tables and links. Hence a length clause for the collection of an access type does not always give precise control over the maximum number of allocated objects. Examples: --assumed declarations: type MEDIUM is range 0 .. 65000; type SHORT is delta 0.01 range -100.0 .. 100.0; type DEGREE is delta 0.1 range -360.0 .. 360.0; BYTE : constant := 8; PAGE : constant := 2000; --length clauses: for COLOR'SIZE use 1*BYTE; -- see 3.5.1 for MEDIUM'SIZE use 2*BYTE; for SHORT'SIZE use 15; for CAR_NAME'STORAGE_SIZE use -- approximately 2000 cars 2000*((CAR'SIZE/SYSTEM.STORAGE_UNIT) +1); for KEYBOARD_DRIVERS'STORAGE_SIZE use 1*PAGE; for DEGREE'SMALL use 360.0/2**(SYSTEM.STORAGE_UNIT -1); Notes on the examples: In the length clause for SHORT, fifteen bits is the minimum necessary, since the type definition requires SHORT'SMALL=2**(-7) and SHORT'MANTISSA = 14. The length clause for DEGREE forces the model numbers to exactly span the range of the type. References: access type 3.8, allocator 4.8, allow 1.6, array type 3.6, attribute 4.1.4, collection 3.8, composite type 3.3, constraint 3.3, delta of a fixed point type 3.5.9, derived type 3.4, designate 3.8, elaboration 3.9, entity 3.1, evaluation 4.5, expression 4.4, first named subtype 13.1, fixed point type 3.5.9, index subtype 3.6, integer type 3.5.4, must 1.6, numeric type 3.5, object 3.2, real type 3.5.6, record type 3.7, small of a fixed point type 3.5.10, static constraint 4.9, static expression 4.9, static subtype 4.9, storage unit 13.7, subcomponent 3.3, system package 13.7, task 9, task activation 9.3, task specification 9.1, task type 9.2, type 3.3, unconstrained array type 3.6 13.3 Enumeration Representation Clauses An enumeration representation clause specifies the internal codes for the literals of the enumeration type that is named in the clause. enumeration_representation_clause ::= for type_simple_name use aggregate; The aggregate used to specify this mapping is written as a one-dimensional aggregate, for which the index subtype is the enumeration type and the component type is universal_integer. All literals of the enumeration type must be provided with distinct integer codes, and all choices and component values given in the aggregate must be static. The integer codes specified for the enumeration type must satisfy the predefined ordering relation of the type. Example: type MIX_CODE is (ADD, SUB, MUL, LDA, STA, STZ); for MIX_CODE use (ADD => 1, SUB =.2, MUL => 3, LDA => 8, STA => 24, STZ =>33); Notes: The attributes SUCC, PRED, and POS are defined even for enumeration types with a noncontiguous representation; their definition corresponds to the (logical) type declaration and is not affected by the enumeration representation clause. In the example, because of the need to avoid the omitted values, these functions are likely to be less efficiently implemented than they could be in the absence of a representation clause. Similar considerations apply when such types are used for indexing. References: aggregate 4.3, array aggregate 4.3.2, array type 3.6, attribute of an enumeration type 3.5.5, choice 3.7.3, component 3.3, enumeration literal 3.5.1, enumeration type 3.5.1, function 6.5, index 3.6, index subtype 3.6, literal 4.2, ordering relation of an enumeration type 3.5.1, representation clause 13.1, simple name 4.1, static expression 4.9, type 3.3, type declaration 3.3.1, universal_integer type 3.5.4 13.4 Record Representation Clauses A record representation clause specifies the storage representation of records, that is, the order, position, and size of record components (including discriminants, if any). record_representation_clause ::= for type_simple_name use record [alignment_clause] {component clause} end record; alignment_clause ::= at mod static_simple_expression; component_clause ::= component_name at static_simple_expression range static_range;  The simple expression given after the reserved words at mod in an alignment clause, or after the reserved word at in a component clause, must be a static expression of some integer type. If the bounds of the range of a component clause are defined by simple expressions, then each bound of the range must be defined by a static expression of some integer type, but the two bounds need not have the same integer type. An alignment clause forces each record of the given type to be allocated at a starting address that is a multiple of the value of the given expression (that is, the address modulo the expression must be zero). An implementation may place restrictions on the allowable alignments. A component clause specifies the storage place of a component, relative to the start of the record. The integer defined by the static expression of a component clause is a relative address expressed in storage units. The range defines the bit positions of the storage place, relative to the storage unit. The first storage unit of a record is numbered zero.The first bit of a storage unit is numbered zero. The ordering of bits in a storage unit is machine_dependent and may extend to adjacent storage units (For a specific machine, the size in bits of a storage unit is given by the configuration-dependent named number SYSTEM.STORAGE_UNIT.) Whether a component is allowed to overlap a storage boundary, and if so, how, is implementation-defined. At most one component clause is allowed for each component of the record type, including for each discriminant (component clauses may be given for some, all, or none of the components). If no component clause is given for a component, then the choice of the storage place for the component is left to the compiler. If component clauses are given for all components, the record representation clause completely specifies the representation of the record type and must be obeyed exactly by the compiler. Storage places within a record variant must not overlap, but overlap of the storage for distinct variants is allowed. Each component clause must allow for enough storage space to accommodate every allowable value of the component. A component clause is only allowed for a component if any constraint on this component or on any of its subcomponents is static. An implementation may generate names that denote implementation-dependent components (for example, one containing the offset of another component). Such implementation-dependent names can be used in record representation clauses (these names need not be simple names; for example, they could be implementation-dependent attributes). Example: WORD : constant := 4; -- storage unit is byte, 4 bytes per word type STATE is (A,M,W,P); type MODE is (FIX, DEC, EXP, SIGNIF); type BYTE_MASK is array (0.. 7) of BOOLEAN; type STATE_MASK is array (STATE) of BOOLEAN; type MODE_MASK is array (MODE) of BOOLEAN; type PROGRAM_STATUS_WORD is record SYSTEM_MASK : BYTE_MASK; PROTECTION_KEY : INTEGER range 0 .. 3; MACHINE_STATE : STATE_MASK; INTERRUPT_CAUSE : INTERRUPTION_CODE; ILC : INTEGER range 0 .. 3; CC : INTEGER range 0 .. 3; PROGRAM_MASK : MODE_MASK; INST_ADDRESS : ADDRESS; end record;  for PROGRAM_STATUS_WORD use record at mod 8; SYSTEM_MASK at 0*WORD range 0 .. 7; PROTECTION_KEY at 0*WORD range 10 .. 11; -- bits 8,9 unused MACHINE_STATE at 0*WORD range 12 .. 15; INTERRUPT_CAUSE at 0*WORD range 16 .. 31; ILC at 1*WORD range 0 .. 1; -- second word CC at 1*WORD range 2 .. 3; PROGRAM_MASK at 1*WORD range 4 .. 7; INST_ADDRESS at 1*WORD range 8 .. 31; end record; for PROGRAM_STATUS_WORD'SIZE use 8*SYSTEM.STORAGE_UNIT; Note on the example: The record representation clause defines the record layout. The length clause guarantees that exactly eight storage units are used. References: allow 1.6, attribute 4.1.4, constant 3.2.1, constraint 3.3, discriminant 3.7.1, integer type 3.5.4, must 1.6, named number 3.2, range 3.5, record component 3.7, record type 3.7, simple expression 4.4, simple name 4.1, static constraint 4.9, static expression 4.9, storage unit 13.7, subcomponent 3.3, system package 13.7, variant 3.7.3 13.5 Address Clauses An address clause specifies a required address in storage for an entity. address_clause ::= for simple_name use at simple_expression; The expression given after the reserved word at must be of the type ADDRESS defined in the package SYSTEM (see 13.7); this package must be named by a with clause that applies to the compilation unit in which the address clause occurs. The conventions that define the interpretation of a value of the type ADDRESS as an address, as an interrupt level, or whatever it may be, are implementation-dependent. The allowed nature of the simple name and the meaning of the corresponding address are as follows: (a) Name of an object: the address is that required for the object (variable or constant). (b) Name of a subprogram, package, or task unit: the address is that required for the machine code associated with the body of the program unit. (c) Name of a single entry: the address specifies a hardware interrupt to which the single entry is to be linked. If the simple name is that of a single task, the address clause is understood to refer to the task unit and not to the task object. In all cases, the address clause is only legal if exactly one declaration with this identifier occurs earlier, immediately within the same declarative part, package specification, or task specification. A name declared by a renaming declaration is not allowed as the simple name. Address clauses should not be used to achieve overlays of objects or overlays of program units. Nor should a given interrupt be linked to more than one entry. Any program using address clauses to achieve such effects is erroneous.  Example: for CONTROL use at 16#0020#; -- assuming that SYSTEM.ADDRESS is an integer type Notes: The above rules imply that if two subprograms overload each other and are visible at a given point, an address clause for any of them is not legal at this point. Similarly if a task specification declares entries that overload each other, they cannot be interrupt entries. The syntax does not allow an address clause for a library unit. An implementation may provide pragmas for the specification of program overlays. References: address predefined type 13.7, apply 10.1.1, compilation unit 10.1, constant 3.2.1, entity 3.1, entry 9.5, erroneous 1.6, expression 4.4, library unit 10.1, name 4.1, object 3.2, package 7, pragma 2.8, program unit 6, reserved word 2.9, simple expression 4.4, simple name 4.1, subprogram 6, subprogram body 6.3, system package 13.7, task body 9.1, task object 9.2, task unit 9, type 3.3, variable 3.2.1, with clause 10.1.1 13.5.1 Interrupts An address clause given for an entry associates the entry with some device that may cause an interrupt; such an entry is referred to in this section as an interrupt entry. If control information is supplied upon an interrupt, it is passed to an associated interrupt entry as one or more parameters of mode in; only parameters of this mode are allowed. An interrupt acts as an entry call issued by a hardware task whose priority is higher than the priority of the main program, and also higher than the priority of any user-defined task (that is, any task whose type is declared by a task unit in the program). The entry call may be an ordinary entry call, a timed entry call, or a conditional entry call, depending on the kind of interrupt and on the implementation. If a select statement contains both a terminate alternative and an accept alternative for an interrupt entry, then an implementation may impose further requirements for the selection of the terminate alternative in addition to those given in section 9.4. Example: task INTERRUPT_HANDLER is entry DONE; for DONE use at 16#40#; assuming that SYSTEM.ADDRESS is an integer type end INTERRUPT_HANDLER; Notes: Interrupt entry calls need only have the semantics described above; they may be implemented by having the hardware directly execute the appropriate accept statements. Queued interrupts correspond to ordinary entry calls. Interrupts that are lost if not immediately processed correspond to conditional entry calls. It is a consequence of the priority rules that an accept statement executed in response to an interrupt takes precedence over ordinary, user-defined tasks, and can be executed without first invoking a scheduling action.  One of the possible effects of an address clause for an interrupt entry is to specify the priority of the interrupt (directly or indirectly). Direct calls to an interrupt entry are allowed. References: accept alternative 9.7.1, accept statement 9.5, address predefined type 13.7, allow 1.6, conditional entry call 9.7.2, entry 9.5, mode 6.1, parameter of a subprogram 6.2, priority of a task 9.8, select alternative 9.7.1, select statement 9.7, system package 13.7, task 9, terminate alternative 9.7.1, timed entry call 9.7.3 13.6 Change of Representation At most one representation clause is allowed for a given type and a given aspect of its representation. Hence, if an alternative representation is needed, it is necessary to declare a second type, derived from the first, and to specify a different representation for the second type. Example: -- PACKED_DESCRIPTOR and DESCRIPTOR are two different types -- with identical characteristics, apart from their representation type DESCRIPTOR is record -- components of a descriptor end record; type PACKED_DESCRIPTOR is new DESCRIPTOR; for PACKED_DESCRIPTOR use record -- component clauses for some or for all components end record; Change of representation can now be accomplished by assignment with explicit type conversions: D : DESCRIPTOR; P : PACKED_DESCRIPTOR; P := PACKED_DESCRIPTOR (D); -- pack D D := DESCRIPTOR(P); -- unpack P References: assignment 5.2, derived type 3.4, type 3.3, type conversion 4.6, type declaration 3.1, representation clause 13.1 13.7 The Package System For each implementation there is a predefined library package called SYSTEM which includes the definitions of certain configuration-dependent characteristics. The specification of the package SYSTEM is implementation-dependent and must be given in Appendix F. The visible part of this package must contain at least the following declarations.  package SYSTEM is type ADDRESS is implementation_defined; type NAME is implementation_defined_enumeration_type; SYSTEM_NAME : constant NAME := implementation_defined; STORAGE_UNIT : constant := implementation_defined; MEMORY_SIZE : constant := implementation_defined; --System-Dependent Named Numbers: MIN_INT : constant := implementation_defined; MAX_INT : constant := implementation_defined; MAX_DIGITS : constant := implementation_defined; MAX_MANTISSA : constant := implementation_defined; FINE_DELTA : constant := implementation_defined; TICK : constant := implementation_defined; --Other System_Dependent Declarations subtype PRIORITY is INTEGER range implementation_defined; ... end SYSTEM; The type ADDRESS is the type of the addresses provided in address clauses; it is also the type of the result delivered by the attribute ADDRESS. Values of the enumeration type NAME are the names of alternative machine configurations handled by the implementation; one of these is the constant SYSTEM_NAME. The named number STORAGE_UNIT is the number of bits per storage unit; the named number MEMORY_SIZE is the number of available storage units in the configuration; these named numbers are of the type universal_integer. An alternative form of the package SYSTEM, with given values for any of SYSTEM_NAME, STORAGE_UNIT, and MEMORY_SIZE, can be obtained by means of the corresponding pragmas. These pragmas are only allowed at the start of a compilation, before the first compilation unit (if any) of the compilation. pragma SYSTEM_NAME (enumeration_literal); The effect of the above pragma is to use the enumeration literal with the specified identifier for the definition of the constant SYSTEM_NAME. This pragma is only allowed if the specified identifier corresponds to one of the literals of the type NAME. pragma STORAGE_UNIT (numeric_literal); The effect of the above pragma is to use the value of the specified numeric literal for the definition of the named number STORAGE_UNIT. pragma MEMORY_SIZE (numeric_literal); The effect of the above pragma is to use the value of the specified numeric literal for the definition of the named number MEMORY_SIZE.  The compilation of any of these pragmas causes an implicit recompilation of the package SYSTEM. Consequently any compilation unit that names SYSTEM in its context clause becomes obsolete after this implicit recompilation. An implementation may impose further limitations on the use of these pragmas. For example, an implementation may allow them only at the start of the first compilation, when creating a new program library. Note: It is a consequence of the visibility rules that a declaration given in the package SYSTEM is not visible in a compilation unit unless this package is mentioned by a with clause that applies (directly or indirectly) to the compilation unit. References: address clause 13.5, apply 10.1.1, attribute 4.1.4, compilation unit 10.1, must 1.6, named number 3.2, number declaration 3.2.2, numeric literal 2.4, package 7, package specification 7.1, pragma 2.8, program library 10.1, type 3.3, visibility 8.3, visible part 7.2, with clause 10.1.1 13.7.1 System-dependent Named Numbers Within the package SYSTEM, the following named numbers are declared. The numbers FINE_DELTA and TICK are of the type universal_real; the others are of the type universal_integer. MIN_INT The smallest (most negative) value of all predefined integer types. MAX_INT The largest (most positive) value of all predefined integer types. MAX_DIGITS The largest value allowed for the number of significant decimal digits in a floating point constraint. MAX_MANTISSA The largest possible number of binary digits in the mantissa of model numbers of a fixed point subtype. FINE_DELTA The smallest delta allowed in a fixed point constraint that has the range constraint -1.0 .. 1.0. TICK The basic clock period, in seconds. References: allow 1.6, delta of a fixed point constraint 3.5.9, fixed point constraint 3.5.9, floating point constraint 3.5.7, integer type 3.5.4, model number 3.5.6, named number 3.2, package 7, range constraint 3.5, system package 13.7, type 3.3, universal_integer type 3.5.4, universal_real type 3.5.6  13.7.2 Representation Attributes The values of certain implementation-dependent characteristics can be obtatined by interrogating appropriate representation attributes. These attributes are described below. For any object, program unit, label, or entry X: X'ADDRESS Yields the address of the first of the storage units allocated to X. For a subprogram, package, task unit or label, this value refers to the machine code associated with the corresponding body or statement. For an entry for which an address clause has been given, the value refers to the corresponding hardware interrupt. The value of this attribute is of the type ADDRESS defined in the package SYSTEM. For any type or subtype X or for any object X: X'SIZE Applied to an object, yields the number of bits allocated to hold the object. Applied to a type or subtype, yields the minimum number of bits that is needed by the implementation to hold any possible object of this type or subtype. The value of this attribute is of the type universal_integer. For the above two representation attributes, if the prefix is the name of a function, the attribute is understood to be an attribute of the function (not of the result of calling the function). Similarly, if the type of the prefix is an access type, the attribute is understood to be an attribute of the prefix (not of the designated object: attributes of the latter can be written with a prefix ending with the reserved word all). For any component C of a record object R: R.C'POSITION Yields the offset, from the start of the first storage unit occupied by the record, of the first of the storage units occupied by C. This offset is measured in storage units. The value of this attribute is of the type universal_integer. R.C'FIRST_BIT Yields the offset, from the start of the first of the storage units occupied by C, of the last bit occupied by C. This offset is measured in bits. The value of this attribute is of the type universal_integer. R.C'LAST_BIT Yields the offset, from the start of the first of the storage units occupied by C, of the last bit occupied by C. This offset is measured in bits. The value of this attribute is of the type universal_integer. For any access type or subtype T: T'STORAGE_SIZE Yields the total number of storage units reserved for the collection associated with the base type of T. The value of this attribute is of the type universal_integer. For any task type or task object T: T'STORAGE_SIZE Yields the number of storage units reserved for each activation of a task of the type T or for the activation of the task object T. The value of this attribute is of the type universal_integer.  Notes: For a task object X, the attribute X'SIZE gives the number of bits used to hold the object X, whereas X'STORAGE_SIZE gives the number of storage units allocated for the activation of the task designated by X. For a formal parameter X, if parameter passing is achieved by copy, then the attribute X'ADDRESS yields the address of the local copy; if parameter passing is by reference, then the address is that of the actual parameter. References: access subtype 3.8, access type 3.8, activation 9.3, actual parameter 6.2, address clause 13.5, address predefined type 13.7, attribute 4.1.4, base type 3.3, collection 3.8, component 3.3, entry 9.5, formal parameter 6.1 6.2, label 5.1, object 3.2, package 7, package body 7.1, parameter passing 6.2, program unit 6, record object 3.7, statement 5, storage unit 13.7, subprogram 6, subprogram body 6.3, subtype 3.3, system predefined package 13.7, task 9, task body 9.1, task object 9.2, task type 9.2, task unit 9, type 3.3, universal_integer type 3.5.4 13.7.3 Representation Attributes of Real Types For every real type or subtype T, the following machine-dependent attributes are defined, which are not related to the model numbers. Programs using these attributes may thereby exploit properties that go beyond the minimal properties associated with the numeric type (see section 4.5.7 for the rules defining the accuracy of operations with real operands). Precautions must therefore be taken when using these machine- dependent attributes if portability is to be ensured. For both floating point and fixed point types: T'MACHINE_ROUNDS Yields the value TRUE if every predefined arithmetic operation on values of the base type of T either returns an exact result or performs rounding; yields the value FALSE otherwise. The value of this attribute is of the predefined type BOOLEAN. T'MACHINE_OVERFLOWS Yields the value TRUE if every predefined operation on values of the base type of T either provides a correct result, or raises the exception NUMERIC_ERROR in overflow situations (see 4.5.7); yields the value FALSE otherwise. The value of this attribute is of the predefined type BOOLEAN. For floating point types, the following attributes provide characteristics of the underlying machine representation, in terms of the canonical form defined in section 3.5.7: T'MACHINE_RADIX Yields the value of the radix used by the machine representation of the base type of T (the digits are extended digits in the range 0 to T'MACHINE_RADIX -1). The value of this attribute is of the type universal_integer. T'MACHINE_EMAX Yields the largest value of exponent for the machine representation of the base type of T. The value of this attribute is of the type universal_integer. T'MACHINE_EMIN Yields the smallest (most negative) value of exponent for the machine representation of the base type of T. The value of this attribute is of the type universal_integer.  Note: For many machines the largest machine representable number of type F is almost (F'MACHINE_RADIX)**(F'MACHINE_EMAX), and the smallest positive representable number is F'MACHINE_RADIX ** (F'MACHINE_EMIN -1) References:arithmetic operator 4.5, attribute 4.1.4, base type 3.3, boolean predefined type 3.5.3, false boolean value 3.5.3, fixed point type 3.5.9, floating point type 3.5.7, model number 3.5.6, numeric type 3.5, numeric_error exception 11.1, predefined operation 3.3.3, radix 3.5.7, real type 3.5.6, subtype 3.3, true boolean value 3.5.3, type 3.3, universal_integer type 3.5.4 13.8 Machine Code Insertions A machine code insertion can be achieved by a call to a procedure whose sequence of statements contains code statements. code_statement ::= type_mark'record_aggregate; A code statement is only allowed in the sequence of statements of a procedure body. If a procedure body contains code statements, then within this procedure body the only allowed form of statement is a code statement (labeled or not), the only allowed declarative items are use clauses, and no exception handler is allowed (comments and pragmas are allowed as usual). Each machine instruction appears as a record aggregate of a record type that defines the corresponding instruction. The base type of the type mark of a code statement must be declared within the predefined library package called MACHINE_CODE; this package must be named by a with clause that applies to the compilation unit in which the code statement occurs. An implementation is not required to provide such a package. An implementation is allowed to impose further restrictions on the record aggregates allowed in code statements. For example, it may require that expressions contained in such aggregates be static expressions. An implementation may provide machine-dependent pragmas specifying register conventions and calling conventions. Such pragmas must be documented in Appendix F Example: M : MASK procedure SET_MASK; pragma INLINE(SET_MASK); procedure SET_MASK is use MACHINE_CODE; begin SI_FORMAT'(CODE => SSM, B => M'BASE_REG, D => M'DISP); -- M'BASE_REG and M'DISP are implementation-specific predefined attributes end;  References: allow 1.6, apply 10.1.1, comment 2.7, compilation unit 10.1, declarative item 3.9, exception handler 11.2, inline pragma 6.3.2, labeled statement 5.1, library unit 10.1, package 7, pragma 2.8, procedure 6 6.1, procedure body 6.3, record aggregate 4.3.1, record type 3.7, sequence of statements 5.1, statement 5, static expression 4.9, use clause 5.4, with clause 10.1.1 13.9 Interface to Other Languages A subprogram written in another language can be called from an Ada program provided that all communication is achieved via parameters and function results. A pragma of the form pragma INTERFACE (language_name, subprogram_name); must be given for each such subprogram; a subprogram name is allowed to stand for several overloaded subprograms. This pragma is allowed at the place of a declarative item, and must apply in this case to a subprogram declared by an earlier declarative item of the same declarative part or package specification. The pragma is also allowed for a library unit; in this case the pragma must appear after the subprogram declaration, and before any subsequent compilation unit. The pragma specifies the other language (and therby the calling conventions ) and informs the compiler that an object module will be supplied for the corresponding subprogram. A body is not allowed for such a subprogram (not even in the form of a body stub) since the instructions of the subprogram are written in another language. This capability need not be provided by all implementations. An implementation may place restrictions on the allowable forms and places of parameters and calls. Example: package FORT_LIB is function SQRT (X : FLOAT) return FLOAT; function EXP (X : FLOAT) return FLOAT; private pragma INTERFACE(FORTRAN, SQRT); pragma INTERFACE(FORTRAN, EXP); end FORT_LIB; Notes: The conventions used by other language processors that call Ada programs are not part of the Ada language definition. Such conventions must be defined by these other language processors. The pragma INTERFACE is not defined for generic subprograms. References: allow 1.6, body stub 10.2, compilation unit 10.1, declaration 3.1, declarative item 3.9, declarative part 3.9, function result 6.5, library unit 10.1, must 1.6, name 4.1, overloaded subprogram 6.6, package specification 7.1, parameter of a subprogram 6.2, pragma 2.8, subprogram 6, subprogram body 6.3, subprogram call 6.4, subprogram declaration 6.1 13.10 Unchecked Programming The predefined generic library subprograms UNCHECKED_DEALLOCATION and UNCHECKED_CONVERSION are used for unchecked storage deallocation and for unchecked type conversions. generic type OBJECT is limited private; type NAME is access OBJECT; procedure UNCHECKED_DEALLOCATION(X: in out NAME); generic type SOURCE is limited private; type TARGET is limited private; function UNCHECKED_CONVERSION(S : SOURCE) return TARGET; References: generic subprogram 12.1, library unit 10.1, type 3.3 13.10.1 Unchecked Storage Deallocation Unchecked storage deallocation of an object designated by a value of an access type is achieved by a call of a procedure that is obtained by instantiation of the generic procedure UNCHECKED_DEALLOCATION. For example: procedure FREE is new UNCHECKED_DEALLOCATION(object_type_name, access_type_name); Such a FREE procedure has the following effect: (a) after executing FREE(X), the value of X is null; (b) FREE(X), when X is already equal to null, has no effect; (c) FREE(X), when X is not equal to null, is an indication that the object designated by X is no longer required, and that the storage it occupies is to be reclaimed. If X and Y designate the same object, then accessing this object through Y is erroneous if this access is performed (or attempted) after the call FREE(X); the efeect of each such access is not defined by the language. Notes: It is a consequence of the visibility rules that the generic procedure UNCHECKED_DEALLOCATION is not visible in a compilation unit unless this generic procedure is mentioned by a with clause that applies to the compilation unit. If X designates a task object, the call FREE(X); has no effect on the task designated by the value of this task object. The same holds for any subcomponent of the object designated by X, if this subcomponent is a task object. References: access type 3.8, apply 10.1.1, compilation unit 10.1, designate 3.8 9.1, erroneous 1.6, generic instantiation 12.3, generic procedure 12.1, generic unit 12, library unit 10.1, null access value 3.8, object 3.2, procedure 6, procedure call 6.4, subcomponent 3.3, task 9, task object 9.2, visibility 8.3, with clause 10.1.1 13.10.2 Unchecked Type Conversions An unchecked type conversion can be achieved by a call of a function that is obtained by instantiation of the generic function UNCHECKED_CONVERSION. The effect of an unchecked conversion is to return the (uninterpreted) parameter value as a value of the target type, that is, the bit pattern defining the source value is returned unchanged as the bit pattern defining a value of the target type. An implementation may place restrictions on unchecked conversions, for example, restrictions dependeing on the respective sizes of objects of the source and target type. Such restrictions must be documented in appendix F. Whenever unchecked conversions are used, it is the programmer's responsibility to ensure that these conversions maintain the properties that are guaranteed by the language for objects of the target type. Programs that violate these properties by means of unchecked conversions are erroneous. Note: It is a consequence of the visibility rules that the generic function UNCHECKED_CONVERSION is not visible in a compilation unit unless this generic function is mentioned by a with clause that applies to the compilation unit. References: apply 10.1.1, compilation unit 10.1, erroneous 1.6, generic function 12.1, instantiation 12.3, parameter of a subprogram 6.2, type 3.3, with clause 10.1.1