Conversely, programs may need to access information that is known to the compiler. There are many uses for such information. A user-level input-output subprogram may need to invoke different algorithms depending on the object machine configuration (with the discrimination being made at compilation time); similarly, it may need to know the size of the storage unit for the object machine, and the size of the objects transferred.
The approach used in Ada is to group such system-dependent information in a package called SYSTEM and to provide certain specific pragmas to establish certain characteristics that may vary between different configurations of the system considered.
|In this section...|
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 defines what addresses are, on the machine considered: on some machines it will be an integer type, on some others an arbitrary record type. The type NAME is an enumeration type that defines names of alternative machine configurations that are handled by the system. For example we could have:
type NAME is (MODEL_20, MODEL_40, MODEL_45, MODEL_70);
As this example suggests, these possible variations are meaningful when dealing with variations of a machine that all have the same type ADDRESS. Although nothing forbids it, it would not make much sense to have a type such as
type NAME is (VAX_11, IBM_370, APPLE_II);
since the other quantities defined in the package SYSTEM are unlikely to be the same for these alternative machines. For example, the following constants are defined in the package:
with SYSTEM; procedure SPECIAL_APPLICATION is ... SIZE : constant := SYSTEM.MEMORY_SIZE; ... end;
The fact that SYSTEM needs to be mentioned in the above manner provides an easy way of finding out which program units make direct use of system-dependent properties.
pragma SYSTEM_NAME(MODEL_45); pragma STORAGE_UNIT(8); -- 8 bits pragma MEMORY_SIZE(2#1#E18); -- 256 kbytes
This has the effect of establishing the corresponding constants:
SYSTEM.SYSTEM_NAME = MODEL_45 SYSTEM.STORAGE_UNIT = 8 SYSTEM.MEMORY_SIZE = 262_144
As mentioned in the section on lexical issues, an attribute designator is always preceded by an apostrophe. The corresponding identifiers are consequently not reserved. Some typical examples are given below.
OLD_PSW'ADDRESS -- the address in storage units of OLD_PSW X.MASK'POSITION -- the starting position of the component MASK in X X.MASK'FIRST_BIT -- the position of the first bit of MASK X.MASK'LAST_BIT -- the position of the last bit of MASK INTEGER'SIZE -- the implemented size of INTEGER in bits
pragma SYSTEM_NAME(MODEL_45); ... case SYSTEM.SYSTEM_NAME is when MODEL_45 | MODEL_70 => ... -- part specific to models with full floating-point support when MODEL_40 => ... -- part specific to models with some floating-point support when MODEL_20 => ... -- part specific to models without floating-point support end case;
The system name established by the pragma is known at compilation time, and the compiler is therefore able to optimize the case statement and generate only the code that corresponds to the current system name. Thus the program can be tailored to a given machine.
This conditional compilation facility is somewhat primitive. More powerful mechanisms for conditional compilation are likely to be provided by the support environments built around the Ada language.