Documentation:BDL

From The BABEL Development Site
Revision as of 18:04, 21 May 2009 by Jlblanco (talk | contribs) (Others (enum, string))

BABEL Definition Language (BDL)

v. 120606

A data definition language for the BABEL development system.

System Engineering and Automation Department.

University of Málaga, Spain.





Introduction

What is BDL?

BDL (Babel Definition Language) is the medium for specifying, in a programming-language independent fashion, some data types that a BABEL module needs. BDL has been implemented as a restricted subset of one of the most extended definition languages: the OMG CORBA IDL (www.omg.org).

Where the BDL types are used?

It is used currently for defining input/output parameters of services and for providing public definitions (data types that the module provides to other modules and to itself). You can use BDL types both in the "Public Definitions" of the module and in the specification of the input/output parameters of the services. You can compose your own types (using "typedef") based on BDL basic or composed types.

What the BDL types are used for?

You can use a variable of a BDL type in the following situations: A) Creating a local variable for the internal use of some logic of the module (auxiliary logic, service logic, start-up logic, etc.). B) Creating a global variable for the internal status of the module (accessible from any logic of the module). C) Using an already defined input/output parameter of a service.


How variables of the BDL types are used?

You should remember that BDL is not a programming language (only a specification for data), and thus, you cannot use directly any BDL type in your codification logics. Rather, BABEL translates automatically for you the BDL types into types understandable by the codification language you have chosen for your module (see for example the Using BDL in the C++ codification language section).


BABEL Definition Language (BDL)

Basic types

Numeric (octet, short, long, ...)

BDL includes the following basic numeric types:

  • octet : 8-bit, unsigned (0...2^8-1)
  • short : 16-bit, signed (-2^15...2^15-1)
  • unsigned short : 16-bit, unsigned (0...2^16-1)
  • long : 32-bit, signed (-2^31...2^31-1)
  • unsigned long : 32-bit, unsigned (0...2^32-1)
  • long long (*) : 64-bit, signed (-2^63...2^63-1)
  • unsigned long long (*) : 64-bit, unsigned (0...-2^64-1)
  • float : IEEE single-precision floating point numbers.
  • double : IEEE double-precision floating point numbers.

(*): The 64-bit integer types (long long and unsigned long long) could not be available in some implementations, being mapped in an undefined way, so its use should be avoided.


Alphanumeric (char)

BDL has only one basic alphanumeric type:

  • char : One unsigned 8-bits character.

There is also one composed alphanumeric type: string.


Others (boolean)

BDL includes one basic type for logical operations:

  • boolean : Stores a boolean value (TRUE or FALSE)



Composed types

Not-Repeated (struct)

BDL includes the following composed type that does not contain more than one occurrence of an object:

  • Structs: They are analogous to C structs, and can contain both basic and composed types fields. For example:

<cpp> struct MyStructName { short FieldOne; double FieldTwo; OtherStructName osn; } MyVarStruct; </cpp>

The union data type is not supported currently in BDL.


Repeated (sequence, array)

BDL includes the following composed types that can hold more than one occurrence of an object:

  • Sequences: An ordered list of elements of the same type (maybe composed). A maximum limit of elements can be specified, or not. For example:

