Overview

EXPRESS models have several different kinds of definitions, and are transformed into C++ classes for efficient programming.

The C++ classes have the "stp_" prefix, which avoids symbol conflicts and makes it easy to identify clases in your code. The STEP "product" definition becomes the stp_product class, "cartesian_point" becomes stp_cartesian_point, and so on. A list of all classes is available with links to the EXPRESS definitions. The raw EXPRESS text is also available.

EXPRESS models are made of ENTITY definitions, which describe the instances that appear in a file. They also define union, aggregate, and enumeration types to characterize the values of entity attributes. All of these appear in the C++ libraries.

ENTITY

EXPRESS models are made of ENTITY definitions, which behave like a C struct. These have attributes that hold references to other entities or primitive data, and are organized into inheritance hierarchies.

The C++ class has a get and put function for each attribute. The attribute name may be capitalized if it conflicts with a reserved word, but otherwise is not changed. The class will inherit from the C++ classes corresponding with its EXPRESS supertypes. If it has no EXPRESS supertypes, it will inherit from the RoseStructure C++ class.

-- EXPRESS
ENTITY product;
      id : identifier;
      name : label;
      description : OPTIONAL text;
      frame_of_reference : SET [1:?] OF product_context;
END_ENTITY;


// C++
class stp_product : virtual public RoseStructure
{
public:
    const char* id();
    void id (const char* var);

    const char* name();
    void name (const char* var);

    const char* description();
    void description (const char* var);

    SetOfstp_product_context * frame_of_reference();
    void frame_of_reference (SetOfstp_product_context * var);
};

Primitive values are stored in place. Setting a string makes a copy of the value. Object values are stored as a pointer. All objects are created on the heap with pnewIn and owned by a RoseDesign.

RoseDesign * d;
stp_product * prod;

prod = pnewIn(d) stp_product;
prod-> id ("1234-ABC");
prod-> name ("super noodle");
// leave other atts null

SELECT

A SELECT type behaves like a C union that knows the type of value that it holds. Selects may contain strings or numbers, but usually bring together many ENTITY definitions which share no common supertype.

The C++ class has a get, put, and test function for each type. The get and put functions are prefixed with an underscore to distinguish it from the type name. The class always inherits from the RoseUnion C++ class.

-- EXPRESS
TYPE date_and_time_item = SELECT
  (action,
   action_method,
   [ 100+ entities omitted ]
   verification,
   verification_relationship);
END_TYPE;


// C++
class stp_date_and_time_item : public RoseUnion
{
public:
    RoseBoolean is_action();
    stp_action * _action();
    void _action (stp_action * var);

    RoseBoolean is_action_method();
    stp_action_method * _action_method();
    void _action_method (stp_action_method * var);

   [ functions for 100+ entities omitted ]

    RoseBoolean is_verification();
    stp_verification * _verification();
    void _verification (stp_verification * var);

    RoseBoolean is_verification_relationship();
    stp_verification_relationship * _verification_relationship();
    void _verification_relationship (stp_verification_relationship * var);
};

As seen in the example above, selects can get quite large, and may even be nested. The rose_get_nested_object and rose_put_nested_object functions get or put an entity in a select, taking care of any typing or nested selects, which covers most common situations.

stp_date_and_time_item * select_obj;
stp_action_method * am_obj;

// takes a RoseObject *, so we can put any type of object.  Will also
// create any nested selects if needed.
rose_put_nested_object (select_obj, am_obj);


// returns a RoseObject *, so still need to test if we want a specific
// type of object.  But will dig through any nested selects if present.
RoseObject * obj = rose_get_nested_object (select_obj);

if (obj->isa(ROSE_DOMAIN(stp_action_method))
{
     am_obj = ROSE_CAST(stp_action_method, obj);
     // do something
}

Lists, Sets, Arrays, Bags

Entity attributes can also contain collections of values. These collections inherit from the RoseAggregate C++ class and have a class name constructed by adding a "ListOf", "SetOf", "ArrayOf", or "BagOf" prefix to the content type.

These classes all act as expandable, strongly-typed, C arrays, with get, put, append, size, and other functions. An aggregate class is generated for each combination used in the schema, as found in the list of classes.

-- EXPRESS
ENTITY representation
      name : label;
      items : SET [1:?] OF representation_item;
      context_of_items : representation_context;
END_ENTITY;

// C++
class SetOfstp_representation_item : (ultimately RoseAggregate)
{
    stp_representation_item * get (unsigned i);
    void add (stp_representation_item * val);
    void put (stp_representation_item * val, unsigned i);
    unsigned size();
}

Because of the way EXPRESS defines the different aggregates, null values are ignored when adding to lists, sets, and bags. Adding to sets is implemented as an add-if-absent.

stp_representation * rep;
SetOfstp_representation_item * items;
unsigned i,sz;

items = rep->items();
for (i=0, sz=items->size(); i<sz; i++)
{
     stp_representation_item * it = items->get(i);
     // do something
}

Enumerations

Attributes can also contain enumerations. These are generated as C++ enum types, but have an extra "NULL" value. To avoid symbol conflicts, each value is prefixed by the type name. This is necessary because C++ puts all enum values in the same namespace.

-- EXPRESS
TYPE si_unit_name = ENUMERATION OF
      (metre,
       gram,
       second,
       [ some units omitted ]
       gray,
       sievert);
END_TYPE;

// C++
enum stp_si_unit_name {
	stp_si_unit_name_NULL = ROSE_NULL_ENUM,
	stp_si_unit_name_metre = 0,
	stp_si_unit_name_gram,
	stp_si_unit_name_second,
       [ some units omitted ]
	stp_si_unit_name_gray,
	stp_si_unit_name_sievert
};

The example below illustrates an enum in C++. When working with STEP units in practice, you may find the extension functions for STEP units useful.

si_unit * u;
switch (u->name()) {
case stp_si_unit_name_NULL:
    printf(None\n); break;

case stp_si_unit_name_metre:
    printf(Length, meter\n); break;

case stp_si_unit_name_gram:
    printf(Mass, gram\n); break;

default:
    printf(Something else\n); break;
}