Note that the message associated with each occurrence need not be static as shown, but could be computed dynamically. Upon completion of the execution of the subprograms‡49, the exception occurrences are retrieved in order of priority and reraised‡51.
47 begin
48 P1; P2; P3;
49 while not Empty(Q)loop
50 begin
51 Reraise_Occurrence(Get(Q’Access).Occurrence.all);
52 exception
53 whenE: others => Put_Line(Exception_Information(E));
54 end;
55 end loop;
56 endExcep;
Each reraised exception is handled ‡53 within the block of the main program by printing the implementation-defined string §11.4.1(13) associated with the occurrence:
EXCEP.EX1 P2 6 EXCEP.EX4 P3 8 EXCEP.EX1 P1 13
11.3
Streams**
Ada.Sequential_IOperforms input–output on values of a single type.Streamsare used for input– output of values of more than one type to a single file. The basic idea is that a value of any type is output as a sequence of bytes which will be reconstructed into a value of the same type upon input. A stream file is much more portable than a binary file: while the encoding of elementary types is implementation-dependent, there is a canonical order defined for encoding composite types §13.13.2(9). Streams are used not only to create files, but also to pass data between the partitions of a distributed system (Section 16.5).
Package Ada.Streams §13.13.1 declares type Root_Stream_Type as an abstract tagged type from which all streams are derived. A stream is composed of a sequence of values of the modular type Stream_Element. Figure 11.1 shows how streams work. Two operations are involved in writing to a stream: the attributeS’Writetransforms values of a subtypeSinto stream elements; then the subprogramWritewrites the elements onto the stream. Reading does these steps in the opposite direction.
11.3 Streams** 183
S ElementsStream Stream S - ElementsStream - Stream
S’Write Write
S’Read Read
Figure 11.1: Streams
§13.13.2
1 The Write, Read, Output, and Input attributes convert values to a stream of elements and reconstruct values from a stream.
2 For every subtype S of a specific typeT, the following attributes are defined.
3 S’Write—S’Write denotes a procedure with the following specification:
4 procedure S’Write(
Stream: accessAda.Streams.Root_Stream_Type’Class;
Item: inT)
5 S’Write writes the value ofItemtoStream.
6 S’Read—S’Read denotes a procedure with the following specification:
7 procedureS’Read(
Stream: accessAda.Streams.Root_Stream_Type’Class;
Item: outT)
8 S’Read reads the value ofItemfromStream.
The subprogramsWriteandReadare not explicitly called; instead, the attributes call them auto- matically §13.13.1(1). You can override the abstract subprogramsWriteandRead§13.13.1(5–6) when you define a stream for a new type, and you can supply an attribute definition clause to specify the attributes §13.13.2(36).
The following case study shows how you can use streams without a detailed knowledge of package
Ada.Streams. To create a stream file, you do not need to explicitly declare a stream. Instead, you can declare a file of typeFile_Typefrom packageAda.Streams.Stream_IO §A.12.1. This package declares a function that returns an access to the stream associated with the file; this access is then used as a parameter of theReadandWriteattributes.
§A.12.1
4 typeStream_Access is access allRoot_Stream_Type’Class; 13 functionStream (File : in File_Type)returnStream_Access;
- - Return stream access
- - for use with T’Input and T’Output
§A.12.1
29 The Stream function returns a Stream_Access result from a File_Type object, thus allowing the stream-oriented attributes Read, Write, Input, and Output to be used on the same file for multiple types.
11.3 Streams** 184
Case study: simulation with streams
This version of the discrete event simulation creates and writes events on a file. The file can then be repeatedly read to rerun the same simulation scenario. (The attributesInputandOutputare used instead of Read andWritefor reasons explained below.) File management of stream files is no different from that of any other file. The essential difference is the declaration of the variableS ‡12
of typeStream_Accessand the assignment toSof the stream obtained from the file‡15,28. Sis then used as a parameter of the attributesEvent’Class’Input ‡30andEvent’Class’Output ‡18–23. - - File: ROCKETST
1 - -
2 - - Discrete event simulation of a rocket.
3 - - Write events to a stream file and read back.
4 - -
5 withEvent_Queue;
6 withRoot_Event.Engine, Root_Event.Telemetry, Root_Event.Steering;
7 use Root_Event;
8 withAda.Streams.Stream_IO; use Ada.Streams.Stream_IO;
9 procedure RocketST is
10 Q: Event_Queue.Queue_Ptr :=newEvent_Queue.Queue;
11 Event_File: File_Type; 12 S: Stream_Access; 13 begin 14 Create(Event_File, Name=>"Event.Str"); 15 S := Stream(Event_File); 16 17 forIin 1..15loop 18 Event’Class’Output(S, 19 Event’Class(Engine.Main_Engine_Event’(Engine.Create))); 20 Event’Class’Output(S, 21 Event’Class(Engine.Aux_Engine_Event’(Engine.Create))); 22 Event’Class’Output(S, Event’Class(Telemetry.Create)); 23 Event’Class’Output(S, Event’Class(Steering.Create)); 24 end loop; 25 Close(Event_File); 26
27 Open(Event_File, In_File, Name=>"Event.Str");
28 S := Stream(Event_File); 29 forIin 1..45loop 30 Event_Queue.Put(Event’Class’Input(S), Q.all); 31 end loop; 32 Close(Event_File); 33
34 while not Event_Queue.Empty(Q.all) loop
35 Root_Event.Simulate(Event_Queue.Get(Q));
36 end loop;
11.3 Streams** 185
The following rule describes how values are transformed into storage elements byReadandWrite: §13.13.2
9 For elementary types, the representation in terms of stream elements is implemen- tation defined. For composite types, the Write or Read attribute for each component is called in a canonical order. The canonical order of components is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream ifT is an array type. IfT is a discriminated type, discriminants are included only if they have defaults. IfT is a tagged type, the tag is not included.
Thus given:
subtypeLineis String(1..120);
Line’Writewill write 120 stream elements (probably bytes), and you must be careful to read it only with the corresponding subprogram Line’Read, which will read the same 120 stream elements. Consider now the following procedure:
procedure Write_String(S:in Stream_Access; Str: in String)is begin
String’Write(S, Str);
endWrite_String;
Each call to the procedure will write the stream elements that represent the current value ofStr. You would need to explicitly write additional information on the stream in order to read it correctly. This can be done automatically by using the attributeOutput§13.13.2(19–21), which is the same asWriteexcept that array bounds and discriminants, if any, are automatically written to the stream. Similarly,Input§13.13.2(22–24) is likeRead, except that it can use this information to determine how much data to read and how to arrange it in an object.
For class-wide types,S’Class’WriteandS’Class’Read§13.13.2(10–16) dispatch to theWriteand
Readattributes according to the specific type of the actual parameter.S’Class’OutputandS’Class’- Input§13.13.2(28–34) are similar except that a representation of the tag is written to the stream and used upon input to reconstruct a value of the corresponding specific type. This is clearly what is needed in the example: the tag of each event is written and restored upon reading. Fortunately,
S’Input andS’Class’Inputare functions, rather than procedures, so we can use the result to give an initial value to an indefinite type, or as an actual parameter to a subprogram with a formal parameter of indefinite type‡30. Note the type conversions toEvent’Class ‡18–23: the attributes expect a value of class-wide type, while theCreatefunctions return values of one of the specific types in the class.
Finally, packageAda.Text_IO.Text_Streams§A.12.2enables you to obtain a stream associated with a text file. This can be used to include ‘binary’ data within the file.
12
Program Structure
12.1
Compilation and execution
This section discusses topics from §10 ‘Program Structure and Compilation Issues’. The basic definitions are given in §10.1:
§10.1
1 Aprogram unitis either a package, a task unit, a protected unit, a protected entry, a generic unit, or an explicitly declared subprogram other than an enumeration literal. Certain kinds of program units can be separately compiled. Alternatively, they can appear physically nested within other program units.
2 The text of a program can be submitted to the compiler in one or morecompilations. Eachcompilationis a succession ofcompilation_units. Acompilation_unitcon- tains either the declaration, the body, or a renaming of a program unit. The repre- sentation for a compilation is implementation-defined.
3 A library unit is a separately compiled program unit, and is always a subprogram, or generic unit. Library units may have other (logically nested) library units as children, and may have other program units physically nested within them. A root library unit, together with its children and grandchildren and so on, form asubsys- tem.
4 An implementation may impose implementation-defined restrictions on compila- tions that contain multiplecompilation_units.
Note that a context clause is associated with a single compilation_unit§10.1.1(3), §10.1.2; if several units ‘with’ing the same package are contained in one compilation, each unit must have a context clause for the package.
Semantic dependencies§10.1.1(23–26) are used to determine both visibility and the order of com- pilation. Before a unit can be compiled, consistentversions of all units upon which the unit de- pends semantically must have been previously compiled §10.1.4(5). For example, if the program depends on two packagesP1andP2which both ‘with’Q, they must have been compiled in the context of the same version ofQ.
Previously compiled units are stored in a conceptual ‘program library’ called an environment
§10.1.4(1). The rules concerning the environment are intentionally left vague to allow any im- plementation that can satisfy the requirements of dependency and consistency.
The GNAT compiler exploits the permission given in §10.1(4) and forbids multiple compilation units in a compilation; instead, a tool is provided for ‘chopping’ a file containing several units into