<cpp> struct LimitedAccounts { string bankSortCode<10>; sequence<Account> accounts; // No maximum length of sequence. sequence<Account,50> accountsBis; // 50 is the maximum length of sequence. }; </cpp>

  • Arrays: Fixed-length indexed sets of elements of the same type (maybe composed). For example:

<cpp> struct SomeAccounts { string bankSortCode<10>; // string of length 10 Account accounts[10][2]; // array of dimensions 10x2 }; </cpp>


Others (enum, string)

BDL includes these other composed types:

  • Enumerated: The enumeration of several constants. No numeric equivalence should be assumed. For example:

<cpp> enum Currency {pound, dollar, yen, franc}; </cpp>

  • Strings: Sequences of characters of 8 bits each. They can be given a fixed maximum length. For example:

<cpp> struct MyStructName { string<10> MyString; // A string that can store no more than 10 characters string MyString2; // A string without maximum length } MyStructVar; </cpp>


Data type alias (typedef)

The typedef keyword has been introduced to define array data types, but it also can be used to define alias for already defined data types.

The syntax is:

<cpp> typedef < an already defined data type > < an alias for that type >; </cpp>

For example:

<cpp> struct MyStruct { long A; string B; };

typedef struct MyStruct MyAliasForMyStruct; typedef unsigned long MyAliasForUnsignedLong;

typedef sequence<short, 50> ShortListType; typedef sequence<long> LongListType;

typedef short ShortArrayType[50][10];

typedef enum MyCurrency {pound, dollar, yen, franc} OtherCurrency;

typedef string<10> MyStringType; typedef string MyString; </cpp>


Constants (const)

The way of defining constants in BDL is: <cpp> const <type> <const name> = <value>; </cpp>

For example:

<cpp> const float PI=3.14159265; const char NUL='\0'; const string LAST_WORDS="My god, it's full of stars!"; </cpp>



Using BDL in C++ codification language

Fixed-length and variable-length data types

The implementation and usage of the BDL data types can be different if the data type is fixed-length or variable-length.


Fixed-length data types

  • octet
  • short

- unsigned short - long - unsigned long - long long - unsigned long long - float - double - char - boolean - enum


Variable-length data types

  • Bounded and unbounded string
  • Bounded and unbounded sequence


Data types that can be fixed-length or variable-length

  • A struct is fixed-length if all its members are fixed-length. It is variable-length if one or more of its members are variable-length.
  • An array is fixed-length if its base type is fixed-length. If its base type is variable-length, then the array is variable-length.

Note: A variable-length array is not an array with a variable number of elements; it is an array with a variable-length element data type.


First consideration: fixed-length and variable-length data types

The first issue when BDL types are translated into C++ is that service output parameters are translated as reference (DataType &) for fixed-length data types, but as a reference to a pointer (DataType *&) for variable-length data types. For variable-length data types, there is also the need to manage the allocation and deallocation of its memory (BABEL does not provide code for that). For specific information, see the documentation for each data type under Usage of BDL in C++.


Examples:

<cpp> // All of this is BDL struct FStrA { // a fixed-length struct (float and long are fixed-length) float f; long c; };

struct VStrB { // a variable-length struct string name; // the struct is variable-length because of this string member unsigned short age; };

struct VStrC { // another variable length struct (the data member contains a string) long x; VStrB data; // the struct is variable-length because of this variable-length struct member };

typedef long FArrA[8][3]; // A fixed-length array (long is fixed-length) typedef FStrA FArrB[8]; // A fixed-length array (FStrA is fixed-length) typedef string<10> VArrC[7]; // A variable-length array (a bounded string is variable-length) typedef VStrB VArrD[12]; // A variable-length array (VStrB is variable-length) </cpp>

Basic types

All the basic types are mapped to types defined in the portable namespace "BABEL" (this is done indepently on the codification language chosen), with functionalities that are indistinguishable from native C++ types. However, octet, boolean, and char may be mapped to the same native C++ type, so any overloaded function that is overloaded solely on these types should be avoided. Also, the 64-bit integer types (long long and unsigned long long) could not be available in some implementations, being mapped in an undefined way.

Translation of basic BDL data types to C++

Numeric:

  • octet: BABEL::Octet
  • short: BABEL::Short
  • unsigned short: BABEL::UShort
  • long: BABEL::Long
  • unsigned long: BABEL::ULong
  • long long: BABEL::LongLong
  • unsigned long long: BABEL::ULongLong
  • float: BABEL::Float
  • double: BABEL::Double

Alphanumeric:

  • char: BABEL::Char

Others:

  • boolean: BABEL::Boolean.

There are two predefined boolean constants: - BABEL::True - BABEL::False

One can use a BABEL::Boolean variable as a C++ bool type, but it can be defined as another type. You can compare a Boolean value with BABEL::False, but the comparison with BABEL::True should be avoided (use v!=BABEL::False or !v instead of v==BABEL::True).


Using basic data types as service parameters

The basic data types are mapped as BABEL::datatype (as shown above) when used as input parameters in services, and as BABEL::datatype& when used as output. For example, a service "MyOp" with the input parameters "char ch" and "long lg" and the output parameters "boolean bl" and "float fl" can be considered as though it was translated into the following C++ method:

<cpp> void <some class not interesting for the user>::MyOp(BABEL::Char ch, BABEL::Long lg, BABEL::Boolean& bl, BABEL::Float& fl); </cpp>

Input parameter (caller point of view)

Since the data type is passed by value, the caller can use for it a local variable, constant, or expression.

Input parameter (callee point of view)

The callee can use and change the value of the input parameter, but, since it was passed by value, the changes will not be sent back to the caller.


Output parameter (caller point of view)

The output parameter type is a reference to the data type, so the caller must use a variable (defined in the caller) of the corresponding translated data type to receive the output value. The initial value of this variable will be ignored by the callee.

Output parameter (callee point of view)

The callee must ignore the initial value of the output parameter (it can be different from the one passed by the caller), and must set a new value (at least once). If the caller does not set the value, then it will be undefined, and this is an error.



Composed Types

Not-Repeated (struct)

The struct data type is mapped to a C++ struct with equivalent members.

Translation example:

<cpp> // BDL struct FStrA { // a fixed-length struct float f; long c; };

struct VStrB { // a variable-length struct string name; // the struct is variable-length because of this string member unsigned short age; };

struct VStrC { // another variable length struct long x; VStrB data; // the struct is variable-length because of this variable-length struct member }; </cpp>

<cpp> // C++ struct FStrA { // a fixed-length struct BABEL::Float f; BABEL::Long c; }; // Full name: BABEL::MyModule::FStrA

struct VStrB { // a variable-length struct (because of the string member) /* string manager class */ name; // the class name is not defined and should not be used BABEL::UShort age; }; // Full name: BABEL::MyModule::VStrB

struct VStrC { // another variable length struct BABEL::Long x; VStrB data; // the struct is variable-length because of this variable-length struct member }; // Full name: BABEL::MyModule::VStrC </cpp>


Dynamic allocation and deallocation

A struct can be dynamically allocated and deallocated using C++ new and delete operators. If the struct contains any strings (directly or inside another contained data type) then, the strings will be initialized to "" instead of NULL.


Deep copy of struct variables

When you use the assignment operator (=), the struct is deep copied. Any allocated memory will be duplicated, so one can change a copied or original struct without changing the other.


Fixed-length and variable-length struct data types

A struct is variable-length if it contains strings or sequences (directly as a member or recursively). If it does not, the struct is fixed-length. See fixed-length and variable-length data types for a detailed definition of fixed-length and variable length data types.

One must know if a struct is fixed-length or variable-length to know how to pass it as an output parameter of a service (an operation).


A struct as an input (in) parameter (caller point of view):

The struct will be sent as const MyStructDataType&, so the caller needs a variable of that struct to use it as an input parameter of a service.


A struct as an input (in) parameter (callee point of view):

Since the input struct is const MyStructDataType&, the callee cannot change it.


A fixed-length struct as an output (out) parameter (caller point of view):

The parameter type will be MyStructDataType& so the caller needs a variable of that struct to use it as an output parameter of a service. The initial content of the variable is ignored by the callee.


A fixed-length struct as an output (out) parameter (callee point of view):

The parameter type will be MyStructDataType&. The callee must ignore the initial value of the output parameter (it can be different from the one passed by the caller), and must set a new value (at least once). If the caller does not set the value, then it will be undefined, and that is an error. The callee can set the parameter's value assigning another struct of the same type or by setting all of its members. Please, see the documentation of the data type (string, sequence, others...) to know how to do the assignment.


A variable-length struct as an output (out) parameter (caller point of view):

The parameter type will be MyStructDataType*& (not MyStructDataType& used with fixed-length structs). The caller needs a pointer variable to use it as an output parameter of a service. In that pointer variable, the service will store a pointer to the returned struct. The caller must free the memory when the struct is not needed (using the C++ delete operator). The pointer variable value will be overwritten without freeing its content, so, make sure to free its contents before using it as an output parameter.


A variable-length struct as an output (out) parameter (callee point of view):

The parameter type will be MyStructDataType*& (not MyStructDataType& used with fixed-length structs). The callee must allocate a new struct using the C++ operator new, change any member as needed, and store the pointer to the allocated struct in the output parameter. The initial value of the output parameter is undefined and must not be used or freed. The caller must do the assignment to the output parameter once and only once. If you do it more than once, the previous struct will not be freed. If you do not assign any pointer to it, the parameter value will be undefined and that is an error. However, the callee can assign a pointer, then delete it using delete and then assign a new pointer.


Repeated (sequence, array)

The sequences are mapped to C++ classes.

Examples: See array operators and the get_buffer functions for examples of the sequence usage.

Dynamic allocation and deallocation

To dynamically allocate and deallocate a sequence, one can use the new and delete C++ operators. The buffer used by the sequence is managed automatically.


A sequence as an input (in) parameter (caller point of view):

The sequence will be sent as const MySequenceDataType&, so the caller needs a variable of that sequence to use it as an input parameter of a service.


A sequence as an input (in) parameter (callee point of view):

Since the sequence is const MySequenceDataType&, the callee cannot change it. Note that the sequence could be empty.


A sequence as an output (out) parameter (caller point of view):

The parameter type will be MySequenceDataType*&. The caller needs a pointer variable to use it as an output parameter of a service. In that pointer variable, the service will store a pointer to the returned sequence. The caller must free the memory when the array is not needed, using the C++ delete operator. The pointer variable value will be overwritten without freeing its content, so, make sure to free its contents before using it as an output parameter.


A sequence as an output (out) parameter (callee point of view):

The parameter type will be MySequenceDataType*&. The callee must allocate a new sequence using the C++ new operator. After the allocation, change the content as needed, and store the pointer to the allocated sequence in the output parameter. The initial value of the output parameter is undefined and must not be used or freed. The caller must do the assignment to the output parameter once and only once. If you do it more than once, the previous sequence will not be freed. If you do not assign any pointer to it, the parameter value will be undefined and that is an error. However, the callee can assign a pointer, then delete it using delete and then assign a new pointer.

Warning: The callee can return a empty sequence, but not a NULL pointer (assigning a NULL pointer to the output parameter is not valid).

Using the output parameter:

After assigning a pointer to the output parameter, the callee can use the pointed sequence as usual, but one must remember that the parameter is a pointer, not a sequence. For example:

<cpp> out_seq = new BABEL::MyModule::MyStringSequenceDataType(); out_seq->length(1); // use -> instead of . (*out_seq)[0] = BABEL::string_dup("my string"); // use (*out_seq)[index] instead of out_seq[index] </cpp>

Others (enum, string)

The enum data type is mapped directly to a C++ enum.


Translation example:


<cpp> // BDL enum MyEnum {one, two, three}; </cpp>

<cpp> // C++ enum MyEnum {one, two, three}; // the full name for using it will be: BABEL::MyModule::MyEnum </cpp>


Using enum as service parameter:

The enum data types are mapped as datatype (shown above) when used as input parameters in services, and as datatype& when used as output. For example, a service "MyOp" with an input and output parameters (a_in and b_out) of the enumerated "MyEnum" can be considered as though it is translated into the following C++ method:

<cpp> void <some class uninteresting for the user>::MyOp(BABEL::MyModule::MyEnum a_in, BABEL::MyModule::MyEnum& b_out); </cpp>


Input parameter (caller point of view):

Since the enum is passed by value, the caller can use a variable or a constant enumerator (an enumerated value) of the same translated type.


Input parameter (callee point of view):

The callee can use and change the value of the input parameter as expected, but, since it was passed by value, the changes will not be sent back to the caller.


Output parameter (caller point of view):

The output parameter type is a reference to the enumerated type, so the caller must use a variable of the translated enumerated type to receive the output value. The initial value of this variable will be ignored by the callee.


Output parameter (callee point of view):

The callee must ignore the initial value of the output parameter (it can be different from the one passed by the caller), and must set a new value (at least once). If the caller does not set the value, then it will be undefined, and this is an error.



Data type alias (typedef)

An alias for a data type created by the BDL typedef keyword behaves as the original data type. For example, an alias for an array should be treated as if that alias was an original array.


Constants (const)

The BDL constants are mapped to equivalent C++ constants. To use a constant one must add BABEL::MyModule:: before the name of the constant ("MyModule" is the name of the BABEL module). Thus, the constant PI should be referenced in C++ as BABEL::MyModule::PI.

For example:

<cpp> // BDL const float PI=3.14159265; const char NUL='\0'; const string LAST_WORDS="My god, it's full of stars!"; </cpp>

<cpp> // C++ static const BABEL::Float PI=3.14159265; static const BABEL::Char NUL='\0'; static const char* LAST_WORDS="My god, it's full of stars!"; </cpp>