PENDING
Your UML model has to fit a template to be well interpreted by the generator. The chosen template is common to C generator and reverser in order to be consistent.
The default template is structured on several sub-packages and each of them plays a role. The three most important are "Source Artifacts", "Types" and "Libs":
EAnnotations bring additional information needed by the generator. They are always related to an UML element. Two distinct EAnnotations are used :
| Detail entry key | Expected value | On UML element | See |
|---|---|---|---|
| PROJECT_CHARSET | The charset to use | Model | Project charset |
| IFNDEF | Conditional inclusion | Classifier | Conditional inclusion |
| C_FILENAME | Relative path to the C file | Classifier | Module creation, Module and header creation |
| H_FILENAME | Relative path to the H file | Classifier | |
| STD_LIBRARY | true or false | Usage | |
| REGISTER | true or false | Property | __ |
| VOLATILE | true or false | Property | __ |
Before making generation, the project charset must be specified to avoid encoding issues. This step will have to be done at the highest level, directly under the uml:Model element of your model.
This step is not mandatory and can be skipped. In this case, the UTF-8 encoding will be applied while generating.
The visibility of the elements is used to define the target of the generated block.
In the Source Artifacts package:
In the Source Artifacts package:
In the Source Artifacts package:
UML Usage elements are used to manage inclusions. Create a UML Usage between the source (client) module and the target (supplier) UML Interface.
Generated code in Engine.h:
#include "Sensor.h"
To make the inclusion of a system-defined file (i.e. stdio), you have to add a "STD_LIBRARY" EAnnotation (see EAnnotations section) with "true" as value, on the UML Usage
Generated code:
#include <stdio.h>
From a UML Classifier ( UML Class or UML Interface), you can specify a conditional inclusion.
For that, add a "IFNDEF" EAnnotation (see EAnnotations section) with the macro constant label you want (i.e. "__ENGINE_H__") as value, on the UML Classifier.
Only the header file will be impacted during the generation. It will look like that:
#ifndef __ENGINE_H__
#define __ENGINE_H__
[...]
#endif
On the Types package of the model, create a UML Primitive Type named "Macro" if not already existing.
On a given UML Class, in a Source Artifacts package, add a UML Property and:
Generated code:
#define BUFFER_SIZE 1024
Same thing as the Object-like_one section. The name will be the signature of the function (i.e. "MAX(a, b)") and the value will be a statement ("((a < b) ? b : a)").
Generated code:
MAX(a, b) ((a < b) ? b : a)
On a UML Class, create a UML Property and set the name, type and visibility of your variable.
If your variable is private, you can set
isStatic to true to obtain a static variable (static will be added during generation).
Set
isReadOnly to true to create a constant (const will be added during generation)
When the property visibility is public, the variable declaration will be generated in the header file while the definition part will be located in the C file. If it is private, the variable declaration and definition will be both on the module file.
To define the variable as volatile or register, respectively add a "VOLATILE" or "REGISTER" EAnnotation (see EAnnotations section).
To initialize the variable, set the default value with a UML OpaqueExpression or UML Literal String and set the value you want on it.
Generated code:
In the header file:
extern const char* address;
In the module file:
const char* address = "0x456FEA";
For multi-dimensional variables, the dimension(s) is directly defined in the name of the ''UML Property" (i.e. "address_array[3]" or "record_matrix[MAX_ROW][MAX_COL]").
A typedef declaration lets you define your own identifiers that can be used in place of type specifiers such as int, float, double and so on.
You can make this definition creating a UML DataType and setting the name you want to express (i.e. "LENGTH"). Then, you have to set the redefined classifier feature with the type you want to redefine (i.e. UML Primitive Type int).
Generated code:
typedef int LENGTH
To redefine a pointer type, you have to reference your own type as redefined classifier (i.e. UML DataType int*)
Generated code:
typedef int* PTR_LENGTH
To define a multi-dimensional array type, you have to set, on the UML DataType, the named expression with a UML String Expression in order to specify the dimension(s). The value of the dimension must be set in the symbol feature, with brackets.
To define a function pointer, you have to add, in the UML DataType, through the ownedOperation feature, a UML Operation.
For example, here is the generated code for a function pointer type named "TYPES_COMMUNS__T_POINTER_FCT" which points to an operation with returns a type (output parameter) named "TYPES_COMMUNS__T_STATUS":
typedef TYPES_COMMUNS__T_STATUS (*TYPES_COMMUNS__T_POINTER_FCT)();
To define a structure, add a UML DataType, in your UML Class, with a name (i.e. "person") and a visibility. Then, add on it a UML Property with a name and type (i.e. "age") for each field of the structure.
Generated code:
struct person
{
char forename[20];
char surname[20];
float age;
int childcount;
};
To declare a structure, add a UML Property in your UML Class with a name and setting the type to the defined structure ( UML DataType).
For example, here is the generated code for 3 person declared structures as john, ed and paul:
struct person
{
char forename[20];
char surname[20];
float age;
int childcount;
} john, ed, paul;
To define a shorthand structure, create a new UML DataType with a name (i.e. "PEOPLE") and reference your structure as redefined classifier (i.e. UML DataType person).
For example:
typedef struct person
{
char forename[20];
char surname[20];
float age;
int childcount;
} PEOPLE;
To define an enumeration, add a UML Enumeration, in your UML Class, with a name (i.e. "week") and a visibility. The content of the enumeration is specified with a set of named UML Enumeration Literal. To specify a default value to a literal, set the specification feature on the literal with a new OpaqueExpression or LiteralString and set the value on it.
Example:
enum week
{
Monday = 0,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
To declare an enumeration, add a UML Property in your UML Class with a name and setting the type to the defined enumeration ( UML Enumeration).
For example, here is the generated code for 2 week declared enumeration as week30 and week31:
enum week
{
Monday = 0,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
} week30, week31;
To define a shorthand enumeration, create a new UML Enumeration' with a name (i.e. "WEEK") and reference your enumeration as ''redefined classifier (i.e. UML Enumeration week).
For example:
typedef enum week
{
Monday = 0,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
} WEEK;
To declare a function, create a UML Operation in your UML Class and:
extern keyword.
static keyword. Note that static will be generated only if visibility is set to "private".
Generated code example:
static BOOL checkValues(const INT32* valueA, const INT32* valueB);
To define a function, a UML OpaqueBehavior has to be created with the same name and parameters as the previous declaration, in the same UML Class. Its body feature must be set with your code implementation. At last, its specification feature must reference the previous declaration ( UML Operation).
Example of generated code:
// function declaration
static BOOL checkValues(const INT32* valueA, const INT32* valueB);
// function definition
static BOOL checkValues(const INT32* valueA, const INT32* valueB)
{
if (*valueA >=0 && *valueA < 256)
{
if (*valueB >=0 && *valueB < 256)
{
return TRUE;
}
}
return FALSE;
}
Comments can be added for every UML NamedElement objects and will be injected into the generated code.
To add a comment, you have to create a " http://www.eclipse.org/umlgen/c/documentation" EAnnotation, under the UML element to document, containing a detail entry where the key is "documentation" and the value is set to your comment content. The content must be raw comments, without any comment formatting characters (slash or star).
Generated code example:
/*
* This buffer will store information on 1024 bytes.
*/
#define BUFFER_SIZE 1024
For that, you must create a " http://www.eclipse.org/umlgen/annotation/c" EAnnotation with different detail entry keys, according to the context: "C_INLINE_COMMENT_AFTER_DECLARATION", "C_INLINE_COMMENT_BEFORE_DECLARATION", "H_INLINE_COMMENT_AFTER_DECLARATION", "H_INLINE_COMMENT_BEFORE_DECLARATION".
To generate C code, your UML model must be compliant with the template defined for this purpose (see Template organization). The generator will look for the source package ('Source Artefacts' by default) and will focus on the classifiers contained inside.