home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-09-21 | 119.6 KB | 3,488 lines |
-
-
- DRAFT
-
-
- ADA STYLE GUIDE HANDBOOK
-
- MIL-HDBK-1804
-
-
-
-
-
-
- TABLE OF CONTENTS
-
- 1.0 SCOPE
- 1.1 Introduction
- 1.2 Scope
- 1.3 Goals
-
- 2.0 REFERENCED DOCUMENTS
- 2.1 Usage
- 2.2 Referenced Documents
-
- 3.0 DEFINITIONS
- 3.1 Introduction
- 3.2 Handbook
- 3.3 Standard
-
- 4.0 GENERAL REQUIREMENTS
-
- 5.0 SPECIFIC GUIDELINES
- 5.1 Introduction
- 5.2 Lexical Elements
- 5.3 Declarations and Types
- 5.4 Names and Expressions
- 5.5 Statements
- 5.6 Subprograms
- 5.7 Packages
- 5.8 Visibility
- 5.9 Tasks
- 5.10 Program Structure and Compilation Issues
- 5.11 Exceptions
- 5.12 Generic Units
- 5.13 Representation Clauses and Implementation-Dependent Features
- 5.14 Input-Output
-
-
-
- 1. SCOPE.
-
-
- 1.1 Introduction. Ada is a programming language of considerable expressive
- power. ANSI/MIL-STD-1815A, Ada Programming Language, provides a thorough
- definition of the language. However, it does not offer sufficient guidance on
- the appropriate use of Ada's powerful features. This document was developed
- to address "program style" issues and is presented as if the reader does not
- have a mentor to explain all the whys and wherefores. It is for this reason
- the document goes beyond styling techniques in some sections by showing
- what is "good and proper" Ada constructs, denoting what to avoid, or why
- certain constructs are used in a particular manner (proper software
- engineering techniques are also "good style"). Besides, both facets are
- needed in the code produced for the next person in line - the maintainer
- and/or reuser.
-
- 1.2 Scope. Program source code serves two functions: to specify an
- algorithm to be performed on a computer, and to communicate this algorithmic
- design to other human readers. Program style relates to how well a program
- meets the second function. It is a consistent manner of using the features of
- a programming language to promote the maintainability, readability and
- understandability of a program. This is a matter of the form of the final,
- delivered, program source code, as opposed to the process of developing the
- code.
-
- 1.3 Goals.
-
- a. While some of what constitutes "good style" is subjective and
- somewhat arbitrary, it is important that the style of a program be consistent
- throughout the program. The primary goal of this guide is to promote such
- consistent use of good style across large numbers of Ada programs. The whole
- intent of "good style" is to increase the readability of these programs.
- Therefore, these guidelines follow from general principles of program
- readability and understandability.
-
- b. The program should reflect the natural levels of abstraction in the
- problem domain, so that the reader can reasonably comprehend each level
- individually. Just as entites in real world applications have structure and
- organization, so should Ada software systems. Furthermore, on a gobal level,
- the overall software architecture should exhibit clarity and be readilly
- comprehended. Ada coding style plays an important role in attainment of
- these goals.
-
- c. There are several features in Ada which are unfamiliar to many
- programmers. There is thus a tendency to either underuse these features or to
- use them inappropriately. A feature of Ada should generally not be ignored,
- but neither should it be used in excess. The guidelines highlight the proper
- use of Ada features. Keep in mind, there are features in the Ada language
- that when used, are considered poor programming and/or software engineering
- practices. Most of this knowledge has become apparent through the use of the
- language. This guide's intent is to alert the reader of these practices; and
- although they are functionally correct, should be avoided. (Words to that
- effect will be used).
-
- d. The textual format of a program should be pleasing to the eye and
- promote the readability and understandability of the program. The format
- should highlight the structure of a program and the role of a program as a
- model of the problem domain. Just as the careful layout of a book can enhance
- written communication, the careful layout of a program can enhance the
- communication of algorithmic design to another human. The consistent use of
- formatting style is especially important, because it allows readers to become
- accustomed to the familiar layout of the program constructs. An automated
- formatting program is particularly helpful, but even in the absence of such a
- tool, much can be gained from a common format style.
-
- 2. REFERENCED DOCUMENTS
-
-
- 2.1 Usage.
-
- a. This is not a static document. Other references need to be consulted
- to provide a valid mix of ideas and "legal" practices when coding Ada. Where
- applicable, conformity among the references should be obtained. Instances,
- for example, where adopting an ISO or ARTEWG practice does not have a negative
- impact, should be encouraged.
-
- b. A listing of other references beside the one given in paragraph 2.2
- will not be made. Other documents were referenced; however, to list them
- could be construed as an endorsement of the document to the exclusion of
- others. Better none than to miss one.
-
- 2.2 Reference documents. ANSI/MIL-STD-1815A, Ada Programming Language.
-
- 3. DEFINITIONS
-
-
- 3.1 Introduction. The definitions and acronyms provided in Ada Reference
- Manual - ANSI/MIL-STD-1815A are applicable for use with this handbook. Since
- this handbook is intended to be a companion document to the Ada Programming
- Language manual, the definitions and acronyms are not restated here.
-
- 3.2 Handbook. The term "Handbook" (capitalization intended) refers to this
- document, MIL-HDBK-1804, Ada Style Guide Handbook. This simplification is
- used to improve readability.
-
- 3.3 Standard. The term "Standard" (capitalization intended) refers to
- ANSI/MIL-STD-1815A, Ada Programming Language. This simplification is to
- improve readability.
-
- 4. GENERAL REQUIREMENTS
-
- NOT APPLICABLE
-
- 5. SPECIFIC GUIDELINES
-
-
- 5.1 Introduction. This section contains fourteen major subparagraphs (5.1
- through 5.14) corresponding to the fourteen chapters of ANSI/MIL-STD-1815A,
- Ada Programming Language. This provides a standard frame of reference for the
- discussion of Ada features. Where appropriate, the guide includes examples
- and justifications for various guidelines. Some of the major subparagraphs,
- themselves, have an "Examples" subparagraph giving additional, longer examples
- for the topic. When more than one example is shown, the order of preference
- will be with the first example, then the second, etc.
-
- 5.1.1 Correlation. Each major subparagraph bears the same title as its
- corresponding chapter in the Standard, e.g. Lexical elements is chapter 5.2
- in this style guide. In the Standard, the basic definition starts in chapter
- 2.
-
- 5.1.2 Handbook Format.
-
- a. Some constraints are implicity included in this Handbook. The reason
- - the explanations are directed towards the Management Information Systems
- environment moreso than the real-time, embedded systems environment. (Granted,
- Ada was initially intended for the latter). Problems in "style" may occur
- when information presented is slanted towards large memory features instead of
- constrained, limited memory systems. (Block statements come to mind as an
- example). Therefore, for real-time programmers/maintainers, comments starting
- with "REAL_TIME" will be included and are directed to their use.
-
- b. Non-numbered paragraphs are editorial comments included to provide
- further clarifications. Also, information in this category and begun with
- the notation of "NOTE:", are of specific interest and special attention should
- be paid to them.
-
- 5.1.3 Non-compliance. It should be noted that some compilers contain
- restrictions that may not allow compliance with all of the guidelines contained
- in Section 5.2 and beyond. An example would be the inability of a system to
- allow the use of the underscore. The Standard, chapter 2.1, "Charater Set",
- includes the underscore as an allowable special character. Obviously, a
- physical impasse is apparent, and as such, should be documented up front in
- the program. This is a basic premise of this guide - if you cannot comply
- with the guidance, information stating such should appear in the program.
-
- 5.1.4 Basic Style Format.
-
- a. The emphasis in style is to have distinct, recognizable parts. That
- is, information to be defined should be on one side, information doing the
- defining on the other; or, on one line, with the defining components on the
- following line(s). The right-left concept comes more into play with the usage
- of the assignment operator (see 5.2.2.7). The one-line-next-line concept will
- cover the majority of style formating use.
-
- b. The reasons for promoting the one-line-next-line style are reada-
- bility and understandability. From the first character on a line to its
- associated semicolon, some information contained between the two must be
- dominant, some must be subordinate. Whether all the information is on one
- line or many does not matter syntactically, it does for readability and
- understandability. Therefore, to promote easier end of line comments,
- maintainability, as well as readability and understandability, the following
- basic style is recommended (exceptions are delineated in other chapter 5
- subchapters):
-
- 1) Reserved words denoting various elements of an Ada program and
- their associated names should be on one line, their subordinate information
- on the succeeding line(s), e.g.
-
- procedure <procedure name>
- [<parameter specification>];
-
- function <function name>
- [<parameter specification>];
-
- 2) Type declarations or other reserve word phrases ending with a verb
- should be on one line, its subordinate information on the succeeding line(s),
- e.g.
- type (identifier> is
- <type definition>;
-
- task type <task name> is
- <entry statement>;
- end <task name>;
-
- task body <body name> is separate;
-
- <loop name>:
- while <expression> loop
- <statement>
- end loop <loop name>;
-
- 3) Objects, strings and similar declarations where the colon
- differentiates the identifier from the definition, should be "muliti-lined"
- by placing the identifier on one line and the colon and the definition on
- the subsequent line(s), e.g.
-
- <object name>
- : <definition>;
-
- 4) Information being protrayed using the assignment operator should
- use the left-right concept, e.g.
-
- identifier := <expression> [<operator starting continued expression>
- <continued expression>];
-
- The expression(s) are continued by leaving an operator on the previous line
- and continuing the expression directly under the start of the expression on
- the line above (see 5.2.2.7 for an example).
-
- 5) The basic formats are not used if multiple occurrences of the same
- form are used in a subordinate role (see 5.3.8.4 b), e.g.
-
- package <package name> is
- procedure <procedure name> [<passing parameters>];
- procedure <procedure name> [<passing parameters>];
- function <function name> [<passing parameters>];
- function <function name> [<passing parameters>];
- private
- end <package name>;
-
- NOTE: if any of the procedures or functions in the above example require
- continuation to the next line, all of the subordinate information should be
- continued in the same manner (see 5.2.2.7).
-
- 5.2 Lexical elements.
-
-
- 5.2.1 The package STANDARD. Language words with predefined meanings in the
- package STANDARD should not be redefined.
-
- 5.2.2 Formatting of lexical elements.
-
- 5.2.2.1 Indentation. The preferred indentation level is two spaces.
- Exceptions are in some cases continuations.
-
- NOTE: The emphasis is more on the indention being consistent throughout the
- program than the exact number of spaces. The key word is consistent!
-
- 5.2.2.2 Character set. Full use should be made of the ISO character set
- where available. Alternate character replacements should only be used when
- the corresponding graphical symbols are not available or are reserved for
- other uses (see chapter 2.10, the Standard).
-
- 5.2.2.3 Upper/lower case.
-
- NOTE: This area is one of just a few that cause the most consternation among
- Ada coders because rationale can be provided for numerous formating methods.
- All things considered, the following was thought best ...
-
- a. Reserved words and attributes should appear in lower case, e.g.
-
- package body Choice is separate;
-
- type REAL is digits 8;
-
- b. All identifiers except type, enumeration value and attribute
- identifiers should be in mixed upper and lower case. The first letter of each
-
- word in the identifier should be in upper case with other characters in lower
- case, unless a word is normally written in all upper case, as are acronyms.
-
- Display_Device
- Number_Of_User Names
- Get_FHST_Data
- Package_Name
- List'first -- "first" is an attribute designator (preceeded by an
- -- apostrophe), not a reserve word.
-
- c. Type names, subtype names and enumeration literals should appear in
- all upper case.
-
-
- type COLOR is (WHITE, RED, YELLOW, GREEN, BLUE, BROWN, BLACK);
- subtype RAINBOW is COLOR range RED .. BLUE;
-
- type ARMED_FORCE is (ARMY, AIR_FORCE, NAVY, MARINES);
-
- 5.2.2.4 Identifiers.
-
- a. Identifier names should be meaningful and easily distinguishable from
- each other, including loop parameters, array indices, and common mathematical
- variables. Names of objects and types should be nouns or noun phrases; names
- of procedures should be verbs or verb phrases; and, names of enumeration
- literals should be adjectives if they are meant to represent properties.
-
- b. Distinct words in identifiers should always be separated by
- underscores.
-
- c. The use of abbreviations in identifiers should be avoided. When used,
-
- an abbreviation should be significantly shorter than the word it abbreviates,
- and its meaning should be clear. The same abbreviations should be used
- consistently throughout a project, precedence is given to sanctioned
- standard data elements and codes or existing functional data dictionaries
- abbreviations, e.g. MGT for management; RQD for required.
-
- d. Acronyms should be avoided if at all possible.
-
- 5.2.2.5 Spaces. Single spaces should be used consistently between lexical
- elements to enhance readability.
-
- 5.2.2.6 Blank lines.
-
- a. Blank lines should be used to group logically related lines of text.
-
- A careful use of blank lines can greatly enhance readability by making the
- logical structure of a sequence of lines more textually obvious. However,
- the overuse of blank lines (e.g., "double spacing") defeats the very purpose
- of grouping and can actually reduce readability. Blank lines should thus
- always be used with grouping in mind and not just to increase white space.
-
- b. A blank line should always preceed and follow a construct whose last
- line is not at the same indentation level as its first line.
-
- -- preceeded by a blank line
-
- type COMPLEX is
- record
- Real : REAL := 0.0;
- Imaginary : REAL := 0.0;
- end record;
-
- -- Followed by a blank line
-
- 5.2.2.7 Continuation of statements.
-
- a. tatements extending over multiple lines should be broken after reserved
- words, operators, delimeters, commas, or if a distinct entity can be
- separated. The one-line-next-line concept should be utilized as discussed
- in the basic formats section, e.g.
-
- package Information is
- procedure Information_Left_Over
- (Return_File : in RETURN_FILE_TYP);
- function Check_Last_Element
- (Return_File : in RETURN_FILE_TYP)
- return BOOLEAN;
- end Information;
-
- For assignments, use the left-right concept, e.g.
-
- Corrected-Value := ((1 + Sensor_Scale) * Raw_Value) +
- (Distortion_Factor * Distortion_Value) -
- Sensor_Bias;
-
- NOTE: Redundant parenthesis are used (see 5.4.2.2).
-
- b. Long strings extending over more than one line should be broken up at
- natural boundaries, appropriate to the meaning of the contents of the string,
- if any.
-
- "This is a rather long string, so it is likely that "
- & "it will extend over more than one line"
-
- NOTE: Do not confuse continuation with basic format (see 5.1.4).
-
- 5.2.2.8 Comments.
-
- a. Comments should be used to add information for the reader or to high-
- light sections of code, and should not merely paraphrase the code.
-
- b. Comments should begin with the "--" aligned with the indentation level
-
- of the code that they describe, or to the right of the code, aligned with
- other such comments.
-
- -- Check if the user has special authorization
- if Authority = SPECIAL then
- Display_Special_Menu; -- All operations are allowed
- else
- Display_Normal_Menu; -- Only normal operations allowed
- end if;
-
- c. Refrain from including any character after the "--", even though
- the Standard gives an example of numerous hyphens in a row. Several formal
- specification languages (commercial-off-the-shelf tools) use the
- --<special symbol> in development and production of automated specification
- documents.
-
- 5.2.2.9 Length of a Line. The preferred length of a line is 72 characters.
- Various restrictions begin to occur, window boarders, etc., if the line
- extends further.
-
- 5.3 Declarations and types.
-
- NOTE: Be advised and understand the limitations imposed with predefined
- numeric types (FLOAT, INTEGER, etc.) This is due to their implementation
- dependent precision.
-
- 5.3.1 Constants.
- a. An object should be declared constant if its value is intended not to
- change.
-
- Declaring an object to be constant clearly signals both the human reader and
- the compiler the intention that its value will not change. This not only
- increases readability, it also increases reliability because the compiler will
- detect any attempt to tamper with the object. Also, it can result in some
- decrease in executable size and better run time efficiency.
-
- b. Defining a constant object is preferable to using a numeric literal
- or expression with constant value, as long as the constant object has an
- intrinsic conceptual meaning. Constants should not be used to avoid
- enumeration type.
-
- There is no use in defining a constant object when a numeric literal is
- obviously more appropriate, for example: using "One" instead of "1." However,
-
- the use of constant objects with intrinsic meaning (such as "Buffer_Size" or
- "Field_Of_View") can greatly increase the readability of code. Further, the
- code is more maintainable since a change in a value will be localized to the
- constant declaration.
-
- c. A named number (i.e., a constant object with type universal-integer
- or universal-real) should be used only for values that are truly "universal"
- and "typeless." Other numeric constants should be declared with an explicit
- type.
-
- Constants, such as "Pi", and cardinal integers (e.g., a "number of things")
- should be named numbers. Note also that declaring a constant in terms of a
- predefined numeric type (INTEGER, FLOAT, etc.) in most cases has no advantage
- over a named number since these predefined types provide only range and
- accuracy constraints and not additional conceptual meaning. In fact, since
- the range and accuracy of predefined numeric types is implementation-defined,
- portability can be increased by using named numbers, in those cases where a
- constant of a user-defined type is not more appropriate.
-
- Pi
- : constant := 3.141_592_65;
-
- Number_Of Sensors -- This is a named number
- : constant := 4;
-
- Main_Sensor_Number
- : constant SENSOR_INDEX := 2;
-
- REAL_TIME: Multiplication or division of a fixed point type by an integer
- results in an object of that fixed point type (as opposed to multiplication
- of an integer by an fixed point type, which results in an integer). Using
- a constant of universal fixed rather than a specified fixed point type may
- force the introduction of an explicit type conversion, possible reducing the
- efficiency of the multiplication.
-
- 5.3.2 Types and Subtypes.
-
- 5.3.2.1 Types. Separate types should be used for values that belong to
- logically independent declarations, and for distinct concepts.
-
- type X_COORDINATE is
- range 1 .. 640;
-
- type Y_COORDINATE is
- range 1 .. 480;
-
- type PIXEL_VALUE is
- range 0 .. 255;
-
- type IMAGE_GRID is
- array (X_COORDINATE, Y_COORDINATE) of PIXEL_VALUE;
-
- A data type characterizes a set of values and a set of operations applicable
- to objects of the type. In the above example, each coordinate has a type
- because coordinates are independent entities. Explicitly declaring these
- types makes the concepts more obvious to a human reader and also allows the
- detection of mistakes such as:
-
- X_Coord : X_COORDINATE := 1;
- Y_Coord : Y_COORDINATE := 1;
- Pixel : PIXEL_VALUE := 0;
- Image : IMAGE_GRID;
-
- Image (Y_Coord, X_Coord) := Pixel; -- Should be "(X_Coord, Y_Coord)"
-
- The drawback of this kind of typing is that the following construct is
- illegal:
-
- if X_Coord = Y_Coord then -- ILLEGAL since X_Coord and Y_Coord
- ... -- have different types
-
- A type conversion must be used:
-
- if X_Coord = X_COORDINATE (Y_Coord) then
- ...
-
- Note that, depending on context (and compiler quality), there may or may not
- be some run time penalty associated with type conversion (e.g., testing of
- range constraints).
-
- 5.3.2.2 Subtypes. For understandability and maintainability, all types and
- subtypes should be grouped together. This ensures the type being subtyped,
- if it is user defined, already exists in the program. Subtypes should be
- used if the problem consists of subsets of the base type, or subsets of the
- subsets, e.g.
-
- type NON_NEGATIVE is range 0 .. INTEGER'last;
- subtype ORDER_SIZE is NON_NEGATIVE range 0 .. 1_000_000;
- subtype SMALL_ORDER is ORDER_SIZE range 0 .. 50;
- subtype BIG_ORDER is ORDER_SIZE range 51 .. 1_000_000;
-
- 5.3.3 Enumeration types. An enumeration type should always be used in
- preference to an integer type, unless the logical nature of the concept to be
- modeled demands the other.
-
- For example the type:
-
- type DEVICE_MODE is
- (READ_ONLY, WRITE_ONLY, READ_WRITE);
-
- is preferable to encoding DEVICE_MODE as an integer 0, 1 or 2.
-
- 5.3.4 "Point" types.
-
- 5.3.4.1 Floating point types.
-
- a. To enhance portability, always specify the range, constraints and
- accuracy of a floating point type.
-
- b. The precision for the predefined floating types (FLOAT, etc.) is
- implementation-dependent, though all implementations should provide at least 6
- decimal digits of accuracy. Explicitly declaring floating point accuracy
- should yield more reliable, efficient and portable code.
-
- 5.3.4.2 Fixed point types. Fixed point types should be expressed with the
- constraints and boundaries appropriate for the identifier. Explicitly
- stating these parameters, as noted with floating point types, enhances the
- portability because the type will be code dependent instead of machine
- dependent.
-
-
- 5.3.5 Record types.
- a. A record type is preferred when each component can be sensibly
- named, the components do not need to be dynamically indexed, and the
- combination of components is needed to provide full meaning to the type, e.g.
-
- type COMPLEX is
- record
- Real : REAL := 0.0;
- Imaginary : REAL := 0.0;
- end record;
-
- "COMPLEX" needs both the Real and the Imaginary part to have meaning.
- Whereas, arrays are useful when one or more component(s) are primary over
- others, or access is needed via indexing, e.g.
-
- type WORK_DAY is (MON, TUE, WED, THU, FRI, SAT, SUN, HOL);
- type DOLLARS is array (5 .. 7) of INTEGER;
- type OVERTIME is array (WORK_DAY) of DOLLARS;
-
- Once the dollars are "loaded" into OVERTIME, computations, etc. will be
- easier than having to scan records for the appropriate OVERTIME.
-
- b. Overcomplicated record structures should be avoided by grouping
- related data into subrecord types.
-
- type COORDINATE is
- record
- Row : INTEGER range 1 .. 20;
- Column : INTEGER range 1 .. 30;
- end record;
-
- type WINDOW is
- record
- Top_Left : COORDINATE;
- Bottom_Right : COORDINATE;
- end record;
-
- c. Discriminants. Discriminants should be used whenever the object
- has closely related variances which would more easily be understood tied to
- a single data type, e.g.
-
- type BUFFER (Size : BUFFER_SIZE := 100) is
- record
- Position : BUFFER_SIZE := 0;
- Value : STRING (1 .. Size);
- end record;
-
- A record component may or may not depend on the discriminant. In the above
- example, the component Value depends on the discriminant Size for its upper
- boundary.
-
- d. Enumeration types should be used for discriminants of record
- variants whenever possible. A discriminant should generally have a default
- initialization only if the discriminant value is intended to change over the
- lifetime of an object.
-
- e. Variant parts. One of the strong features of Ada is the use of
- variants in defining alternate lists of components. This is good software
- engineering practice because all possible uses of a discriminant are defined
- and in one location, with the constraints being specified in the variable or
- a subtype declaration, e.g. (from the Standard)
-
- type DEVICE is (PRINTER, DISK, DRUM);
- type STATE is (OPEN, CLOSED);
-
- type PERIPHERAL (Unit : DEVICE := DISK) is
- record
- Status : STATE;
- case Unit is
- when PRINTER => Line_Count : LINE_RANGE;
- when others => Cylinder : CYLINDER_INDEX;
- Track : TRACK_NUMBER;
- end case;
- end record;
-
- In this example, a general record type is made for the three types of
- peripheral units. From there, subtypes can be created of specific
- peripheral units, e.g.
-
- subtype DRUM_UNIT is PERIPHERAL (DRUM);
-
- If a constraint was not stated in a subtype or variable declaration, the
- compiler would assume the default of DISK.
-
- 5.3.6 Access types.
-
- a. Generally, access types should not be used when static types and
- stack allocation would be sufficient.
-
- b. Generally access types should be used only when it is necessary
- to have data structures with dynamic pointers or to dynamically create
- objects. However, access types may be needed for static objects if this leads
-
- to a more consistent programming style (e.g., so that similar static and
- dynamic objects are treated identically). For example, if linked lists are
- used in a program, there may be some lists which are constant, but which are
- still implemented as linked lists using access types. This would allow, for
- example, passing these constant lists to subprograms which also handle dynamic
-
- lists.
-
- REAL_TIME: There are certain instances where it is desirable to use access
- types to address static objects in embedded real-time applications. Certain
- Ada compilers support only limited types of parameters when pragma INTERFACE
- is used (to assembly language, C, or some other language selected for
- efficiency or interface requirements), and access types are usually one of
- those supported when other static types, such as record structures, are not.
-
- 5.3.7 Object declarations.
-
- a. A single object declaration should be used to gather objects of the
- same type, e.g.
-
- Table Size,
- Table Index,
- Current Entry
- : TABLE_RANGE;
-
- b. An object should not be declared using a unnamed constrained array
- definition.
-
- The unnamed array definition is the only case in Ada where an object can be
- declared to be of a type which does not have a name. Instead, the array type
- should be named in an array type declaration, and that name used in the object
- declaration, even if there is only one object declared of that type.
-
- type POOL_TYP is
- array (POOL_RANGE) of CHARACTER;
-
- POOL
- : POOL_TYP;
-
- c. Objects should generally be initialized. Where possible, objects
- should always be initialized by their declaration, rather than in later code.
-
- Is_Found
- : BOOLEAN := FALSE;
-
- 5.3.8 Formatting of declarations and types.
-
-
- 5.3.8.1 Commenting.
-
- a. Type declarations (or groups of declarations) should be commented to
- indicate what is being defined, if that is not obvious from the type
- declaration itself.
-
- type VELOCITY is -- Inertial velocity relative to the Earth
- array (1 .. 3) of FLOAT; -- Three test samples needed for comparison
-
- b. Object declarations should always be commented if the object
- definition is unclear from the object and type identifiers alone. Note
- that those properties of an object obtained from its type should not be
- repeated in comments on the object declaration.
-
- Spacecraft_Velocity -- Spacecraft orbital velocity, assuming a
- : VELOCITY; -- circular orbit
-
- 5.3.8.2 Indentation. All declarations in a single declaration part should
- begin with the same indentation level.
-
- 5.3.8.3 Type definitions.
-
- a. Array type definitions should have one of the following formats:
-
- type <type name> is
- array <index definition> of <subtype indication>;
-
- type <type name> is
- array <index definition>
- of <subtype indication>;
-
- b. Record type definitions should have one of the following formats:
-
- type <type name> is
- record
- <component declaration>
- <component declaration>
- end record;
-
- type <type name>
- ( <discriminant declaration>;
- <discriminant declaration> ) is
- record
- <component declaration>
- case <discriminant name> is
- when <choices> =>
- <component declaration>
- <component declaration>
-
- end case;
-
- end record;
-
- c. All <component declarations> and <discriminant declarations> should be
-
- formatted like object declarations (see paragraph 5.3.8.4).
-
- d. Other type definitions should be formatted as follows:
-
- type <type name> is
- <type definition>;
-
- subtype <type name> is
- <subtype indication>;
-
- e. Long enumeration type definitions should be formatted into easily
- readable columns.
-
- 5.3.8.4 Formatting of object declarations.
-
- a. Object declarations should have one of the following formats. The
- preferred formats are:
-
- <object name>
- : <subtype indication> := <expression>;
-
- b. When the subtype indication and/or expression is long, or when comments
-
- are needed, it may be necessary to futher continue the declaration as follows:
-
- <object name>
- : <subtype indication> -- narrative explanation of subtype
- := <expression>;
-
- c. Declarations containing short identifiers may also be formatted all on
- one line, and is the perferred method when used as subordinate or supportive
- declarations, e.g.
-
- <object name> : <subtype indication> := <expression>;
-
- In this case, all such declarations textually grouped together or appearing as
- components in a single record definition or in a single parameter list should
- have their ":" and ":=" symbols aligned.
-
- 5.3.9 Examples for declarations and types.
-
-
- 5.3.9.1 Example 3X1.
-
- type SENSOR_ARRAY is
- array (NATURAL range <>) of SENSOR;
-
- UARS_Sensors -- Sensor configuration for the
- : SENSOR_ARRAY (1 .. Num_Sensors); -- UARS control system
-
- 5.3.9.2 Example 3X2.
-
- type JULIAN_DATE_NUMERIC is
- record
- Two_Digit_Year : INTEGER range 0 .. 99;
- Numeric_Day : INTEGER range 1 .. 366;
- end record;
-
- 5.3.9.3 Example 3X3.
-
- type DEVICE is
- (PRINTER, DISK, DRUM);
-
- type STATE is -- Operational state of a
- (OPEN, CLOSED); -- device.
-
- type PERIPHERAL
- (Unit : DEVICE := DISK) is
- record
- Status : STATE;
- case Unit is
- when PRINTER =>
- Average_Lines_Per_Page : INTEGER range 1 .. Page_Size;
- when DISK | DRUM =>
- Cylinder : CYLINDER_INDEX;
- Track : TRACK__NUMBER;
- end case;
- end record;
-
- 5.4 Names and expressions
-
-
- 5.4.1 Aggregates.
-
- a. Aggregates are preferable to individually setting all or most of the
- components of an array or record.
-
- b. Named aggregates should be used where possible.
-
- 5.4.2 Static expressions. Being able to differentiate between static and
- universal expressions and their respective uses will assist in understanding
- different characteristics of software engineering practices, i.e. to
- maximize accuracy, static expressions should be used. The detail can be
- provided to the depth desired, e.g.
-
- Pi : constant := 3.141_592;
- Two_Pi : constant := 6.283_185;
-
- Whereas, understandability and readability are increased using universal
- expressions, e.g.
-
- Half_Pi : constant := Pi / 2.0;
- Deg_To_Rad : constant := Half_Pi / 90.0;
- Rad_To_Deg : constant := 1.0 / Deg_To_Rad;
-
- NOTE: Two_Pi could have been gained by the expression Pi * 2.0; however,
- if accuracy is needed to six decimal places, the static expression must be
- used or the original Pi would have to show additional decimal places. (The
- seventh decimal value for Pi is a 6; therefore, doubling Pi, the sixth
- decimal is a 5, not a 4 as would be obtained).
-
- 5.4.3 Short-circuit control.
-
- a. Short-circuit control forms should generally be used only to avoid
- evaluation of an undefined or illegal expression. Short circuit operators
- should not be used to optimize execution.
-
- (N /= 0) and then (Total/N > Limit)
-
- (Index = 0) or else User(Index).Not_Available
-
- b. The short-circuit control forms should be used to signal to a human
- reader that the correctness of the second condition depends on the results of
- the first. They should not be used for micro-efficiency reasons, concerns
- better handled by an optimizing compiler. If efficiency considerations are
- substantially important, "if" statements should be used instead of the short-
- circuit forms with functions used to avoid repeated code, if necessary.
-
- REAL_TIME: Memory considerations are a concern; therefore, the opposite
- should be true, i.e. short-circuits should be used over "if" statements.
-
- 5.4.4 Type qualification.
-
- a. An explicit type conversion should not be used if a type qualified
- expression is meant.
-
- Good : LONG_FLOAT'(3.141_59)
- Bad : LONG_FLOAT (3.141_59)
-
- A qualified expression is used to state explicitly the type, and possibly sub-
- type, of a value. A type conversion, however, results in the dynamic
- conversion of a value to a target type. Sometimes a type conversion can be
- used to serve the purpose of a type qualification. However, if the operand is
- already of the desired base type, a conversion is not really necessary and a
- qualification should be used instead.
-
- b. Type qualification should be avoided if possible, especially when
- the type of an enumeration literal or aggregate is not known from context.
- For example:
-
- type COLOR is
- (BLACK, RED, GREEN, BLUE, WHITE);
-
- type LIGHT is
- (RED, YELLOW, GREEN);
-
- procedure Set
- ( Color_Code : in COLOR );
-
- procedure Set
- ( Color-_Code : in LIGHT );
- ...
-
- Set (COLOR'(RED)); -- Type qualification must be used here to
- Set (LIGHT'(RED)); -- resolve the overloading of Set and RED
-
- It would be better in this case to rename one of the Set procedures
- or to at least give them different parameter names so the overloading
- could be resolved using name notation.
-
- 5.4.5 Formatting of names and expressions.
-
- 5.4.5.1 Names.
-
- a. The name for a type should be a common noun indicating the class of
- the objects it contains.
-
- DEVICE
- AUTHORITY_LEVEL
- USER_NAME
- PHONE_LIST
-
- A type name should end with the suffix "_TYP" if convolution will develop
- among other types (enumeration, etc.) with the same name.
-
- EMPLOYEE_TYP
- SCHEDULE_TABLE_TYP
- COLOR_TYP
-
- NOTE: The POSIX/Ada committee has recommended the suffix "_TYPE" not be used
- because of various problems, and it will not be used in the Ada/POSIX
- interface standard.
-
- b. The names of non-BOOLEAN valued objects should be nouns, preferably
- more precise than the names of types.
-
- Current_User
- : USER_NAME;
-
- Output_Device
- : DEVICE;
-
- Schedule_Table
- : SCHEDULE_TABLE_TYP;
-
- New_Employee
- : EMPLOYEE_TYP;
-
- BOOLEAN valued objects should have predicate-clause (e.g., "Is Open") or
- adjective names.
-
- User_Is_Available
- List_Empty
- Done
- Not_Ready
- Is_Waiting
-
- 5.4.5.2 Parentheses. Syntactically redundant parentheses should generally be
- used to enhance the readability of expressions, especially by indicating the
- order of evaluation. This is true even for single expressions where operators
- of different precedence levels are present.
-
- For example:
-
- Variance := (Roll_Error ** 2) + ((Yaw_Error ** 2) / 2);
-
-
- 5.4.5.3 Aggregates format.
-
- a. When longer than two components, or whenever readability is
- improved, named aggregates should be formatted as indicated below, with one
- association per line and the "=>" arrows aligned.
-
- Output_Device := ( Device => DISK,
- Status => CLOSED,
- Cylinder => 1,
- Track => Startup_Track_Num );
-
- b. Aggregates for multidemensional arrays may be formatted in a
- tabular fashion to enhance readability.
-
- 5.5 Statements.
-
-
- 5.5.1 Slice Statements. Array slice assignments should be used rather than
- loops to copy all or part of an array. This is more readable and less error
- prone, especially in the case of slices with overlapping ranges.
-
- Client_List (Last_Client .. Number_Of_Clients) :=
- New_Clients (1 .. Num_New_Clients)
-
- NOTE: on format - array elements should stay with the array name, which is
- why a left-right format was not used in this instance (line too long).
- on syntax - array slice assignments work properly only if both arrays
- are of the same type.
-
- 5.5.2 If statements. An "if" statement should not be used to create the
- effect of a "case" statement controlled by the value of an enumeration type
- other than BOOLEAN.
-
- 5.5.3 Case statements.
-
- a. A "case" statement should be controlled by an enumeration type, not
- by a BOOLEAN value.
-
- b. When possible, the explicit listing of all choices on a "case"
- statement is preferable to the use of an "others" clause.
-
- This makes it easier for a human reader to see that the proper actions are
- being taken in all cases. Further, if the enumeration type of the control
- expression is modified, the compiler will indicate overlooked alternatives.
- However, there are cases when an "others" clause makes sense. For example, if
- the control expression is of type character, then it is usually best to use an
- "others" clause to handle the "undesired characters" case.
-
- 5.5.4 Block statements.
-
- a. Blocks should be used cautiously to introduce local declarations or to
- define a local exception handler. Resources for data local to the block are
- allocated only when the block is entered (elaborated). This is a fundamental
- difference between procedures and blocks. A procedure is callable by any
- number of other program units while a block is limited in scope to its
- immediate lexical level and cannot be called.
-
- To some extent, a block can be thought of as a procedure which is hard coded
- in-line. However, a procedure call contributes to readability precisely by
- not having its source code in-line (providing a "functional abstraction").
- Therefore, blocks should always be used cautiously and only for specific
- purposes. Thought should always be given to using a procedure call instead of
- a block to improve readability.
-
- b. Declarations of objects used only within a block should be nested
- within the block.
-
- REAL_TIME: Procedure calls require substanial execution time overhead. A
- potential run-time efficiency advantage of blocks is memory savings. If a
- declare statement is used in the block, the resources for data which are local
- to the block will only be allocated when the block is entered. Additionally,
- some compilers may deallocate these memory resources after the block is exited.
-
-
- 5.5.5 Exit statements. "Exit" statements should be used cautiously, and
- only when they significantly enhance the readability of the code. If used,
- the exit statement should use the name of the loop it is exiting.
-
- It is often more readable to use exit than to try to add BOOLEAN variables to
- a "while" loop condition to simulate exits form the middle of a loop.
- However, it can be difficult to understand a program where loops can be
- exited from multiple places. It is best to limit the use of "exit" statements
- to one per loop, if possible, and it is generally more readable to use "exit
- when." Use "if...then...exit; end if" when "last wishes" processing is needed.
-
-
- REAL_TIME: "Exit"s should not be used because they can greatly increase run
- time if the code at the exit address has to be paged into working space.
-
- 5.5.6 Return statements. It is preferable to minimize the number of return
- points from a subprogram, as long as this does not distract from the natural
- structure or readability of the subprogram.
-
- 5.5.7 Goto statements. It is deemed as poor programming practice to use
- "goto" statements.
-
- Use of the "goto" makes the textual structure of code less reflective of its
- logical structure. Possible uses of the "goto" statement can always be
- handled by other constructs in Ada, such as a procedure call or via an exit.
-
- 5.5.8 Formatting of statements.
-
- 5.5.8.1 Statement sequences. Blank lines should be used liberally to break
- sequences of statements into short, meaningful groups (see paragraph 5.2.2.6).
-
- Put_Line ("Welcome to the Electronic Message System");
-
- Logon_User (Current User);
- User_Directory.Lookup
- ( User_Name => Current_User
- Authority => User_Authority );
-
- if User_Authority = SPECIAL then
- Put_Line ("** You have SPECIAL authorization **");
- end if;
-
- 5.5.8.2 If statement format.
- a. "If" statements should have the following format:
-
- if <condition> then
- <statement>
- <statement>
- elsif <condition> then
- <statement>
- <statement>
- else
- <statement>
- <statement>
- end if;
-
- b. Multiple conditions in an "if" clause should be grouped together,
- placed on appropriate lines, and aligned so as to enhance clarity.
-
- 5.5.8.3 Case statement format. "Case" statements should have the following
- format:
-
- case <expression> is
- when <choices> => <statement>
- when others => <statement>
- end case;
-
- case <expression> is
- when <choices> =>
- <statement>
- <statement>
- when others =>
- <statement>
- <statement>
- end case;
-
- 5.5.8.4 Loop statement format.
-
- a. "Loop" statements should have one of the following formats:
-
- <loop name>:
- <iteration scheme> loop
- <statement>
- <statement>
- end loop <loop name>;
-
- b. A loop should preferably have a loop identifier.
-
- 5.5.8.5 Block statement format.
-
- a. Block statements should have the following format:
-
- <block name>:
- declare
- <declaration>
- <declaration>
- begin
- <statement>
- <statement>
- exception
- when <exceptions> =>
- <statement>
- <statement>
- end <block name>;
-
- b. Blocks should always have a block identifier.
-
- 5.5.9 Examples for statements.
-
- See also examples 5.9.14.2, 5.9.14.3, 5.9.14.4, 5.14.5.1, and 5.14.5.2.
-
- 5.5.9.1 Example 5X1.
-
- if Security_Level = 0 then -- appropriate comments
- Message_Classification :=UNCLASSIFIED; -- should be placed here
-
- elsif Security_Level > User_Clearance then -- stating what's going
- Message_Classification := PROTECTED; -- on
-
- else
- Message_Classification := Classification (Security_Level);
-
- end if;
-
- 5.5.9.2 Example 5X2.
-
- case Sensor is
- when ELEVATION => Record_Elevation (Sensor_Value); -- <comments>
- when AZIMUTH => Record_Azimuth (Sensor_Value);
- when DISTANCE => Record Distance (Sensor_Value);
- end case;
-
- 5.5.9.3 Example 5X3.
-
- Read_File:
- while not Text_IO.End_Of_File (File 1) loop
- Text_IO.Get (File1, Next_Record); -- <comments>
- Store_Record (Next_Record);
- end loop Read_File;
-
- Compute_Total_Taxes:
- while Next /= Head loop
- Total_Taxes := Total_Taxes + Next.Pay_Period Deductions;
- Next := Next.Successor;
- end loop Compute_Total_Taxes;
-
- Merge Files:
- for N in 1 .. Max_Num_Files loop
- Get_Items:
- for J in 1 .. Max_Num_Items loop
- Get_New_Item (New_Item);
- Merge_Item (New_Item, Storage_File);
- exit Merge_Files when New _Item = Terminal Item;
- end loop Get_Items;
- end loop Merge_Files;
-
- 5.5.9.4 Example 5X4.
-
- Swap_Integers:
- declare
- Temp : constant INTEGER := U;
- begin -- Swap_Integers;
- U := V;
- V := Temp;
- end Swap_Integers;
-
- Check_Entry:
- begin
- Int IO.Get (Value);
- Update (Value);
- exception
- when Data Error =>
- Text_IO.New_Line;
- Text_IO.Put_Line ("Value entry error.");
- Entry_Error_Flag := TRUE;
- end Check_Entry;
-
- 5.6 Subprograms.
-
-
- 5.6.1 Cohesion. A subprogram should perform a single, conceptual action
- (i.e., should be "functionally cohesive").
-
- The use of a subprogram increases readability by hiding the details of how an
- action is performed and giving it a descriptive name. A subprogram should
- perform only a single conceptual action so that its use can be understood as
- independently as possible from its implementation details and it can be given
- a self-documenting name. Note that simply shortening a program by placing
- "repeated code" into subprograms must be considered a secondary goal. Thus it
- is quite acceptable to have subprograms which are only called at one place, so
- long as those programs define cohesive actions.
-
- NOTE: Explicit parameter passing is the best way to build interfaces to
- subprograms. This method keeps the affected variables clearly defined and
- visible. Intensional use of side effects is considered poor programming
- practice and should be used on a limited basis. If used, side effects should
- be extensively commented ... where they are taking place and where they are
- affected.
-
- 5.6.2 Parameters.
-
- a. Subprograms with equivalent parameters should generally declare each
- parameter in the same position with the same identifier.
-
- b. Parameters with default expressions should be used only when they have
- very well known default values and/or they are defaulted most of the time,
- with the default being over-ridden only in special circumstances. Great care
- should be taken in using defaults, insuring the "mixing" of default and named
- parameters does not disrupt the understandability and readability of the code.
-
- c. Parameters with default expressions should generally be placed at the
- end of the parameter list, so that they may be omitted if desired in calls
- using positional notation.
-
- d. As noted in the section for naming (5.2.2.4), parameters should
- follow a similar schema, chosen to promote readability of the subprogram
- calls, and where possible, should reflect the mode of the parameter.
-
- 5.6.3 Recursion. A recursive subprogram should generally be used only if
- it is conceptually simpler for a given problem than a corresponding iterative
- subprogram.
-
- Many people have difficulty in understanding a program which uses recursion
- extensively. However, there are many cases where a recursive solution is
- considerably simpler and clearer than an iterative one. This is especially
- true, for example, for traversing complicated data structures such as tree and
- graph structures.
-
- 5.6.4 Functions. A subprogram without side-effects returning a single
- value should generally be written as a function. Since functions can be called
- from within expressions, there is more freedom in how a function can be used.
- For example, if a function is to be called only once within some other
- subprogram, it can be used to initialize a constant object.
-
- procedure Process_Sensor Data is
- Main_Sensor_Data
- : constant SENSOR_DATA := Read_Sensor (Main_Sensor_Index);
-
- begin
- ...
-
- However, if this sort of freedom is specifically not desired, or if the
- subprogram has side effects, then use of a procedure should be considered
- instead of a function, even if the subprogram returns only a single value.
-
- 5.6.5 Overloading.
-
- a. Overloading of subprograms should not be done. Use a meaningful
- function name instead. Possible (a weak possible) exceptions are the
- following cases:
-
- (1) Widely used utility subprograms which perform identical or very
- similar actions on arguments of different types (e.g., square-root of integer
- and real arguments).
-
- (2) Overloading of operator symbols.
-
- Note that this is not meant to cover subprograms with identical names in
- different packages, unless both subprograms are visible through "use" clauses
- for their packages.
-
- b. Operator symbols should be overloaded only when the new operator
- definitions comply closely with the traditional meaning of the operator (e.g.,
- "+" for vector addition).
-
- 5.6.6 Formatting of subprograms.
-
-
- 5.6.6.1 Subprogram names.
-
- a. Except as indicated below, a subprogram name should be an imperative
- or interrogatory verb phrase describing its action.
-
- Action_Complete
- Obtain_Next_Token
- lncrement_Line_Counter
- Create_New Group
-
- b. Non-BOOLEAN valued function names may also be noun phrases.
-
- Top_Of_Stack
- X_Component
- Successor
- Sensor_Reading
-
- c. BOOLEAN valued functions should have predicate-clause names.
-
- Stack_Is_Empty
- Last_Item_Check
- Device_Not_Ready
-
- 5.6.6.2 Subprogram header. Each subprogram specification, body or stub
- should be preceded by a header comment block containing at least the
- subprogram name and the indication SPEC, BODY, SPEC & BODY, STUB or SUBUNIT.
-
- -- ............................
- -- . .
- -- . Obtain_Next_Token . SPEC
- -- . .
- -- ............................
-
- 5.6.6.3 Subprogram declarations.
-
- a. Procedure declarations should have the following format:
-
- -- <subprogrammer header>
-
- procedure <procedure identifier>
- ( <parameter specification>;
- <parameter specification> );
-
- -- <documentary comments>
-
- Each <parameter specification> should be formatted like an object declaration
- (see paragraph 5.3.8.4). The documentary comments should follow guideline d.,
- below.
-
- b. Function declaration should have the following format:
-
- -- <subprogrammer header>
-
- function <function designator>
- ( <parameter specification>;
- <parameter specification> )
- return <type mark>;
-
- -- <documentary comments> Each <parameter specification> should be
- formatted like an object declaration (see paragraph 5.3.8.4). The
- <documentary comments> should follow guideline d., below.
-
- c. Parameter mode indications should always be used in procedure
- specifications. In a function specification, mode indications should either
- be used for all of the parameters or none of the parameters.
-
- d. Subprogram declarations should be followed by at least the following
- documentation:
-
- -- PURPOSE <--headings can be upper or lower case
- -- A description of all purposes and functions of the subprogram.
- --
- -- EXCEPTIONS
- -- A list of all exceptions which may propagate out of the subprogram,and
- -- a description of when each would be raised.
- --
- -- NOTES
- -- Additional comments on the use of the subprogram, references, etc.
-
- The "Exceptions" and "Notes" headings should be included even if these
- sections are empty. An empty section may be indicated by placing the
- annotation "(none)" after the appropriate header. Only in the case that the
- subprogram declaration is a compilation unit, the following section should be
- added to the documentation:
-
- -- MODIFICATIONS
- -- A list of modifications made to the subprogram DECLARATION.
- -- Each entry in the list should include the date of the change,
- -- the name of the person who made the change and a description
- -- of the modification. The first entry in the list should
- -- always be the initial coding of the subprogram declaration.
-
- 5.6.6.4 Subprogram bodies and stubs.
-
- a. Subprogram bodies should have the following format if not standalone:
-
- separate (<parent name>)
- <subprogram specification> is
-
- -- <documentary comments>
-
- <declaration>
- <declaration>
-
- begin -- <subprogram name>
-
- <statement>
- <statement>
- exception
- when <exceptions> =>
- <statement>
- end <subprogram name>;
-
- The <subprogram specification> should be formatted as in a subprogram
- declaration (see paragraph 5.6.6.3). The <documentary comments> should follow
- guide- line b., below. Note that the "end" of a subprogram should always
- include the subprogram name.
-
- b. Subprogram bodies should have AT LEAST the following documentation
- placed immediately after the subprogram header:
-
- -- NOTES
- -- Comments on the design, implementation and use of the
- -- subprogram.
-
- The "NOTES" heading should be included even if the section is empty. An empty
- section may be indicated by the comment "Notes (none)." Only in the case of a
- subprogram body which is a separate compilation unit from its specification,
- the following section should be added to the documentation.
-
- -- MODIFICATIONS
- -- A list of modifications made to the subprogram BODY.
- -- Each entry in the list should include the date of the change,
- -- the name of the person who made the change and a description
- -- of the modification. The description should identify exactly
- -- where in the compilation unit that the change was made. The
- -- first entry in the list should always be the initial coding
- -- of the subprogram body.
-
- If there is no declaration or stub for a subprogram, then the subprogram body
- should also include all the documentation required for a subprogram
- declaration (see paragraph 5.6.6.3).
-
- c. Subprogram stubs should have the following format:
-
- <subprogram specification> is separate;
-
- where the <subprogram specification> is formatted as in a subprogram
- declaration (see paragraph 5.6.6.3). If there is no previous declaration for
- a separate subprogram, then the subprogram stub should be followed by the same
- documentary comments required for a subprogram declaration (see paragraph
- 5.6.6.3).
-
- 5.6.6.5 Named parameter association.
-
- a. Named parameter association should generally be used for procedure
- calls of more than a single parameter. Positional parameters are generally
- preferred for function calls.
-
- b. Named and positional parameter associations should generally not be
- mixed in a single subprogram call.
-
- c. Named parameter associations should generally appear one to a line
- with formal parameters, "=>" symbols and actual parameters aligned.
-
- Obtain_Next_Token
- ( File => Current Source File,
- Position => Current Column',
- Token => Next_Token );
-
- 5.6.7 Examples for subprograms. See also examples 5.7.6.3, 5.9.14.3,
- 5.12.7.1, 5.12.7.3, 5.14.5.1, and 5.14.5.2.
-
- 5.6.7.1 Example 6X1.
-
- -- .............................
- -- . .
- -- . Obtain_Next_Token . SPEC
- -- . .
- -- .............................
-
- procedure Obtain_Next_Token
- ( File : in out Parser_Types.FILE; -- sequential file
- Token : out Parser_Types_TOKEN_TYP;
- Position : in Parser_Types.COL_NUM_TYP := 0 );
-
- -- Purpose
- -- This procedure scans the current input line from the point at
- -- which it was last called and returns the next token.
- --
- -- Exceptions
- --
- -- Source_File_Not_Open -- Raised if the input file is not open
- -- Notes (None)
-
- 5.6.7.2 Example 6X2.
-
- -- ..........................
- -- . .
- -- . Decode_Token . SPEC
- -- . .
- -- ..........................
-
- function Decode_Token
- ( File : Parser_Types.FILE;
- Token : Parser_Types.TOKEN_TYP )
- return Parser_Types.TOKEN_TYP;
-
- -- Purpose
- -- This function returns the ordinal value of the decoded token.
- --
- -- Exceptions
- -- Illegal Token -- raised if the token is not legal
- --
- -- Notes
- -- This function will later be changed to a procedure.
-
- 5.6.7.3 Example 6X3.
-
- -- ...............................
- -- . .
- -- . Obtain_Next_Token . STUB
- -- . .
- -- ...............................
-
- procedure Obtain_Next_Token
- ( File : in out Parser_Types.FILE;
- Token : out Parser_Types.TOKEN_TYP;
- Position : in Parser_Types. COL_NUM_TYP :=0 ) is separate;
-
- 5.6.7.4 Example 6X4.
-
- -- .........................
- -- . .
- -- . Decode_Token . STUB
- -- . .
- -- .........................
-
- function Decode_Token
- ( File : Parser_Types.FILE;
- Token : Parser_Types.TOKEN_TYP )
- return Parser_Types.TOKEN_TYP is separate;
-
- 5.6.7.5 Example 6X5.
-
- -- ................................
- -- . .
- -- . Obtain_Next_Token . SUBUNIT
- -- . .
- -- ................................
-
- with Parser_Types,
- File_Handler;
-
- separate (Lexical_Analyzer)
-
- procedure Obtain Next Token
- ( File : in out Parser_Types.FILE;
- Token : out Parser_Types.TOKEN_TYP;
- Position : in Parser_Types.COL_NUM_TYP :=0 ) is
-
-
- -- Notes (None)
- --
- -- Modifications
- -- 7/4/85 Rebecca DeMornay Initial version of the subunit
- -- 9/6/85 R. DeMornay Added the local function
- -- "Increment_Line_Counter".
-
- type LINE_COUNT is -- A count of the number
- range 1 .. File_Handler_Max Size; -- of lines in a file.
-
- Line_Counter : LINE_COUNT := 1;
-
- -- ...............................
- -- . .
- -- . Increment_Line_Counter . SPEC & BODY
- -- . .
- -- ...............................
-
- function Increment_Line_Counter
- ( File : Parser_Types.FILE;
- Line : LINE_COUNT ) -- Line number in "File"
- -- at the time of call
- return LINE_COUNT is
-
- -- Purpose
- -- This function increments the line counter from the point at
- -- which it was after the last call of this routine.
- --
- -- Exceptions
- -- Source_File_Not_Open -- Raised if "File" is not open.
- -- End_Of_File -- Raised if the function is called and
- -- the end of the file has already been
- -- reached.
- --
- -- Notes (None)
-
- begin -- Increment_Line_Counter
- ...
- end Increment_Line_Counter;
-
- begin -- Obtain_Next_Token
- exception
- when File_Handler.FILE_ERROR => Token := Parse_Types.NONE;
- raise Source_File_Not_Open;
- end Obtain_Next_Token;
-
- 5.7 Packages.
-
-
- 5.7.1 Use of packages.
-
- a. There are numerous roles for packages, the following represent the
- most common:
-
- (1) Model an abstract entity (or data type) appropriate to the domain
- of a problem.
-
- (2) Collect related type and object declarations which are used
- together (this kind of package should generally be used only to provide a
- common set of declarations for two or more library units).
-
- (3) To group together program units for essential configuration
- control (packages fulfilling this role alone should be used sparingly).
-
- The roles above are listed in order of decreasing desirability. The first
- role, modeling a problem domain entity, is the strongest use of packages for
- structuring a program. It corresponds to the requirement of functional
- cohesion for subprograms (see paragraph 5.6.1) and contributes to the goal of
- making the structure of a program reflect the structure of its problem domain.
-
- The second kind of package, collection of related declarations, should
- generally be used only to provide a common set of declarations for two or more
- library units. Further, it is better to minimize the declaration of variables
- in these packages. Overuse of packages of variables results in a FORTRAN
- COMMON block style program decomposition which defeats the abstraction and
- information hiding properties of packages (see paragraph 5.7.4).
-
- Finally the last type of package, a grouping of units for configuration
- reasons, should be used sparingly since it gives no additional information to
- a human reader on the structure of the program. This type of package might,
- for example, be used to divide a large program at the top level into
- subsystems to be developed by separate teams. It would be best, however, if
- these subsystem packages fulfilled, in addition, one of the other two roles.
-
- b. Packages should NOT be designed based on the procedural structure of
- the code which calls them.
-
- For example, a group of procedures should not be packaged simply because they
- are all called at system initialization, or because they are always called in
- a certain sequence. Such a package is closely coupled to the context in which
- it is used and is not very understandable, reusable or maintainable as a unit.
-
- c. A logical hierarchy of packages should be used to reflect or model
- levels of abstraction.
-
- 5.7.2 Nesting. The use of nesting is not recommended because of the
- numerous precautions and limitations involved.
-
-
- 5.7.3 Initialization. The initialization process should be self-contained.
- It is poor programming practice to call from the initialization statement of
- a package to subprograms outside the package and should be avoided.
-
- 5.7.4 Visible variables.
-
- a. Variable declarations in package specifications should be minimized.
-
- One of the aspects of software engineering Ada supports so well is information
- hiding. The use of variables in a package specification generally reduces the
- abstraction and information hiding properties of the package. For example, a
- variable cannot provide protection against being changed by units other than
- the package. Therefore it is generally better to use a function rather than a
- variable to read data from a package. It is also generally better to use a
- procedure rather than a variable to give data to a package, since a variable
- cannot trigger any package operations and a variable declaration often exposes
- some internal data representation details of the package.
-
- b. The private part of a package specification should only be used to
- supply the full definitions of private types and deferred constants; all other
- declarations should be put in the package body.
-
- c. Object of private type should be initialized by default, if possible.
-
- 5.7.5 Formatting of packages.
-
- 5.7.5.1 Package names. A package name should be a noun phrase describing the
- abstract entity modeled by the package, or simply whatever is being packaged.
-
- Stack_Handler
- Vehicle_Controller
- Terminal_Operations
- Parser_Types
- Utilities_Package
-
- 5.7.5.2 Package header. Each package specification, body or stub should be
- preceded by a header comment block containing at least the package name and
- the indication SPEC, BODY, STUB or SUBUNIT. A suggested format follows:
-
- -- ***************************
- -- * *
- -- * Lexical_Analyzer * SPEC
- -- * *
- -- ***************************
-
- 5.7.5.3 Package specifications.
-
- a. Package specifications should have the-following format: package
- <package identifier> is
-
- -- <documentary comments>
-
- <declaration>
- <declaration>
-
- private -- <package identifier>
-
- <declaration>
- <declaration>
-
- end <package identifier>;
-
- The <documentary comments> should follow guideline b., below. Note that the
- <package identifier> should always be repeated at the "end" of the package
- specification.
-
- b. A package specification should include AT LEAST the following
- documentation immediately after the package header:
-
- -- Purpose
- -- A description of the purpose and function of the package.
- --
- -- Initialization Exceptions
- -- A list of all exceptions which may propagate out of the
- -- package INITIALIZATION PART and a description of when each
- -- would be raised.
- --
- -- Notes
- -- Additional comments on the use of the package.
-
- The "Initialization Exceptions" and "Notes" headers should be included even if
- these sections are empty. An empty section may be indicated by placing the
- annotation "(none)" after the appropriate header. Only in the case a package
- specification which is a compilation unit, the following section should be
- added to the documentation:
-
- -- Modifications
- -- A list of modifications made to the package SPECIFICATION.
- -- Each entry in the list should include the date of the change,
- -- the name of the person who made the change and a description
- -- of the modification. The description should indicate exactly
- -- where in the compilation unit that the change was made. The
- -- first entry in the list should always be the initial coding of
- -- the package specification.
-
- c. In a declarative part, all package specifications should appear before
- any package or task bodies.
-
- 5.7.5.4 Package bodies and stubs.
-
- a. Package bodies should have the following format:
-
- separate (<parent name>)
- package body <package identifier> is
-
- -- <documentary comments>
-
- <declaration>
- <declaration>
-
- begin -- <package identifier>
-
- <statement>
- <statement>
-
- exception
- when <exception> =>
- <statement>
-
- end <package identifier>;
-
- The <documentary comments> should follow guideline b below. Note that the
- <package identifier> should always be repeated at the "end" of the package
- body.
-
- b. A package body should have at least the following documentation placed
- immediately after the package header:
-
- -- Notes
- -- Comments on the design, implementation and use of the
- -- package.
-
- The "Notes" header should be included even if the section is empty. An empty
- section may be indicated by the comment "Notes (none)." Only in the case of a
- package body which is a compilation unit, should the following section be
- added to the documentation:
-
- -- Modifications
- -- A list of modifications made to the package BODY. Each
- -- entry in the list should include the date of the change,
- -- the name of the person who made the change and a
- -- description of the modification. The description should
- -- indicate exactly where in the compilation unit that the
- -- change was made. The first entry in the list should always
- -- be the initial coding of the package body.
-
- c. Package stubs should have the following format: package body <package
- identifier> is separate;
-
- 5.7.6 Examples for packages.
-
- See also example 5.12.7.3
-
- 5.7.6.1 Example 7X1.
-
- -- ***************************
- -- * *
- -- * Lexical Analyzer * SPEC
- -- * *
- -- ***************************
-
- with Basic_Types,
- Parser_Types;
-
- package Lexical_Analyzer is
-
- -- Purpose
- -- The routines in this package read the source program, one
- -- character at a time, to generate a stream of tokens. As each
- -- token is produced it is passed to the package "Parser." The
- -- legal tokens are defined in the Language Reference Manual.
- --
- -- Initialization Exceptions
- --
- -- Diana_ File_ Non_Existent -- Raised if the file "DIANA.ADA"
- -- does not exist
- -- Notes
- -- Tokens are limited to 32 characters in length. Also, only
- -- sequential text files can be operated on by the parser.
- -- Modifications
- --
- -- 6/14/85 Rebecca DeMornay Initial version of spec
- -- 8/26/87 C. Royale Added "Decode_Token" function.
-
- Diana_File_Non_Existent
- : exception;
-
- Source_File_Not_Open
- : exception;
-
- Illegal_Token
- : exception;
-
- -- .................................
- -- . .
- -- . Obtain_Next_Token . SPEC
- -- . .
- -- .................................
-
- procedure Obtain_Next_Token
- (
- ...
- );
-
- ...
-
- -- ....................
- -- . .
- -- . Decode_Token . SPEC
- -- . .
- -- ....................
-
- function Decode_Token
- (
- ...
- )
- return Parser_Types.TOKEN_VALUE_TYP;
-
- ...
- end Lexical_Analyzer;
-
- 5.7.6.2 Example 7X2.
-
- -- ***************************
- -- * *
- -- * Lexical Analyzer * BODY
- -- * *
- -- ***************************
-
- with Text_IO,
- File_Handler;
-
- package body Lexical_Analyzer is
-
- -- Notes
- -- The package "Lexical_Analyzer" will later be changed to:a task,
- -- so that the "Parser" task (now a package) can make an entry
- -- call to "Lexical_Analyzer" when it needs the next token.
- --
- -- Modifications
- -- 6/14/85 Charity Royale Initial version of body.
- -- 8/26/85 Charity Royale Added "Decode_Token" function.
-
- -- Added instantiation of "Enumeration_IO."
-
- -- ******************
- -- * *
- -- * Char_IO * SPEC
- -- * *
- -- ******************
-
- package Char_IO is
- new Text_IO.Enumeration IO (Enum => Character);
-
- -- Purpose
- -- Used to read the input text file character by character.
- --
- -- Initialization Exceptions (none)
- -- Notes (none)
-
- -- ..................................
- -- . .
- -- . Obtain_Next_Token . STUB
- -- . .
- -- ..................................
-
-
- procedure Obtain_Next_Token
- (
- ...
- ) is separate;
-
- -- ......................
- -- . .
- -- . Decode_Token . STUB
- -- . .
- -- ......................
-
- function Decode_Token
- (
- ...
- )
- return Parser_Types.TOKEN_VALUE_TYP is separate;
- ...
-
- begin -- Lexical_Analyzer
-
- ...
-
- exception
- when File_Handler.File_Error =>
- raise Diana_File_Non_Existent
-
- end Lexical_Analyzer;
-
- 5.7.6.3 Example 7X3.
-
- -- *********************
- -- * *
- -- * Disk * SPEC
- -- * *
- -- *********************
-
- generic
-
- type SPECIFIC_DATA_TYP is -- The type of data to be
- ( <> ); -- stored on disk
-
- package Disk is
-
- -- Purpose
- -- This package defines an abstract data type to simplify
- -- the I/O interface to disk files.
- --
- -- Initialization Exceptions (none)
- -- Notes (none)
- -- Modifications
- -- 9/10/86 Ada Users Group Initial version
-
- type FILE_TYP is private;
-
- End_Of_File
- : exception;
-
- Open_Error
- : exception;
-
- Mode_Error
- : exception;
-
- subtype FILE_MODE is
- (IN_FILE, OUT_FILE);
-
- -- .....................
- -- . .
- -- . Create . SPEC
- -- . .
- -- .....................
-
- function Create
- ( Name : STRING;
- Mode : FILE_MODE := IN_FILE )
- return FILE_TYP;
-
- -- Purpose
- -- This function creates a FILE_TYP data object to
- -- represent the disk file with the given name and mode.
- --
- -- Exceptions (none)
- -- Notes
- -- This function does not actually open the file.
-
-
- -- .....................
- -- . .
- -- . Close . SPEC
- -- . .
- -- .....................
-
- procedure Close
- ( Disk_File : in out FILE_TYP );
-
- -- Purpose
- -- This procedure closes a disk file if it is open. If
- -- the file is already closed it has no effect.
- --
- -- Exceptions (none)
- -- Notes (none)
-
- -- ....................
- -- . .
- -- . Read . SPEC
- -- . .
- -- ....................
-
- procedure Read
- ( Disk_File : in out FlLE_TYP;
- Data : out SPECIFIC_DATA_TYP );
-
- -- Purpose
- -- This procedure reads the next record from a file,
- -- opening the file if necessary.
- --
- -- Exceptions
- -- End_Of_File - raised if no more elements can be
- -- read from the file
- -- Open_Error - if the file cannot be opened
- -- Mode_Error - if the file mode is not IN FILE
- --
- -- Notes (none)
-
- -- ......................
- -- . .
- -- . Write . SPEC
- -- . .
- -- ......................
-
- procedure Write
- ( Disk_File : in out FILE_TYP;
- Data : in SPECIFIC_DATA_TYP );
-
- -- Purpose
- -- This function writes a record to a file,
- -- opening the file if necessary.
- --
- -- Exceptions
- -- Open_Error - if the file cannot be opened
- -- Mode_Error - if the file mode is not OUT_FILE
- --
- -- Notes (none)
-
- private -- Disk
-
- -- *********************
- -- * *
- -- * Disk_IO * SPEC
- -- * *
- -- ********************* package Disk_IO is
-
- new Sequential_IO (SPECIFIC_DATA_TYP);
-
- -- Purpose -- This package provides the basis for the representation
- -- of disk files.
- --
- -- Initialization Exceptions (none)
- -- Notes (none)
-
- File_Name_Length
- : constant := 40;
-
- type FILE_TYP is
- record
- File_Name : STRING (1..File_Name_Length) := (others => ' ');
- File : Disk_IO.FILE_TYP;
- Mode : FILE_MODE := Disk_IO.IN_FILE;
- end record;
- end Disk;
-
- 5.8 Visibility.
-
-
- 5.8.1 Scope of identifiers. The scope of identifiers should not extend
- further than necessary. Where a scope is extended by "with" clauses, these
- clauses should cover as small a region of text as possible.
-
- For example, "with" clauses should be placed only on the subunits that really
- need them, not on their parents. This promotes information hiding and reduces
- coupling. It can also result in faster recompilation (due to the dependency
- rules).
-
- 5.8.2 The package STANDARD and WITH clauses. The package STANDARD should
- not be named in a "with" clause.
-
- 5.8.3 The use clause. The "use" clause should be employed only in a limited
- application. It detracts from the readability of the program by allowing
- the "expanded" name to be shorten (not having to specify the "prefix", not
- having to use the dot notation). Thus, the understandability of the program
- may be affected. Another detraction, there is an outside possibility it may
- introduce a name clash.
-
- 5.8.4 Renaming declarations. Usually renaming causes more problems than it
- is worth; so again, use it in a limited fashion, if at all.
-
- a. For a name with a large number of package qualifications, a renaming
- declaration may be used to define a new shorter name. The new identifier
- should still reflect the complete meaning of the full name.
-
- b. For a function which can be appropriately represented by an operator
- symbol name, a renaming declaration may be used to give it such a name.
- However, notice that a renaming declaration may have some appropriateness
- for achieving direct visibility, e.g.
-
- A Matrix_ Multiply function could be renamed "*".
-
- 5.8.5 Redefinition.
-
- a. It is extremely poor programming practice to redefine or rename items
- from the package STANDARD.
-
- b. Redefinition of an identifier in different declarations should be
- avoided.
-
- 5.9 Tasks.
-
-
- 5.9.1 Use of tasks. A task should fulfill one or more of the following:
-
- a. Model a concurrent abstract entity appropriate to the problem domain.
-
- b. Serve as an aceess-controlling or synchronizing agent for other tasks,
- or otherwise act as an interface between asynchronous tasks.
-
- c. Serve as an interface to asynchronous entities external to the program
- (e.g., asynchronous I/O, devices, interrupts, etc.).
-
- d. Define concurrent algorithms for faster execution on multiprocessor
- architectures.
-
- e. Perform an activity which must wait a specified time for an event or
- have a specific priority.
-
- Just as for packages (paragraph 5.7.1) it is best to have tasks which model
- problem domain entities. However, in the case of tasks it is also necessary
- to have some tasks which provide interfaces between other tasks and which
- handle the other issues of concurrency and parallelism mentioned above. The
- program should generally be structured, however, around the tasks which
- represent problem-domain entities.
-
- 5.9.2 Nesting of tasks.
-
- a. Tasks should generally not be nested within tasks or subprograms,
- except for the main procedure.
-
- Note that a subprogram containing a task cannot return until the task has
- terminated.
-
- b. Nested task bodies should be separate subunits, unless they are quite
- small.
-
- 5.9.3 Visibility of tasks.
-
- a. When only certain entries of a task are intended to be called by
- program components outside an enclosing package, it is generally preferable to
- hide the task specification in the package body, introducing package
- procedures which in turn call the actual entries.
-
- b. This helps to promote information hiding and strengthens the
- abstraction of the enclosing package (see paragraph 5.7.2.d). It also hides
- the use of tasking within the package. Note, however, that special care must
- be taken if the task entries are to be called using conditional or timed entry
- calls. In this case either the outer package must provide special procedures
- or procedure parameters or this guideline should not be followed.
-
- 5.9.4 Task types.
-
- a. A task type should be used only when multiple instances of that type
- are required. Otherwise a directly named task should be used.
-
- b. Identical tasks should be derived from a common task type.
-
- c. Static task structures should be used whenever they are sufficient.
- Access types to task type should be used only when it is essential to create
- and destroy tasks dynamically, or to be able to change the names with which
- they are associated.
-
- 5.9.5 Task termination. Nesting of tasks within other tasks should be
- avoided. If tasks must be nested, they should be forced to terminate when
- they are suppose to by causing them to reach their end statement. If a task
- is a "active" task, this is done by having the main loop as a "while" loop.
- If the task is "passive", there should be an entry which causes the main loop
- to be exited.
-
- 5.9.6 Entries and accept statements.
-
- a. Only those actions should be included in the "accept" statement which
- must be completed before the calling task is released from its waiting state.
-
- b. Conditional entry calls should be used sparingly to avoid unnecessary
- busy waiting.
-
- 5.9.7 Delay statement.
-
- a. A "delay" statement should be used whenever a task must wait for some
- known duration. A "busy wait" loop should never be used for this purpose.
-
- It is important to remember that "delay t" provides a delay of at least t
- seconds, but possibly more. A program should not rely on any upper bound for
- this delay, especially when tasks are used (since tasks must compete for CPU
- time).
-
- The following example is only one of many techniques to alleviate this
- problem in a periodic activity:
-
- ...
- Next_Time := Calendar.Clock + Required_ Period;
-
- Periodic_Activity:
- while Still_Time.loop
- -- Perform activity
- ...
- -- Correct for delay statement incertitude
- Period := Next_Time - Calendar.Clock;
-
- if Period < 0.0 then -- Processing was too slow
- Next_Time := Calendar.Clock -- Avoid cumulative effect
- end if;
- Next_Time := Next_Time + Required_Period;
- delay Period;
- end loop Periodic_Activity;
-
- b. The "delay" statement should normally only be used to manage
- interaction with some external process which works in real time, or to create
- a task which behaves in a well-defined manner in real time.
-
- 5.9.8 Task synchronization. Knowledge of the execution pattern of tasks
- (e.g., fixed, known time pattern, etc.) should not be used to avoid the use of
- explicit task synchronization.
-
- 5.9.9 Priorities.
-
- a. Only a small number of priority levels should be used. The priority
- levels used should be spread over the range made available to type PRIORITY in
- the implementation. Names should be given to the priority levels by declaring
- constants of predefined type PRIORITY and grouping these declarations into a
- single package.
-
- Using only a small number of priority levels makes the interaction of the
- various prioritized tasks easier to understand. On the other hand, spreading
- the levels across the available range allows easy insertion of a new level
- between existing levels if this later becomes necessary. As with other
- literal numbers, the use of names is more readable than the use of the
- literals.
- Further, for priorities, the allowable range of levels is implementation
- dependent. Naming priority levels by constant declarations grouped into a
- single package restricts the implementation dependency to that package. For
- example:
-
- with System;
- package Priority_Levels is
- Lowest_Priority
- : constant System.PRIORITY := System.PRIORITY'first;
- Highest_Priority
- : constant System.PRIORITY := System.PRIORITY'last;
- Median
- : constant := Highest_Priority - Lowest_Priority + 1;
- Average
- : constant System.PRIORITY := Lowest_Priority + (Median / 2);
- Idle
- : constant System.PRIORITY := Lowest_Priority;
- Background
- : constant System.PRIORITY := Lowest_Priority + (Median / 5);
- User
- : constant System.PRIORITY := Lowest_Priority + (2 * Median / 5);
- Foreground
- : constant System.PRIORITY := Lowest_Priority + (4 * Median / 5);
- end Priority_Levels;
-
- b. For any group of related tasks, such as those declared within the same
- program unit, priorities should be specified either for all, or for none of
- them.
-
- This avoids confusion about the scheduling of tasks with undefined priorities.
-
- 5.9.10 Abort statements. Abortion of tasks should generally be avoided.
-
- Aborting a task can produce unpredictable results. In particular, do not
- assume anything about the moment at which an aborted task becomes terminated.
- The "abort" statement should generally be used only in case of unrecoverable
- failure.
-
- 5.9.11 Shared variables.
-
- a. Tasks should not directly share variables unless only one of them can
- possibly be running at any one time.
-
- b. Any task which uses shared variables should identify in its
- documentary comments all the shared variables that it uses.
-
- 5.9.12 Local exception handling. To allow the handling of local exceptions
- without task termination, a task should generally have a block statement with
- an exception handler coded within its main loop.
-
- begin -- Some Task
-
- Main_Loop:
- loop
-
- Local:
- begin
- -- Task code
- ...
- exception -- Local
- -- handle local exceptions ...
- end Local;
-
- end Main_Loop;
-
- exception
- -- handle fatal exceptions ...
-
- end Some_Task;
-
- 5.9.13 Formatting of tasks.
-
- 5.9.13.1 Task and entry names.
-
- a. A task name should be a noun phrase describing the task function or
- abstract entity modeled by the task.
-
- Sensor_Interface
- Status_Monitor
- Event_Handler
- Message_Buffer
-
- b. Entry names should follow the same guidelines as for subprogram names
- (see paragraph 5.6.6.1).
-
- 5.9.13.2 Task and entry headers. Each task or task type specification or
- body and each entry specification should be preceded by a header comment block
- containing at least the unit name and the indication SPEC, BODY or STUB.
-
- -- **********************
- -- * *
- -- * Buffer * SPEC
- -- * *
- -- **********************
-
- task Buffer is
-
-
- -- ....................
- -- . .
- -- . Read . SPEC
- -- . .
- -- ....................
-
- entry Read ( Output : out Character );
-
- 5.9.13.3 Task specifications.
-
- a. Task specifications should have the following format:
-
- task <task identifier> is
-
- -- <documentary comments>
-
- <declaration>
- <declaration>
-
- end <task identifier>;
-
- Guidelines for <documentary comments> should be AT LEAST as rigorous as those
- for a subprogram declaration (see paragraph 5.6.6.3), except for the
- "Exceptions" section.
-
- NOTE: The <task identifier> should always be repeated at the "end" of the
- task specification.
-
- b. A task type specification should be formatted the same as a task
- specification, with the exception of including "task type" in the header.
- c. Entry declarations should have the following format:
-
- entry <entry identifier> (<family range>)
- ( <parameter specification>;
- <parameter specification> );
-
- -- <documentary comments>
-
- Each <parameter specification> should be formatted like an object declaration
- (see paragraph 5.3.8.4). Guidelines for <documentary comments> should be AT
- LEAST as rigorous as those for a subprogram declaration (see
- paragraph 5.6.6.3).
-
- d. Parameter mode indications should always be used in entry
- declarations.
-
- e. In a declarative part, all task specifications should appear before
- any task or package bodies.
-
- 5.9.13.4 Task bodies and stubs.
-
- a. Task bodies should have the following format:
-
- separate (<parent>)
- task body <task identifier> is
-
- -- <documentary comments>
-
- <declaration>
- <declaration>
-
- begin -- <task identifier>
-
- <statement>
- <statement>
-
- exception
- when <exceptions> =>
- <statement>
-
- end <task identifier>;
-
- b. Guidelines for <documentary comments> should be AT LEAST as rigorous
- as those for a subprogram declaration (see paragraph 5.6.6.3).
-
- NOTE: The <task identifier> should always be repeated at the "end" of the
- task body.
-
- c. Task stubs should have the following format:
-
- task body <task identifier> is separate;
-
- 5.9.13.5 Accept statements.
-
-
- a. "Accept" statements should have one of the following formats:
- accept <entry identifier> (<entry index>);
-
- accept <entry identifier> (<entry index>)
- ( <parameter specification>;
- <parameter specification> )
- do
- <statement>
- <statement>
- end <entry identifier>;
-
- Each <parameter specification> should be formatted like an object declaration
- (see paragraph 5.3.8.4). Note that the <entry identifier> should always be
- repeated at the "end" of the "accept" (if there is an "end").
-
- b. Parameter mode indications should always be used in accept statements.
-
-
- 5.9.13.6 Select statements.
-
- a. Selective wait statements should have the following format:
-
- select
- <statement>
- <statement>
- or
- <statement>
- <statement>
- or
- when <condition> =>
- <statement>
- <statement>
- end select;
-
- This format is consistent with the indentation style of other statements. In
- addition, the added level of indentation especially highlights guarded
- sections of code.
-
- b. Conditional and timed entry calls should have the following format:
-
- select
- <entry call>
- <statement>
- else
- <statement>
- <statement>
- end select;
-
- 5.9.13.7 Pragma priority. The priority pragma should appear in task
- specification before any entry declarations, and in the main program before
- any declarations.
-
- 5.9.14 Examples for tasks.
-
-
- 5.9.14.1 Example 9X1.
-
- -- **********************
- -- * *
- -- * Buffer * SPEC
- -- * *
- -- **********************
-
- task Buffer is
-
- -- Purpose
- -- This task provides a character buffer to smooth variations
- -- between the speed of output of a producing task and the speed
- -- of input of a consuming task.
- --
- -- Exceptions (none)
- -- Notes (none)
-
- -- .....................
- -- . .
- -- . Read . SPEC
- -- . .
- -- .....................
-
- entry Read ( Output : out Character );
-
- -- Purpose
- -- This entry reads a character from the buffer.
- -- If the buffer is empty, the entry will wait
- -- until a character is written into the buffer.
- --
- -- Exceptions (none)
- -- Notes (none)
-
- -- .....................
- -- . .
- -- . Write . SPEC
- -- . .
- -- .....................
-
- entry Write ( Input : in Character );
-
- -- Purpose
- -- This entry writes a character into the buffer.
- -- If the buffer is full the entry will wait
- -- until a character is read from the buffer.
- --
- -- Exceptions (none)
- -- Notes (none)
-
- end Buffer;
-
- 5.9.14.2 Example 9X2.
-
- -- **********************
- -- * *
- -- * Buffer * BODY
- -- * *
- -- **********************
-
- separate (Buffer Package)
- task body Buffer is
-
- -- Notes
- -- This task contains an internal pool of characters processed
- -- in a round-robin fashion.
- --
- -- Modifications
- -- 7/2/86 Fred Blah Initial version.
-
- Pool_Size
- : constant := 100;
- subtype POOL_RANGE is
- INTEGER range 1..Pool_Size;
- type POOL_TYP is
- array (POOL_RANGE) of CHARACTER;
- Pool
- : POOL_TYP;
- Count -- The number of characters in
- : INTEGER range 0..Pool_Size := 0; -- the pool.
- In_Index -- The space for the next input
- : POOL_RANGE := 1; -- character.
- Out_Index -- The space for the next output
- : POOL_RANGE := 1; -- character.
-
- begin -- Buffer
-
- Pool_Loop:
- loop
- select
- when Count < Pool_Size =>
- accept Write ( Input : in Character ) do
- Pool(In_Index) := Input;
- end write;
- In_Index := In_Index mod Pool_Size + 1;
- Count := Count + 1;
- or
- when Count > 0 =>
- accept Read ( Output : out Character) do
- Output := Pool(Out_Index);
- end Read;
- Out_Index := Out_Index mod Pool_Size + 1;
- Count := Count - 1;
- or
- terminate;
- end select;
-
- end loop Pool_Loop;
-
- end Buffer;
-
- 5.9.14.3 Example 9X3.
-
- -- ...................
- -- . .
- -- . Shellsort . BODY
- -- . .
- -- ...................
-
- procedure Shellsort
- ( List : in out ITEM_LIST; -- to be sorted in place.
- Number_Of_Items : in NATURAL );
-
- -- Purpose
- -- This is a basic integer sorting routine.
-
- -- Notes
- -- This sorting procedure implements the Shell sort by
- -- separating the n-sorts into multiple Ada tasks.
- -- This algorithm is designed for parallel processing
- -- of the tasks and is not an efficient method on a
- -- single processor. The process works on an one
- -- dimensional array called ITEM_LIST.
- --
- -- Modifications
- -- 9/5/86 A. Shell Initial version
-
- Increment -- Increment of an n-sort
- : NATURAL;
-
- Number_of_Sorts -- Number of parallel sorts
- : NATURAL; -- for a single pass
-
- Number_Of_Tasks
- : NATURAL;
-
- -- ********************
- -- * *
- -- * SORTER TASK * SPEC
- -- * *
- -- ********************
-
- task type SORTER_TASK is
-
- -- Purpose
- -- Tasks of this type perform the n-sort for the Shell sort.
- --
- -- Notes
- -- A SORTER_TASK terminates itself when it is no longer
- -- needed for the sort.
-
- -- ......................
- -- . .
- -- . Sort . SPEC
- -- . .
- -- ......................
-
- entry Sort
- ( First : in INTEGER;
- Step : in NATURAL );
- -- Purpose
- -- This entry signals a sorter task to perform a new
- -- n-sort. Elements are sorted in place in List,
- -- starting with the element at index First and
- -- including subsequent elements at the indicated Step.
- --
- -- Exceptions (none)
- -- Notes (none)
-
- end SORTER_TASK;
-
- -- *********************
- -- * *
- -- * SORTER_TASK * STUB
- -- * *
- -- *********************
-
- task body SORTER_TASK is separate;
-
- type SORTER_ARRAY is
- array (INTEGER range <>) of SORTER_TASK;
-
- begin -- Shellsort
-
- if Number_Of_Items < 2 then
- return;
- end if;
-
- -- Determine the first n-sort increment.
- Increment := 1;
-
- while Increment < Number_Of_Items loop
- Increment := (3 * Increment) + 1;
- end loop;
-
- Increment := Increment / 3;
- if Increment < 1 then
- Increment := 1;
- end if;
-
- -- Determine the number of tasks required to perform
- -- the sort.
-
- if Number_Of_Items / Increment = 1 then
- Number_of_Sorts := Number Of Items mod Increment;
- if Increment / 3 > Number Of Sorts then
- Number_Of_Tasks := Increment / 3;
- else
- Number_Of_Tasks := Number_Of_Sorts;
- end if;
- else
- Number_Of_Sorts := Increment;
- Number_of_Tasks := Number_Of_Sorts;
- end if;
-
- -- Perform the sort
-
- Task_Block:
- declare
- Sort_List
- : SORTER_ARRAY (1 .. Number_Of_Tasks);
- begin -- Task_Block
-
- Incrementation:
- while Increment > 0 loop
-
- Sort_Work:
- for K in 1 .. Number_Of_Sorts loop
- Sort_List(K).Sort
- ( First => List'first + K - 1'
- Step => Increment );
- end loop Sort_Work;
-
- Increment := Increment / 3;
- Number_of_Sorts := Increment;
- end loop Incrementation;
-
- end Task_Block;
-
- end Shellsort;
-
- 5.9.14.4 Example 9X4.
-
- -- *********************
- -- * *
- -- * SORTER_TASK * SUBUNIT
- -- * *
- -- *********************
-
- separate (Shellsort)
- task body SORTER_TASK is
-
- -- Notes
- -- This task body implements a task type.
- --
- -- Modifications
- -- 9/5/86 A. Shell Initial version
-
- -- Global variables
- -- List -- An array of all items to be
- sorted by Shellsort.
- -- Number_Of_Items -- The number of items in the list.
-
- Start : INTEGER;
- Increment : NATURAL;
-
- A : INTEGER;
- B : INTEGER;
- First_B : INTEGER;
-
- Temp : INTEGER;
-
- begin -- SORTER_TASK
-
- Main_Loop:
- loop
-
- accept Sort
- ( First : in INTEGER;
- Step : in NATURAL )
- do
- Start := First;
- Increment := Step;
- end Sort;
-
- First_B := Start + Increment;
-
- Determine_Criteria:
- while First_B <= List'first + Number_Of_Items - 1 loop
- B := First_B;
- A := B - Increment;
-
- Find_Position:
- while A >= Start loop exit when not (List(A) > List(B));
- Temp := List(A);
- List(A) := List(B);
- List(B) := Temp;
- B := A;
- A := B - Increment;
- end loop Find_Position;
-
- First_B := First_B + Increment;
-
- end loop Determine_Criteria;
-
- -- Terminate if task is not needed for n-sort
- exit when (Increment / 3) < Start - List'first + 1;
- end loop Main_Loop;
-
- end SORTER_TASK;
-
- 5.10 Program structure and compilation issues.
-
-
- 5.10.1 Library units. Library units are divided into two categories,
- subprograms and packages. Library subprograms define one entity, whereas
- packages provide services which define more than on entity. Some of the
- primary uses are:
-
- a. To allow configuration control of the high level functional
- subsystems of a program.
-
- b. For general purposes, reusable program units.
-
- 5.10.2 WITH clauses.
-
- a. No unit should have a "with" clause for a unit it does not need to see
-
- directly.
-
- b. If only a small part of a given unit needs access to a library unit,
- then it should generally appear as a subunit and have its own "with" clause
- for that library unit (see paragraph 5.8.1).
-
- NOTE: Understanding the use of the "with" clause is important. Where the
- "with" is interpreted, based on the compiler, can cause recompilation
- problems by hiding names.
-
- 5.10.3 Program unit dependencies.
-
- a. Excessive dependencies between compilation units should be avoided,
- especially the use of complicated networks of "with" clauses.
-
- b. It is preferable to limit program unit dependencies to a logical tree
- structure whenever possible. In this instance, the preferred tree stucture
- would be where a parent can have multiple children; however, every child has
- only one parent. Any program that creates a dependency of multiple parents
- to multiple children should be evaluated for redesign.
-
- 5.11 Exceptions.
-
-
- 5.11.1 Exception propagation.
-
- a. Exceptions propagated by a program unit should be considered part of
- the abstraction or function represented by that unit. Therefore, it should
- generally only propagate exceptions which are appropriate to that level of
- abstraction. If necessary, an exception which cannot be handled by a unit at
- one level of abstraction should be converted into an exception which can be
- explicitly recognized by the next higher level.
-
- For example, a Stack package should provide a Stack_Full exception instead of
- propagating a Constraint_Error. Similarly, a Matrix_lnverse function should
- raise a Matrix_is_Singular exception rather than propagating Numeric_Error.
-
- b. Exceptions should not be allowed to propagate outside their own scope.
- An exception may be allowed to propagate to any point where it can be named in
- an exception handler. Note that this includes the case where an exception is
- defined in a package specification and has its scope "expanded" by a "with"
- clause. What must be avoided are cases such as the following:
-
- procedure Raise_Exception is
- Hidden_Exception : exception;
- begin
- raise Hidden_Exception;
- end Raise_Exception;
-
- begin
- Raise_Exception;
- -- "Hidden_Exception" CANNOT be named at this point
-
- 5.11.2 Use of exceptions.
-
- a. An exception should be used sparingly. If used, extensive and clear
- comments should be included. Possible reasons for exceptions are:
-
- (1) It reports an irregular event which is outside the normal
- operation of a program unit or is in some sense an error.
-
- (2) It is used where it can be argued that it is safer (more
- defensive) than the alternative, in particular to guard against omissions of
- error checking code for especially harmful errors.
-
- (3) It reports an event for which it is inconvenient or unnatural to
- test at the point of cause/occurrence and thus use of the exception enhances
- readability. Exceptions declared in package specifications are really part of
- the abstraction defined by that package. Therefore their use should be
- integral to the design of the package (see paragraph 5.10.1).
-
- Also, note that the predefined exceptions should be used with care. Due to
- allowable implementation differences, they should not be relied upon to
- indicate particular circumstances.
-
- b. Exceptions should not be used as means of returning normal state
- information.
-
- For example, a Stack package may have Stack Full and Stack Empty exceptions
- which are raised by its Push and Pop subprograms. However, these subprograms
- should not be used solely to raise exceptions to test if the appropriate
- conditions are true. Instead, the package should provide BOOLEAN functions
- such as Full and Empty to test for these state conditions.
-
- 5.11.3 Exception handlers.
-
- a. The exception handler choice "others" should be used only if it is
- necessary to ensure that no UNANTICIPATED exception can be propagated or if
- some special action must be taken before propagation.
-
- For example, important tasks should generally have an "others" clause in a
- local exception handler (see paragraph 5.9.12) to prevent them from
- terminating due to unanticipated exceptions. However, in the case when it can
- be expected that a certain exception may sometimes occur, then that exception
- should always be explicitly named in the exception handler.
-
- b. Recursion should not be used within an exception handler.
-
- c. Exception handlers on block statements should be used sparingly. One
- of the advantages of using exceptions is that it separates the error handling
- code from the more often executed normal processing code. Excessive use of
- exception handlers in block statements can defeat this advantage.
-
- 5.11.4 Raise statements.
-
- a. Exceptions declared in the specification of a package which represents
- a problem domain entity should not be raised outside that package.
-
- Exceptions declared in a package specification should be considered part of
- the abstraction defined by the package. These exceptions provide special
- "signals" from the package operations, and should thus not be raised outside
- of the package.
-
- b. Exceptions raised within a.task should always-be handled within the
- task.
-
- NOTE: In the case of an exception raised during a rendezvous the exception
- will also be propagated back to the point of the entry call.
-
- c. The predefined exceptions should generally not be explicitly raised.
-
- 5.11.5 Suppressing checks. Checks should not be suppressed except for
- essential efficiency or timing reasons in thoroughly tested program units.
-
- 5.11.6 Exception declarations. Exception declarations should re formatted
- like object declarations, paragraph 5.3.8.4.
-
- 5.11.7 Examples for exceptions. See examples 5.5.9.4, 5.6.7.5, 5.7.6.2,
- and 5.14.5.2.
-
- 5.12 Generic units.
-
-
- 5.12.1 Use of generic units.
-
- a. Generics should not be used in situations in which normal programming
- constructs are equivalent.
-
- b. A generic program unit should fulfill one or more of the following:
-
- (1) Provide logically equivalent operations on objects of different
- type.
-
- (2) Parameterize a program unit by a subprogram value.
-
- (3) Provide a data abstraction required at many points in a program,
- even if no parameterization is required.
-
- (4) Provide parameters which are particularly appropriate to be fixed
- at declaration or elaboration time.
-
- (5) Reduce coupling by controlling visibility.
-
- c. Functions should be made generic whenever possible to facilitate and
- increase reusability.
-
- 5.12.2 Generic library units. Generic units should generally be library
- units.
-
- 5.12.3 Generic instantiation.
-
- a. The most commonly used generic instantiations should generally be
- placed in library units.
-
- b. Generic instantiations should be used cautiously within generic units.
-
- NOTE: Information presented in some cases fall into the realm of guidelines
- to compensate for compiler and/or run-time deficiencies. Sub-subparagraph
- b is an example.
-
- 5.12.4 Generic formal subprograms.
-
- a. The actual subprograms associated with the formal subprogram
- parameters of a generic unit should be consistent with the conceptual meanings
- of the formal parameters (e.g., only functions which are conceptually "adding
- operations" should be associated with a formal parameter named "plus").
-
- b. Operator symbol function generic parameters should generally be
- provided with a box default body ("is <>").
-
- with function "<"
- ( X : ITEM;
- Y : ITEM )
- return BOOLEAN is <>;
-
- 5.12.5 Use of attributes.
-
- In writing generic bodies, attributes should be used as much as possible
- to generalize the code produced.
-
- 5.12.6 Formatting of generic units.
-
- 5.12.6.1 Generic declarations.
-
- a. Generic declarations should have the following format:
-
- generic
- <declaration>
- <declaration>
- <program unit specification>;
-
- -- <documentary comments>.
-
- Each <declaration> should be formatted like its non-formal counterpart (see
- paragraphs 5.3.8.3 and 5.3.8.4), except for formal subprograms which should be
- formatted as in b below. The <program unit specification> should be formatted
- as for non-generic units (see paragraphs 5.6.6.3 and 5.7.5.3).
-
- b. A generic formal parameter subprogram declaration should have one of
- the following formats:
-
- with <subprogram specification>;
- -- <purpose>
-
- with <subprogram specification> is <>;
- -- <purpose>
-
- with <subprogram specification> is <default name>;
- -- <purpose>
-
- The <subprogram specification> should be formatted as for a subprogram
- declaration (see paragraph 5.6.3.3). Note, however, that the only
- documentation generally needed on formal subprograms is the "Purpose."
-
- c. A generic declaration should be preceded by the appropriate unit
- header block (see paragraphs 5.6.6.2 and 5.7.5.2).
-
- 5.12.6.2 Formatting of generic instantiations.
-
- a. Generic instantiations should have one of the following formats:
-
- <unit header> is
- new <generic name> (<generic argument>, <generic argument>);
-
- -- <documentary comments>
- <unit header> is
- new <generic name>
- ( <generic parameter> => <generic argument>,
- <generic parameter> => <generic argument>);
-
- <documentary comments>
-
- NOTE: In the second form the arrows ("=>") should be kept aligned. Also, the
- <documentary comments> should not duplicate information presented in the
- generic specification. A referral back to the original comments should be a
- good beginning.
-
- b. Generic instantiations should have the same kind of header comment
- block as for a specification of the appropriate kind of unit (paragraphs
- 5.6.6.2 and 5.7.5.2).
-
- 5.12.7 Examples for generic units. See also examples 5.7.6.2 and 5.7.6.3.
-
- 5.12.7.1 Example 12X1.
-
- -- ........................
- -- . .
- -- . Shellsort_Generic . SPEC
- -- . .
- -- ........................
-
- generic
- type ITEM is private; -- The type of items sorted
- type LIST_TYP is -- The type of the item list
- array (INTEGER range <>) of ITEM;
-
- with function "<"
- ( Left : ITEM;
- Right : ITEM )
- return BOOLEAN is <>;
-
- -- Purpose
- -- This function defines the ordering used when the
- -- items are sorted.
-
- procedure Shellsort_Generic
- ( List : in out LIST_TYP ; -- This list will be sorted in place.
- N : in NATURAL ); -- The number of items in the list.
-
- -- Purpose
- -- This procedure sorts the items in List using a Shell
- -- sort algorithm designed for parallel processing.
- --
- -- Exceptions (none)
- --
- -- Notes
- -- (This is a generic declaration for the procedure
- -- body five in example 9X3.)
- --
- -- Modifications
- -- 9/5/86 A. Shell Initial version
-
- 5.12.7.2 Example 12X2.
-
- -- .....................
- -- . .
- -- . Name_Sort . SPEC
- -- . .
- -- .....................
-
- procedure Name_Sort is
- new Shellsort_Generic
- ( ITEM => NAME,
- LIST_TYP => NAME_LIST );
-
- 5.12.7.3 Example 12X3.
-
- -- *************************
- -- * *
- -- * *
- -- * Unit_Statistics * SPEC
- -- * *
- -- *************************
-
- with Text_IO;
- generic
-
- Unit_Name -- Name of the unit for which
- : STRING; -- statistics are to be kept.
-
- type ELEMENT_TYP is -- Enumeration type of the elements
- (<>); -- to be counted.
-
- package Unit_Statistics is
- -- Purpose
- -- This package provides operations to keep counts for the
- -- various elements of a program unit. These counts can be
- -- incremented or printed out in a report.
- --
- -- Initialization Exceptions (none)
- --
- -- Notes
- --
- -- This package is based on the generic package "Task_Statistics"
- -- written by Dan Roy.
- --
- -- Modifications
- -- 8/18/86 Ed Seidewitz Initial version
-
- -- ............................
- -- . .
- -- . Number_Of_Lines . SPEC
- -- . .
- -- ............................
-
- function Number_Of_Lines
- return POSITIVE;
-
- -- Purpose
- -- This function returns the number of lines printed by
- -- procedure Report since the last call to Number_Of_Lines.
- --
- -- Exceptions (none)
- --
- -- Notes (none)
-
- -- ...........................
- -- . .
- -- . Count_of . SPEC
- -- . .
- -- ...........................
-
- function Count_Of
- ( Element : ELEMENT_TYP ) return NATURAL;
-
- -- Purpose
- -- This function returns the current count for the specified
- -- element.
- --
- -- Exceptions (none)
- --
- -- Notes (none)
-
- -- ...................
- -- . .
- -- . Increment . SPEC
- -- . .
- -- ...................
-
- procedure Increment
- ( Element : in ELEMENT_TYP;
- By_Amount : in INTEGER := 1 );
-
- -- Purpose
- -- This procedure increments the count for the specified
- -- element by a certain amount. By default, this amount
- -- is one.
- --
- -- Exceptions (none)
- --
- -- Notes (none)
-
- -- ....................
- -- . .
- -- . Report . SPEC
- -- . .
- -- ....................
-
- procedure Report
- ( Report File : in Text_IO.FILE_TYP );
-
- -- Purpose
- -- This procedure prints a report of all statistics for
- -- this unit to the specified text file.
- --
- -- Exceptions (none)
- --
- -- Notes (none)
-
- end Unit_Statistics
-
- 5.12.7.4 Example 12X4.
-
- -- ***********************************
- -- * *
- -- * Telemetry_Reader_Statistics * SPEC
- -- * *
- -- ***********************************
-
- package Telemetry_Reader Statistics is
- new Unit_Statistics
- ( Unit_Name => "Telemetry_Reader",
- ELEMENT_TYP => READER_ELEMENTS );
-
- -- Purpose
- -- This package collects statistics on elements of the
- -- Telemetry_Reader.
- --
- -- Initialization Exceptions (none)
- -- Notes (none)
-
- 5.13 Representation clauses and implementation-dependent features. Any
- library units using representation clauses and implementation-dependent
- features should explicitly document their use. One of the attractions of
- Ada is its code reusability. If only machine independent interfaces are
- presented, while representation clauses and implementation features are
- hidden, those wishing to make use of the code may find unexplainable errors
- arising.
-
-
- 5.13.1 Encapsulation. Representation clauses and implementation dependent
- features should, if possible, be hidden inside packages which present
- implementation independent interfaces to users.
-
- 5.13.2 Use of representation clauses and implementation-dependent features.
-
- a. Machine dependent and low-level Ada features should not be used except
- when absolutely necessary.
-
- b. Representation clauses and implementation-dependent features should
- only be used for one of the following:
-
- (1) To increase efficiency (when absolutely necessary).
- (2) For interrupt handling.
- (3) For interfacing to hardware, foreign code or foreign data.
- (4) To specify task storage size. Further, address clauses should be
- used with entries only to associate them with hardware interrupts.
-
- c. Representation clauses should not be used to change the meaning of a
- program.
-
- 5.13.3 Interrupts. Interrupt routines should be kept as short as possible.
-
- 5.13.4 Formatting of representation clauses. Representation clauses should
- be placed near the objects they affect. An exception may be to separate the
- machine-independent from the machine-dependent representations.
-
- 5.14 lnput-output.
-
-
- 5.14.1 Encapsulation of I/O.
-
- a. Use of the LOW_LEVEL_IO procedures should always be encapsulated in
- packages or tasks.
-
- b. Use of the LOW_LEVEL_IO procedures should generally be encapsulated in
- task objects associated with each item of controlled equipment.
-
- c. File management and textual input-output software should generally be
- encapsulated in specialized packages with simple interfaces.
-
- This should include file interface code, textual formatting code and user
- inter-face code. User interface encapsulation can be especially useful when a
- system must accommodate increasing levels of user interface sophistication or
- changing user needs over its lifetime. In these cases it is crucial that
- details of the implementation of the user interface be hidden so that changes
- can be made to it without affecting the rest of the system.
-
- NOTE: An argument can be made to encapsulate all I/O, to include the use
- Text_IO and Direct_IO, because most Ada I/O has machine dependencies.
-
- 5.14.2 Text formatting. Line and page formatting should be done using the
- New_Line and New_Page subprograms, rather than explicitly writing end-of-line
- or end-of-page characters.
-
- 5.14.3 Low-level input-output. Use of package Low_Level-IO should be
- avoided unless absolutely necessary.
-
- 5.14.4 Form parameter. Use of the Form parameter of the Open and Create
- procedures should generally be avoided.
-
- The "Form" parameter on the file Open and Create procedures specifies system
- dependent file characteristics. This can reduce both readability and
- portability, and so should only be used if absolutely necessary.
-
- 5.14.5 Examples for input-output. See also examples 5.5.9.3, 5.5.9.4 and
- 5.7.6.3.
-
- 5.14.5.1 Example 14X1.
-
- -- ....................
- -- . .
- -- . Report . SUBUNIT
- -- . .
- -- ....................
-
- separate (Unit_Statistics)
- procedure Report
- ( Report_File : in Text_IO.FILE_TYP ) is
-
- -- Notes
- -- This example is based on Task_Statistics.Report
- -- by Dan Roy.
- --
- -- Modifications
- -- 8/18/86 Ed Seidewitz Initial version.
-
- Unit_Name_Column
- : constant := 10;
-
- Value_Column
- : constant := 40;
-
- use Text_IO; -- For output operations.
-
- begin -- Report
-
- -- Print header
- New_Line (Report File);
- Set_Col (Report. File, To => Unit_Name_Column);
- Put_line (Report_File,
- "Statistics for " & STRING(Unit_Name)); New Line (Report_File);
- Number_Lines_Printed := Number_Lines_Printed . 2;
-
- -- Print "element name element value" for all elements
- Print_All:
- for Element in Statistics Array'range loop
- Put (Report_File, ELEMENT_TYP'image (Element));
- Set Col (Report_File, To => Value_Column);
- Put Line (Report_File, INTEGER'image (Statistics_Array(Element)));
- Number_Lines_Printed := Number_Lines_Printed + 1;
- end loop Print_All;
-
- end Report;
-
- 5.14.5.2 Example 14X2.
-
- -- ....................
- -- . .
- -- . Read . SUBUNIT
- -- . .
- -- ....................
-
- separate (Disk)
- procedure Read
- ( Disk_File : in out FILE_TYP;
- Data : out SPECIFIC_DATA_TYP ) is
-
- -- Notes
- -- (This is the body of procedure Read in example 7X3)
-
- -- Modifications
- -- 9/10/86 Ada User's Group Initial version
-
- begin -- Read
-
- if not Disk_IO.Is_Open(Disk_File.File) then
- Open_File(Disk_File);
- end if;
-
- Disk_IO.Read
- ( File => Disk_File.File,
- Item => Data );
-
- exception
-
- when Disk_IO.End Error =>
- Disk_IO.Close (Disk_File.File);
- raise End_Of_File;
- when Disk_IO.Name Error Disk_IO.Use_Error =>
- raise Open_Error;
- when Disk_IO.Mode_Error =>
- raise Mode_Error;
-
- end Read;
-