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; }