Rational Software Corp.

TOC PREV NEXT INDEX



       

Ada Code Generation


Contents

This chapter is organized as follows:


What is the Ada Generator?

The Ada Generator is the code generation capability that is provided by the Ada 95/Ada 83 add-in to Rational Rose. The commands for the Ada Generator are located in the Ada 95/Ada 83 submenu of the Rose Tools menu.

You use the Ada Generator to generate Ada units from information in a Rose model. These units contain Ada code constructs that correspond to the notation items (classes, relationships, and adornments) you have defined in the model via diagrams and specifications.

The Ada Generator provides code-generation properties that control the kinds of Ada code constructs that are generated for the various kinds of notation items in the model. You can use the default values for these properties or you can specify different values to generate the code you want.

The Ada Generator inserts specially-marked code regions into the generated files where you can add further code (for example, to fill in extra private declarations in a package specification). By default, such regions are preserved, so you can regenerate the file without losing the code you added.

The Ada Generator may generate code in a directory hierarchy or, if Rational Apex is available, in subsystems and views. In order to generate code in subsystems and views, the Apex add-in must be activated, and the property CreateApexSubsystemAndView of the Apex add-in must be set to "yes". The Ada Generator, when generating code for Apex, makes use of some properties defined by the Apex add-in. These properties have a name which starts with "Apex" and are described in the documentation for the Apex add-in.


Basic Steps for Iterative Code Development

The basic strategy for generating code is to use the default values for code-generation properties initially, and later introduce non-default values as needed. This section describes these steps for generating Ada units from a Rose model:

Overview

In order to generate Ada 95 or Ada 83 code, you must first activate the Ada 95/Ada 83 add-in using the Add-In Manager, which is accessible from the Add-Ins menu.

Then, you must set the default language for your model to be Ada 95 or Ada 83: choose the Tools > Options menu item, and in the Options dialog box click the Notation tab; use the Default Language list to select Ada 95 or Ada 83.

You may generate a different language for some classes by associating them with a component that has a different language.

By default, code is generated in the current directory or working view (determined initially when you start Rose and changed each time you open a model in a different view). If this is unacceptable, you can specify a default view before generating code.

1 Start Rose, if necessary.

2 Create or open the Rose model from which you want to generate code and display an appropriate class diagram.

3 Select one or more class items (classes, utilities, parameterized classes and bound classes) or UML packages.

4 Choose the Code Generation command from the Tools > Ada 95 submenu. If code generation fails, inspect the log.

5 Evaluate the generated code. Based on your evaluation, you can change the model and/or code-generation properties, and then regenerate the code.

The Generated Files

The generated files are placed in a directory based on the properties of the model and the component UML packages. By default, each logical or component UML package in Rose is associated with an Apex view within a subsystem (if Apex is available) or with a hierarchy of directories (if Apex is not available).

In general one specification file (.1.ada) is generated for each class you selected in the diagram. The name of each file is derived from the name of the corresponding class. If you selected a UML package, a file is generated for each class in the UML package.

Note that the generated file structure realizes the physical portion of your Rose model. If you have developed only a logical model (class diagrams), the Ada Generator assumes an implicit physical model in which each class is effectively assigned to an implicit module specification, and therefore an Ada package specification.

The Basic Code Contents

The content of the generated code is based on the notation items in the logical portion of your model. In general:

The Ada Generator takes into account all model information that pertains to the selected class items, even information that does not appear in the diagram. For example, a component is generated for every "has" relationship that is defined for a class, including "has" relationships defined on other diagrams or in the class specification.

Entering Parameters for Parameterized Classes

The parameters for parameterized classes are entered in Rose using a dialog box which has two fields: Name and Type. Because there is such a large variety of formal parameters in Ada generics, and of discriminants in unconstrained types, users must follow a convention that specifies the nature of the parameters. Roughly speaking, the Name field contains the name of the parameter, and may start with an Ada keyword that indicates its nature. The type field contains any additional information that may be needed to complete the formal parameter or discriminant declaration. The Ada Generator adds the syntactic glue required by the language, such as the reserved words with, is, new, and the colons and semicolons.

Here is a detailed list of the possible formal parameters, and how they may be entered in the Type and Name fields. Note that an anonymous access type is only allowed if the Unconstrained Type implementation is used. Conversely, formal types, procedures, functions, packages, and formal object with an explicit mode are only legal if the Generic implementation is used.

For actual parameters (appearing in bound classes) the convention is the following: the Name field contains the value of the actual parameter, and the Type field contains the name of the formal parameter. For example, if a parameterized class has the following parameters:

Name:    Foo
Type:    Float

