Ptrans (short for transformations) allow users to specify both a physical and a logical representation for data, both as Pads types. Users supply a pair of functions that map between the physical and logical representations. The physical type is used to parse the data, which is then transformed according to the supplied transformation function. The logical type is used in tools, such as accumulators, Xml convertion, etc. The write2buf and write2io functions first call the reverse translations to map the logical representation to the physical representation before printing the data. This mechanism has been designed to give users some control over the logical representation of their data and to make it easier to add new base types.
p_trans_spec | ::= | expression [p_actuals] |
p_trans_maskmap | ::= | Pmaskmap expression ; |
trans_ty | ::= | Ptrans identifier [p_formals] { |
p_trans_spec : p_ty <=> p_ty : p_trans_spec ; | ||
[p_trans_maskmap] } |
We explain the meaning of this syntax in the remainder of this chapter. All non-terminals not defined in this grammar fragment were defined previously, as follows. Expressions (expression) are any C-expression, Pads types (p_ty), parameter lists (p_formals), and lists of actual arguments (p_actuals) in Section 3.6.
The following Ptrans declaration defines a type of 32-bit integers represented on disk as ASCII strings of length size.
Ptrans hexint32(:Puint32 size:){
toInt32: Pstring_FW(:size:) <=> Puint32: toHexString(:pads, size :);
};
In this case, the type Pstring_FW(:8:) denotes the physical type while Puint32 denotes the logical type. The function toInt32 converts the parsed string and the corresponding parse descriptor into a 32-bit integer and parse descriptor, while the function toHexString performs the reverse translation. The notation toHexString(:pads,size:) allows the user to pass additional arguments to the translation function. The parameter pads is a special variable in scope within the body of the Ptrans expression. It is bound to the Pads handle active when operations related to the Ptrans are invoked. Figures 11.1and 11.2 show the implementations of the two conversion functions. Note that the function toHexString needs the Pads handle to pass as an argument to the Pstring_cstr_copy function that copies the C string str into the desired Pstring.
void toInt32(Pstring *src, Pbase_pd *src_pd, Puint32 *dest, Pbase_pd *dest_pd){
size_t i;
Puint32 digit;
*dest = 0;
*dest_pd = *src_pd; /* set destination parse descriptor from source */
for(i=0; i<src->len; i++){
digit = hexCharToInt(src->str[i]);
if (digit <0) {
dest_pd->nerr++;
dest_pd->errCode = P_TRANSFORM_FAILED;
break;
} else {
*dest = *dest * 16 + digit;
// should check for overflow here
}
}
};
void toHexString(P_t *p, Puint32 size, Puint32 *src, Pbase_pd *src_pd,
Pstring *dest, Pbase_pd *dest_pd){
Puint32 local = *src;
int i;
char str[256];
Puint32 msize = (size < 256) ? size : 255;
*dest_pd = *src_pd;
if (msize < size) {
// Error: hex representation too large
dest_pd->nerr++;
dest_pd->errCode = P_TRANSFORM_FAILED;
}
for (i=0; i<msize + 1; i++){
str[i] = 0;
}
for (i = msize-1; i>=0; i--){
char result = intToHexChar(local % 16);
if (’z’ == result) {
// Error: hex string contained a non-hex digit
dest_pd->nerr++;
dest_pd->errCode = P_TRANSFORM_FAILED;
break;
}
str[i] = result;
local = local / 16;
}
if (local != 0) {
// Error: number too big to be represented in given size.
dest_pd->nerr++;
dest_pd->errCode = P_TRANSFORM_FAILED;
};
if (P_OK != Pstring_cstr_copy(p, dest, str, size)) {
// Error: copy into Pstring failed
dest_pd->nerr++;
dest_pd->errCode = P_TRANSFORM_FAILED;
};
}
If the masks of the logical and physical types differ, or if the desired conversion from the logical to the physical mask is not the identity function, the Ptrans declaration must specify a function to convert the logical mask to the physical mask. For example, the Ptrans hexint32withMask in Figure 11.3 uses the function cnvMask to map the mask for the logical type to one for the physical type. In the example, the mapping is simply the identify function, but the user is free to supply an arbitrary mapping function as long as it has the necessary type signature. The generated library calls this function to convert the logical mask to the physical mask just before invoking the parser for the physical representation.
void cnvMask(Pbase_m *phy, Pbase_m *log){
*phy = *log;
}
Ptrans hexint32withMask(:Puint32 size:){
toInt32: Pstring_FW(:size:) <=> Puint32: toHexString(:pads, size :);
Pmaskmap cnvMask;
};
Within the various expression contexts of Ptrans declarations, the special variable pads is in scope.
Variable | Type | Contexts | Binding |
pads | P_t | all | Active Pads handle. |
The in-memory representation of a Ptrans is the same as the representation of logical type.
The mask of a Ptrans is the same as the mask of the logical type.
The parse descriptor for a Ptrans is the same as the parse descriptor for the logical type.
The operations generated by the Pads compiler for a Ptrans are those described in Chapter 3.
The error codes for Ptrans are:
Code | Meaning |
P_NO_ERR | Indicates no error occurred |
P_TRANSFORM_FAILED | Indicates a failure during transformation. |
Accumulator functions for Ptrans are just as the accumulator functions for the logical type.
Histogram functions for Ptrans are just as the histogram functions for the logical type.
Clustering functions for Ptrans are just as the clustering functions for the logical type.