# Generating C99 source file: ops structure As part of the C99 source file, there is an array of uint32\_t specifying the operation codes for (de)marshalling the data from and to the data structures defined in the generated header file. This sequence is generated by starting with the struct and output some operation codes for each of the members of the struct, followed by a return operation code. ## Basic types For members with a basic type, at least two uint32\_t values are used. The first specifies the operation and the second and following the operands. The operation is specified by combining (with bit-or) flags. The flags specify: * The type of the member. For the basic type this specifies the size of the type. For string and bounded string, separate flags are used. * Whether the field is a key field * Whether it is an array. If it is an extra operand will speficify the total size of the array (by multiplying the sizes of the various dimensions). * Whether the type is a sequence. (In case the elment type is a struct, additional information will follow the operation and its operands, as described below.) In case of a bounded string, an extra operand will follow, to specify the size (including its terminating null-character) of the bounded string. The operand for a simple type makes such of 'offsetof', which returns the offset of a field in a struct. ### Examples of nummeric fields Given the IDL struct definition: ```C struct M { char ch; short i; unsigned long ul; long long ll; float f; double d; }; ``` will need the following operation codes (using the predefinted macros): ```C DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (M, chr), DDS_OP_ADR | DDS_OP_TYPE_2BY, offsetof (M, i), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (M, ul), DDS_OP_ADR | DDS_OP_TYPE_8BY, offsetof (M, ll), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (M, f), DDS_OP_ADR | DDS_OP_TYPE_8BY, offsetof (M, d), DDS_OP_RTS, ``` The `DDS_OP_ADR` macro indicates that the operand will be an address. The `DDS_OP_TYPE_1BY` to `DDS_OP_TYPE_8BY` specify the size of the data type. Note that there is no difference between signed and unsigned integer values. In case one of the fields is a key the ` | DDS_OP_FLAG_KEY` will be added to the operator. The `DDS_OP_RTS` is to indicate the end of the operation codes for the structure. ### Examples of strings Given the IDL struct definition: ```C struct M { string str; string<4> str4; }; ``` will need the following operation codes: ```C DDS_OP_ADR | DDS_OP_TYPE_STR, offsetof (M, str), DDS_OP_ADR | DDS_OP_TYPE_BST, offsetof (M, str4), 5, DDS_OP_RTS, ``` ### Example of a sequence of a basic type Given the IDL struct definition: ```C struct M { sequence longs; sequence strings; }; ``` will need the following operation codes: ```C DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_4BY, offsetof (M, longs), DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STR, offsetof (M, strings), DDS_OP_RTS, ``` In this the `DDS_OP_SUBTYPE_` define that the element type of the sequence as being `DDS_OP_TYPE_`. ### Example of an array of a basic type Given the IDL struct definition: ```C struct M { long arr[4][5]; }; ``` wil need the following operation codes: ```C DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_4BY, offsetof (M, arr), 20, DDS_OP_RTS, ``` Note that 20 is the product of 4 and 5. ## Member that is a struct itself When a member is a struct (both embedded and refered), the members of that struct are also included, where in `offsetof` the selection of the nested field is used. For example, `coord.x` when the member has the name `coord` and uses a struct that has a member with name `x`. ## Sequence of struct or sequence In case of a member that is a sequence of struct, the definition of the struct also needs to be included. The operation codes need to include the size of the struct and two addresses that specify where the operation codes of for the structure start and where they end. The, so called, jsr address specifies the offset from the start of the current operand to the start of the operation codes for the structure. The, so called, jmp address specifies the offset from the start of the current operand to the operation codes for the following element. Both addresses are 16 bits and stored together in one 32 unsigned long, such that the lower order 16 bits contain the jsr address and the higher order the jmp address. The operation codes describing the struct are terminated with a return operation (`DDS_OP_RTS`). The case of a member is a sequence of sequence of a certain type, is handled in the same way, where the definition of the sequences is included at the place of the struct. ### Example of sequence of struct Given the IDL struct definitions: ```C struct coord_t{ long x, y; unsigned long z; }; struct M { sequence coords; }; ``` will need the following operation codes: ```C DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (M, coords), sizeof (coord_t), (11u << 16u) + 4u, DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (coord_t, x), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (coord_t, y), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (coord_t, z), DDS_OP_RTS, DDS_OP_RTS, ``` In expression `(11u << 16u) + 4u` in the codes, the `11u` represents the jmp address and the `4u` the jsr address. Note that there are two `DDS_OP_RTS`. The last one is to indicate the end of the IDL struct `M`. The first indicates the end of the IDL stuct `coord_t`, which is used in the sequence. ## Union The operation code of a union is followed by a number specifying the number of cases. This is followed by a combination of jsr and jmp addresses. The jsr address specifies the start of the cases. A case consists of a JEQ operation with a type and an optional jump address. When a case exists of a structure, the jump address specifies the offset (from the start of the current case) of the struct definition (which is terminated with a return operation). ### Example of a union with a struct Given the IDL definitions: ```C struct coord_t{ long x, y; unsigned long z; }; union u switch (short) { case 0: char ch; case 1: coord_t coord; }; struct s{ u u_val; }; ``` will need the following operation codes: ```C DDS_OP_ADR | DDS_OP_TYPE_UNI | DDS_OP_SUBTYPE_2BY, offsetof (s, u_val._d), 2u, (17u << 16) + 4u, DDS_OP_JEQ | DDS_OP_TYPE_1BY | 0, 0, offsetof (s, u_val._u.ch), DDS_OP_JEQ | DDS_OP_TYPE_STU | 3, 1, offsetof (s, u_val._u.coord), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (coord_t, x), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (coord_t, y), DDS_OP_ADR | DDS_OP_TYPE_4BY, offsetof (coord_t, z), DDS_OP_RTS, DDS_OP_RTS, ``` In thus `u_val` stands for C-struct that is used for defining the IDL-union, where `u_val._d` represents the switch parameter and the `u_val._u` the union. In this `2u` stands for the number of cases. For the union `3` represents the jmp address to the operation code for the `coord_t` struct. ## Recursive types The current implementation does not support recursive types. With a recursive type it is not possible to follow the above procedure because it will lead to an infinite sequence of operation codes. The operation also contain a jump subroutine operation, called JSR, that has a 16 bit signed integer value as an offset to the location where the code starts. It is thus possible to execute operation codes that have been defined before. There are two methods for deciding when to use a jump subroutine operation: 1. Whenever a recursion is detected. 2. Whenever a description of a struct already has been generated. The second method could lead to less operations, where the first method could lead to slightly efficient execution. In practice, this probably won't make much difference. The second method is slightly easier to implement: simple maintain a map of structures to offsets (of the start of a struct description from the start of the sequence). ### Example Give the IDL defintion: ```C struct x { char ch; sequence xs; } ``` The following operation codes can be used: ```C DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (x, ch), DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (x, xs), sizeof (coord_t), (7u << 16u) + 4u, DDS_OP_JSR, -6, DDS_OP_RTS, DDS_OP_RTS, ``` Here the `-6` specifies that operation codes for the structure of the sequence, start 6 positions before the `DDS_OP_JSR` operation. The first `DDS_OP_RTS` indicates the end of the sequence type. # Implementation During the generation of operation codes, the tree needs to be traversed (at least) twice, because the values for the various jmp addresses need to be calculated.