it may be instantiated using the following parameters:

Name:    3.14
Type:    Foo

Entering Static Attributes and Metaclass Attributes

Static attributes and metaclass attributes can result in a wide variety of (package-level) declarations. They are entered in Rose using a dialog box which has two fields: Name and Type. In order to control the nature of the declaration that is generated, users must follow the following conventions:

The following examples demonstrate how to use these fields, and what is the corresponding Ada declaration:

Evaluating the Generated Code

After you have located the generated files, you evaluate them to determine whether to use them as generated. Based on your evaluation, you may decide to regenerate the code after refining the model, adjusting the values of code-generation properties, or both.

Use the information provided in the rest of this chapter to guide your evaluation. Each section lists some of the things you can change about a particular aspect of code generation.

Completing the Implementation of the Generated Code

When you are satisfied with the way code is generated from your model, you complete the code by implementing the package bodies. If you did not use the Ada Generator to create stubbed bodies, you can select the specifications in Apex, and choose the Build Body command from the Compile menu. Rational recommends, however, that you let Rose generate code for the bodies, since it will produce the appropriate code regions.

To complete the implementation of your code, you may insert additional statements and/or declarations in the preserved code regions. A preserved code region is a special block of comments starting with --## and containing the clause preserve=yes. Preserved code regions are preserved by the code generator the next time the code is regenerated. This makes sure that you may continue evolving your model in Rose after you have started refining the implementation of the code. Note that some of the code regions that Rose generate have preserve=no, so if you want them preserved, you must change this clause to preserve=yes.

You cannot add your own code regions: if you try to do this, they will be considered orphaned by the code generator (see below). You must use the code regions produced by the Ada Generator. Here is a list of the code regions that the Ada Generator produces:

Regenerating Code

You can regenerate code for a given set of class items by following the same steps you used to generate the original code. When you regenerate code into existing files, the current contents of these files are saved in backup files before the new contents are written. By default, each backup file has the extension .1.ad~ or .2.ad~, as appropriate. The same backup files are overwritten each time you regenerate code to the same source-code files. The regenerated files:

Note that if you delete or rename a notation item for which a code region was preserved, that region is "orphaned" when you regenerate code. This means that the Ada Generator places the code region in a special section at the end of the regenerated file so that you can decide whether to reuse any of the edits you made in that region. The Ada Generator automatically changes the preserve keyword to no in orphaned regions, so that they are discarded the next time you regenerate the file.


Refining the Subsystem and View Structure

Determining the Directory for an Ada File

There are several properties which the Ada Generator uses when determining the directory for an Ada file, if Apex is available:

The directory for a module is based on the concatenation of the project Directory property, and the UML package's ApexSubsystem and ApexView properties. Modules must be contained within component UML packages.

The directory for a class which has been assigned to a module is determined by applying these rules to its assigned module. The directory for a class which has not been assigned to a module is based on the UML package to which it is assigned: if it is enclosed in a logical UML package which is assigned to a component UML package, its directory is created from the ApexSubsystem and ApexView properties for the component UML package. If ApexSubsystem is blank, the subsystem name is set to the name of the component UML package.

If it is enclosed in a logical UML package which is not assigned to a component UML package, its directory is created from the default values of ApexSubsystem and ApexView properties, plus the project Directory property. If the default ApexSubsystem property is blank, the subsystem name is set to the name of the logical UML package.

If Apex is not available, a hierarchy of directories is created using the name of the component UML packages (if they exist) or of the logical UML packages (in the absence of component UML packages).

Mapping Classes and Modules to Ada Units

By default, each class is assigned to an implicit module specification. From these implicit modules, the Ada Generator produces a package specification containing the class definition. The units are generated according to the values in the default module-spec property set.

To change the default mapping from classes to units, you may either change the class name, or assign two or more classes to the same module, as follows:

1 Introduce component diagrams into your model.

2 Create a module specification for each Ada specification you want to generate.

3 Assign each class to the appropriate module via the class's specification: to generate a package specification, you assign the class to a module specification. To generate the code for multiple classes in a single package, you assign each class to the same module.

Specifying Filenames

The name of a generated file has two parts: a name and an extension, separated by a period (for example, foo.1.ada). The name is generated automatically, and the extension is controlled by different code-generation properties. If you are using Rational Apex, you should not change these values.

When a file is generated from a module, the filename is determined by the name of the module: it is the same as the module name, except in lowercase.

In the default case where classes are mapped to implicit modules, each implicit module assumes the name of the corresponding class. Consequently, each generated filename is based on the implicit module name (and, indirectly, on the class name).

