This is a package for marshaling written jointly by Gene Cooperman
and Ning Ke. The software is still in progress. This should be thought
of only as an interim report on the expected functionality of the
package.
This version of the package is for C++. Other versions will be
provided for other languges.
============================
GRAMMAR:
In the preprocessor language, one would see:
%{
INCLUDE_MACROS [anything you want to include or defined]
%}
marshaling class MTYPE (TYPE OBJ) {
TYPE1 FIELD1; { GETSPEC } { SETSPEC } { SIZESPEC }
TYPE2 FIELD2; { GETSPEC } { SETSPEC } { SIZESPEC }
...
}
EXAMPLE:
class Foo {
int a;
int b;
char *c;
}
marshaling class MarshaledFoo (Foo x) {
int a; { $$ = x.a; } { x.a = $$; } { sizeof(int) }
int b; { $$ = x.b; } { x.b = $$; } { sizeof(int) }
char *c;
{ $$ = strcpy(malloc(strlen(x.a)+1), x.a); }
{ x.b = strcpy(malloc(strlen(x.b)+1), $$); }
{ strlen(x.b) }
}
Explanations:
1) class and marshal are reserved keywords.
2) MTYPE is the name of the class that contains the marshaled object.
3) TYPE is the original type (or class or struct).
By convention, if TYPE is Foo, then MTYPE is MarshaledFoo
4) OBJ is the parameter name (an object of the type). It must be a pointer
type at the moment. [ This restriction will be lifted in the future? ]
5) Each line inside the `class MTYPE' command contains a specification for
one field of the struct or class given by TYPE.
6) Whitespace (, , or ) serves as delimiters.
is equivalent to , and are for human readability.
7) Within one fieldspec:
i) Everything before the first ";" is the declaration of a field.
ii) The statements contained in the first {} should specify exactly
how to convert that field into a stream of bytes and copied it
to the memory space pointed to by msh_cursor. msh_cursor is an
instance variable contained in MarshaledFoo that always points to
where the next field should be marshaled. Additional braces
(`{' and `}') are permitted inside {} only if they are balanced.
[ For the moment, nested braces are not allowed,
but this constraint will be removed in the future. ]
iii) The statements contained in the second {} should specify how to
convert the stream of bytes that we created in ii) back into
the field's data type. Braces inside {} must be balanced.
[ For the moment, nested braces are not allowed,
but this constraint will be removed in the future. ]
iv) The statements contained in the third {} (sizespec) should tell
the size (in bytes) of the converted field.
8) getspec and setspec are C++ statements. sizespec is a C++
expression. In getspec and setspec, $$ is a variable of type (char *)
pointing to the beginning of the location where that field is to be marshaled.
9) If the field is a common type (e.g. int, double) then the getspec,
setspec and sizespec can be omitted. The marshalling of
these fields will be carried out according to a standard definition
built into the marshalling package. [ The list of built-in types
is .... ]
10) A future version will allow marshaling of multiple objects (Foo1, Foo2,
etc.) into a single marshaled class
11) Invocation [ THIS WILL CHANGE IN THE FUTURE. ]
MarshaledFoo *mf = new MarshaledFoo();
mf->marshal(); // This may be done by the creator function in the future.
// char *mf->msh_cursor points to marshaled buffer and int mf->msh_size is
// the buffer length. (Maybe mf->getBuf, mf->getLen() more conventional.)
...
Foo *f = new Foo();
mf->unmarshal(f);
====================================
INSTALLATION AND USAGE:
Within the directory front-end/, (After typing "make") there should be
an excutable called "front-end". This is the "compiler" that converts your
marshaling language program into C++ source code. To run the front-end, type
./front-end <
After this is done, two files, one called MarshaledFoo.h, another called
MarshaledFoo.cpp are generated. These two files defines a class "MarshaledFoo"
that is used to do all the marshaling.
To marshal a struct(or class), first you need to write the marshaling specs,
as described above. Then use front-end to generate the two files. (Note any
syntax or semantics errors within your marshaling spec is not checked by
the marshaling language "compiler" (front-end). Instead, these errors will be
passed on to the two C++ files and will create problems when you compile
or run your code). Then use the constructor to construct a MarshaledFoo object
and just call _name_of_obj.marshal(). The object will be marshaled and stored
in the MarshaledFoo's instance variable called msh_buffer.
To unmarshal, one can construct a MarshaledFoo from a char* buffer and call
_name_of_marshaledObj.unmarshal(&an_obj). The marshaled object is restored
and put into an_obj.
Looking at the examples provided will make this clearer.