| ### C++ Composition Tools

AHEAD supports a provisional set of tools for composing C++ files, specifically .cpp and .h files. These tools, mix and unmix, approximate a counterpart to the mixin and unmixin tools of AHEAD. In the following, we sketch the basic design of how C++ files can be composed, and then describe the mix and unmix tools themselves. This material and the tools themselves are subject to change.

- Design
  - .h Files
  - .cpp Files
- The mix Tool
- The unmix Tool

## Design

Our goal is to be able to compose C++ files. To do this easily and quickly, we require the following constraints.

- Each C++ class is defined in a pair of files: a .cpp file and a .h file. The .h file defines the signature or header of a C++ class (where all data members and the signatures of each method is defined) plus a .cpp file where the methods of the class are defined.
- Each C++ class is either a base class (AHEAD constant) or a mixin (AHEAD refinement). As in the mixin tool, when classes are composed, the names of the class, its superclass, and namespace (which corresponds to the Java package construct) can change. We will given them a standard name and use the C++ preprocessor to assign them their correct names. Thus, when specifying .cpp and .h files, special identifiers will be used to designate the name of a class, its superclass, and namespace. These identifiers are class_, super_, and namespace_.
- C++ files typically include other .h files. To prevent the inclusion of the same file multiple times (as can arise when files are composed), we follow the lead of the mixin and jampack tool by harvesting all import statements, forming their union, and listing them at the top of a composed file. As we want our provisional tools to be as simple as possible, we will use a special identifier to designate imports, namely "import_". When the mix tools sees an "import_" statement, it performs the #import harvesting as described here.

With the above constraints, we can integrate the mix tool with composer, and use AHEAD tools and design techniques to synthesize applications in C++. Examples of all the above will be given shortly.

### .h Files

An example of a .h file for a base class is listed below:

>     import_ "Param.h"

>     class class_ {
>        public:
>           class_(Param& b);
>           string GetName();
>           int Dof() const;
>           bool SetServoValue(const RRVector& v);

>        protected:
>           int m_dof;
>           string m_name;
>           RRVector m_vals;
>     };

Note the use of the class_ and import_ identifiers. In general, class_ is used to designate the name of the class, class constructor(s) and class destructor(s). An example of a .h file for a refinement class is:

>     import_ "Param.h"

>     class class_ : super_ {
>        public:
>           class_(Param& b);
>           bool SetServoValue(const RRVector& v);
>        protected:
>           RRVector m_minLimits;
>           RRVector m_maxLimits;
>     };

Note the use of class_, super_, and import_ identifiers.

### .cpp Files

An example of a .cpp file of a base class is:

>     import_ "Servo.h"

>     class_::class_(Param& b) {
>        m_dof = b.dof;
>        m_name = b.name;
>     }

>     string class_::GetName() {
>        return m_name;
>     }

>     int class_::Dof() const {
>           return m_dof;
>     }

>     bool class_::SetServoValue(const RRVector& v) {
>        m_vals = v;
>        cout<<v<<endl;
>        return true;
>     }

Note that class constructors are always defined as class_::class_ and destructors are class_::class_~. An example of a .cpp file of a refinement is:

>     class_::class_(Param& b) : super_(b) {
>        m_minLimits = b.minLimits;
>     m_maxLimits = b.maxLimits;
>     }

>     bool class_::SetServoValue(const RRVector& v) {
>        bool isInLimits = true;

>        //check limits here
>        for(int i=0; i< m_dof; i++) {
>           ...
>        }//end check limits

>        return super_::SetServoValue(v);
>     }

Note how class_ and super_ are used.

## The mix Tool

mix is a tool that composes .cpp and .h files. It is really never called directly by users. Rather, AHEAD users simply invoke composer, and composer invokes mix. In this section, we explain how mix works so that users can better understand its mechanics. When mix composes a set of .cpp or .h files, it does the following:

- it harvests all import_ statements, forms their union, and generates qualified #include statements for each file to be included.
- it copies each file to be composed, commenting out each import_ statement
- it generates qualified preprocessor statements that assign values to the class_, super_, and namespace_ identifiers

Suppose the base and refinement .h files defined above are composed. The result is:

>     #ifndef _import_			(1)
>     #include "Param.h"
>     #define _import_
>     #endif

>     class Servo;				(2)

>     #ifdef class_				(3)
>     #undef class_
>     #undef super_
>     #undef namespace_
>     #endif

>     #define super_ Servo__0
>     #define class_ Servo__1
>     #define namespace_ test2

>     //SoUrCe ../Base/Servo.h		(4)
>     //import_ "Param.h"			(5)

>     class class_ {				(6)
>        ...
>     };

>     //EnDSoUrCe 				(7)

>     class Servo;

>     #ifdef class_
>     #undef class_
>     #undef super_
>     #undef namespace_
>     #endif

>     #define super_ Servo__1
>     #define class_ Servo
>     #define namespace_ test2

>     //SoUrCe ../Limits/Servo.h
>     //import_ "Param.h"

>     class class_ : super_ {
>        ...
>     };
>     //EnDSoUrCe

Note the following, which corresponds to the numbering above

1. These statements define the union of the import_ statements.
2. Forward references are needed in .h files to reference the most refined version of a class. Forward references are generated only for .h files.
3. Here is where the names for class_, super_, and namespace_ are redefined only for the following class definition. These identifiers are renamed for each class declaration.
4. The SoUrCe comment indicates the beginning of a file, the EnDSoUrCe comment is a marker that designates the end of a copied file. It is used by the unmix tool, discussed below.
5. Note that all import_ statements of copied files are commented out.
6. This is the copied class definition (abbreviated).
7. This is the EndSoUrCe comment, again used by the unmix tool.

Thus, when each .h file is composed, new names are given to the class_ and super_ identifiers.

> Note: at the time of this writing, it is becoming obvious that this design can be improved, such as the elimination of the #ifdef _import_, the generation of only a single #define namespace_ statement, and maybe the generation of only a single forward reference. Once further improvements have been decided upon, the tool and its documentation will be updated.

As stated earlier, the mix tool really isn't called directly by users. Instead, users invoke composer and composer calls mix. The standard way is:

- create an equation file that defines the equation to compose. Example: test3.equation has the following content, which defines the expression Limits( Logging( Base )):

>     Base
>     Logging
>     Limits

- invoke composer to evaluate test3. composer should be invoked in the "model" directory, which has directories for features Base, Logging, and Limits. The result of a composition will be a new directory, named test3:

      > composer --equation=test3

If you insist on calling mix directly, do so as:

>     >mix
>     Error: must specify at least one input file
>     Usage: java mix.Main [options] baseFile extensionFile1 extensionFile2 ...
>            -a <layerName> name of layer to generate
>            -f <fileName> name file to generate
>            -output same as -f

## The unmix Tool

After files are composed, they are compiled, and a debugging cycle ensues: composed C++ files are edited, recompiled, etc. Manually backpropagating changes to the original .cpp and .h files is both tedious, slow, and error prone. Instead, you can use the unmix tool to do so automatically. unmix takes any number of .h and .cpp files produced by mix as input, and backpropagates their changes:

>     > unmix *.h *.cpp

>     > unmix
>     Error: must specify at least one input file
>     Usage: java unmix.Main [options] file1 file2 ...
>            -verbose

Use the -verbose option to see what files have changed. unmix does not propagate changes to source files that have not been changed.

When editing files, all text between //SoUrCe and //EnDSoUrCe comments defines a file. If unmix detects that changes to this file have been made, it backpropagates the entire file text. Note that it automatically uncomments import_ statements as part of this backpropagation effort.

ATS Home Page

Copyright © Software Systems Generator Research Group. All rights reserved.
Revised: February 08, 2006.