To specify a non-default file name for a generated class, introduce a component diagram, if necessary, and assign the class to a module specification with the desired name.


Refining Class Definitions (Ada 83)

The Ada Generator creates a type declaration for each selected class. The format of the type depends on the following property values:

See Code Generation Properties for more information on each property.

Standard Operations

Standard operations are subprogram declarations that are commonly found in Ada classes. They include:

By default, each class is generated with a default constructor, copy constructor, and destructor. Class properties permit you to specify the kind (procedure or function) and name for some of these standard operations.

Note that you can overload a standard operation by setting the relevant class property to cause it to be generated, and then specifying one or more additional operations with the same name, but different parameters in the class specification.

User-Defined Operations

User-defined operations are subprogram declarations that are generated from the operations you define in a class specification. Note that you do not need to define standard operations in a class specification, unless you want to overload them (see above).

If you want additional subprogram declarations for a class, or if you want different arguments or return types, you must edit the class specification.

One operation property, ClassParameterMode, permits you to specify the parameter mode of the class parameter, which is included automatically.

Get and Set Operations

Get and set operations are subprogram declarations that provide access to components. By default, a pair of get and set operations are generated from each "has" relationship, providing the relationship is public.

You can suppress the generation of a get and set operations by blanking-out the GetName and SetName properties in the property set that is attached to the has relationship. To define your own get and set functions, you define them as you would any other user-defined operation in the class specification.

Inherited Operations

When one class (called a subclass) inherits another class, all of the visible user-defined, get, and set operations defined in the superclass get replicated in the package specification of the subclass. This is how Ada 83 can achieve inheritance: the data is inherited by adding a field to the record, and the operations are inherited by replicating them in the subclass definition.

When you implement the body of an inherited operation, you typically do nothing except call the operation of the inherited class with record field that matches that class. If you do anything else, you are overriding that operation.

Record Fields and Object Declarations

Record fields are generated from "has", association and generalization relationships and attributes defined in diagrams or in specifications. (If you have set the static adornment on the "has" relationship, an object declaration in the private part of the package specification is generated.

The component type is determined by a number of factors. By default, the type is determined by a combination of the supplier class and the multiplicity and containment of the "has" relationship.

In the simplest cases, the component type is:

In more complex cases (maximum allowable cardinalities larger than 1), the Ada Generator inserts a container class for the component type, which you can either use as generated or replace with the name of a container class of your own.

For bounded containers, the Ada Generator creates an array declaration in the private part of the class package specification.

For unbounded containers, the Ada Generator instantiates a container generic package in the private part of the package specification.

You replace these default container classes by setting the various Container class properties.


Specifying Additional Ada Unit Contents

You can tailor aspects of the structured comments and context clauses that appear at the beginning of the generated Ada units. You can also cause the Ada Generator to generate visible declarations at the beginning of one or more units.

Adding Structured Comments

The Ada Generator inserts a block of structured comments at the beginning of each generated file. You can set properties to generate a copyright notice string in these comments.

In the default case where classes are mapped to implicit modules, you edit properties in the default module-spec property set, which is attached to the implicit modules. If you have explicitly assigned classes to modules, you must edit each property set that is attached to a module.

Adding With Clauses

By default, the Ada Generator produces with clauses in units based on class relationships and module dependencies in your model. If you want additional with clauses to appear in one or more generated files, use one of the following methods, as appropriate.

If you want more generated units to reference each other in with clauses, you can inspect the relationships among existing items in the model to determine whether you have represented them adequately.

For example, you may find that you need to add a uses relationship from one class to another, which will cause a with clause to be generated in the first class's Ada unit. (A with clause is generated only if the classes are generated in different units.)

Similarly, you can introduce dependencies among modules in a module diagram, which result in generated with clauses.

If you want any of the generated units to reference units that are not among the generated units, you can use the AdditionalWiths property to insert additional with clauses to reference those units.

If you want to put a special with clause in just one or two generated units, you can do so by editing these units directly. To do this, you insert the desired with clauses between these source markers at the beginning of the unit:

--##begin module.withs preserve=yes
--##end   module.withs

Adding Global Declarations

You can cause the Ada Generator to generate global declarations before the first class definition in a unit. To do this, you:

1 Introduce a module diagram, if necessary, and assign one or more classes to a module specification (or body, as appropriate).

2 Double-click on the module specification to bring up its specification.

3 Enter the desired declaration(s) in the Declarations box. The text you enter here will be inserted at the beginning of the generated unit.


Rational Software Corporation  http://www.rational.com
support@rational.com
techpubs@rational.com
Copyright © 1993-2001, Rational Software Corporation. All rights reserved.
TOC PREV NEXT INDEX