UML2C

Bx Examples Repository

Title: UML2C

Version: 0.1

Type: Sketch

Overview

This is a large-scale practical example of reversible code-generation for round-trip engineering. UML design models are mapped to a C metamodel, and from this to C code. The first transformation should be a bx.

Models

The source model is an instance of the UML design metamodel design.km3, including UML class diagrams, use cases, OCL and an activity language. The target model is an instance of the ANSI C metamodel c.km3.

The following class diagram corresponds to the example C declaration file app.h and to UML and C models basicmodels.txt.

simplemodel.jpg

Consistency

The UML and C models should represent the same application. In particular, C structs and UML classes should bijectively correspond, UML type occurrences should correspond bijectively to C type occurrences, and UML operations and use cases are represented as C operations, activities are represented as C statements, and OCL expressions as C expressions. Corresponding objects are linked by common values of identifier attributes, eg.: e1.expId = e2.cexpId for corresponding UML and C expressions e1 and e2. Details of the required relations are provided in the uml2Cj.pdf document.

The mapping of types is carried out in the first subtransformation, types2C, of UML2C, and the mapping of model structures, classdiagram2C, in the second. These subtransformations are sequentially composed.

The types2C transformation maps UML types (primitive types, classes, collection types) to C types. For example a UML class (as a type) is mapped to a C pointer type pt, with pt pointing to the struct C corresponding (as a program structure) to C. pt has corresponding typeId to C, and the struct has the same name as C. Names are unique for structs in the C model and for classes in the UML model, and similarly ctypeId is unique for CTypes and typeId for UML types. Names are disjoint from typeids.

The mapping of class types is expressed by the rule:

Entity::
  CPointerType->exists( p | p.ctypeId = typeId & 
         CStruct->exists( c | c.name = name & c.ctypeId = name & p.pointsTo = c ) )

In QVT-R this amounts to executing the following relation in the C direction:

top relation Class2PointerType
{ enforce domain design e : Entity
    { typeId = t, name = n };
  enforce domain C p : CPointerType 
    { ctypeId = t, pointsTo = c : CStruct { name = n, ctypeId = n} };
}

The reverse direction is expressed by the rule (derived as the logical dual of the forward rule):

CPointerType::
  c : CStruct & pointsTo = c  =>
     Entity->exists( e | e.typeId = ctypeId & e.name = c.name )

This corresponds to executing the QVT-R rule in the 'design' direction.

The mapping of model structures maps attributes of a class to members of the corresponding struct, inserts a 'super' member to represent single inheritance, and creates additional global variables to manage the collection of instances of a class. For example, the mapping of owned attributes is:

Entity::
    CStruct->exists( c | c.name = name &
      ownedAttribute->forAll( p | 
           CMember->exists( m | m.name = p.name & m.isKey = p.isUnique &
                        m.type = CType[p.type.typeId] & m : c.members ) ) )

The CStruct is looked up and not re-created, likewise for the CType for p.type. This rule could be expressed by 2 QVT-R rules. Name is unique for CMembers within a CStruct and for attributes within a class.

Consistency Restoration

Given a UML model d and C model c:

Forward: produce a modified version of c by (i) deleting from c any element that does not have a corresponding element in d; (ii) modifying each element of c that corresponds to an element of d to restore their required data relation; (iii) creating new elements in c for elements of d that have no corresponding element in c.

Backward: the same process with the roles of c and d reversed

Properties

Correct; Hippocratic

Discussion

The mappings of types and model structures operation as a bx. The mapping of expressions and statements runs into difficulties because of the complexity of some cases of OCL expressions (eg., various kinds of iterator expression which require the creation of multiple expressions in the C model to represent one in the UML model). It is an interesting challenge to improve this part of the mapping.

References

The case was reported in ‘Translating UML-RSDS OCL to ANSI C’, K. Lano, S. Kolahdouz-Rahimi, H. Alfraihi, S. Yassipour-Tehrani,
OCL 2017.

Author(s)

Kevin Lano

Reviewer(s)

Comments

Artefacts

The UML2C translator is available as part of the UML-RSDS tools.

The C metamodel is available here: c.km3

The design metamodel is available here: design.km3

Unless otherwise stated, the content of this page is licensed under GNU Free Documentation License.