=============================================================================== MMXX Header Macro Guide: =============================================================================== MMXX Header File Structure -------------------------- The following structure is merely indicative. The most peculiar requirements for MMXX-compatible header files are that: 1. They must be conditionalized on the value of the _MMXX_BREWING_ macro. Whenever _MMXX_BREWING_ is set to 1, they must: a. Be repeatedly includeable b. Not expose any content but a correctly structured set of MMXX_* macro expansions. 2. The contents of class declarations not enveloped in macros (in particular, private method and private instance variable declarations) should be conditionalized on whether the class in question is being compiled as a shadow or as a real class. The most sensible way of doing this is to rely on the same flag macros that MMXX uses, namely _MMXX_SHADOW_. The catch is that the flag macros themselves must be already available by the time the header is included. This is generally done by using one or more prefix files (prefixed to all compilation within the unit, such as by using gcc's -include option, or by MMXX's "artificial" include file, available by setting the _MMXX_prefix_ macro by a compiler command-line switch.) This is necessary to eliminate potential compiler and linker errors, to drop the space overhead for instance variables in shadow classes, and most importantly to avoid compile-time and runtime errors related to the presence of member objects. Example: /* "foo.h" BEFORE CONVERSION TO MMXX: -------------------------------------- */ #ifndef __FOO__ #define __FOO__ 1 #ifndef __BAR__ /* header dependency */ #include "bar.h" #endif class foo : public bar { public: foo(int num); virtual ~foo(); void SetNumber(int num); int GetNumber() const; virtual void Recalculate(); static const char * GetText(); virtual int GetCustomCode() = 0; /* This is a pure virtual method, which in C++ makes the class abstract. In MMXX, pure virtual methods appear to be regular virtual methods, because base classes can never be abstract as far as the compiler is concerned: since they can be subclassed in modules, the host must still be able to instantiate the base class. However, the methods are still "pure virtual" in that the runtime linker will refuse to instantiate a derived class if any required pure virtual methods in any of its base classes are not overridden. Note that pure virtual methods are very useful in MMXX because a design based on pure virtual methods can be faster than one based on regular virtual methods. Note that if a pure virtual method is not overridden in a derived class and it is NOT marked as required, instantiation will be possible. Calling the method will result in a no-op. If the method returns a result, 0 will be returned. Because of this, all result types returned by pure virtual methods must be castable from "0". The GetCustomCode() above satisfies this requirement since it returns "int". */ protected: virtual void PerformAction(); private: /* in MMXX, all member variables are private - classes with protected or public member variables need reworking beforehand. Class "foo" in this example was already conforming. */ int number; void MyPrivateMethod(); static const char * text; }; #endif /* "foo.h" AFTER CONVERSION TO MMXX: --------------------------------------- */ #if !defined(__FOO__) || defined(_MMXX_BREWING_) /* make sure it can be included multiple times if _MMXX_BREWING_ is 1 */ #define __FOO__ 1 #ifndef _MMXX_BREWING_ /* make sure we don't output anything but MMXX_* macros, or recurse to any other header, if we're brewing */ #ifndef __BAR__ /* header dependency */ #include "bar.h" #endif /* #ifndef __BAR__ */ #include "mmxxapi.h" /* get the MMXX macro definitions that generate C++ declarations */ #endif /* #ifndef _MMXX_BREWING_ */ MMXX_CLASS_1_0(foo,public,bar) /* a base class must itself be declared with MMXX if it's public or protected, here we're assuming that bar.h is an MMXX header as well */ MMXX_CONS_1( Pub, foo,Req, 1,(bar), int,num) /* public: foo(int num); Note that constructors take the number and list of nonprivate superclasses in lieu of the method name, or 1,(bar) in this case */ /* public: virtual ~foo(); a virtual destructor is always automatically declared by MMXX */ MMXX_METHOD_1( Pub, foo,Req, SetNumber, int,num) /* public: void SetNumber(int number); */ MMXX_METHOD_0RC(Pub, foo,Req,int, GetNumber ) /* public: int GetNumber() const; */ MMXX_METHOD_0( PubV, foo,Req, Recalculate ) /* public: virtual void Recalculate(); it's virtual, so it must be implemented as void foo::_I_Recalculate() */ MMXX_STATIC_0R( Pub, foo,Req,const char*,GetText ) /* public: static const char *GetText(); */ MMXX_METHOD_0R( PubPV, foo,Req,int, GetCustomCode ) /* public: virtual int GetCustomCode() = 0; (note: pure virtual requires no _I_ prefix for the implementation) */ MMXX_METHOD_0( ProtV, foo,Req, PerformAction ) /* protected: virtual void PerformAction(); it's virtual, it must be implemented as void foo::_I_PerformAction() */ #if !defined(_MMXX_BREWING_) && defined(_MMXX_SHADOW_foo) && _MMXX_SHADOW_foo==0 /* make sure we don't output any private declarations if we're brewing or if this is a shadow class */ private: int number; void MyPrivateMethod(); static const char * text; #endif /* #if !defined(_MMXX_BREWING_) && defined(_MMXX_SHADOW_foo) && _MMXX_SHADOW_foo==0 */ MMXX_CLASS_END(foo) #endif /* #if !defined(__FOO__) || defined(_MMXX_BREWING_) */ Header Grammar v.1.0: --------------------- In the following, a literal sequence of characters is enclosed in double quotes, e.g. "identifier" (if the literal sequence contains double quotes, \ is used to escape them.) If two tokens should be concatenated into one, they are presented with no intervening whitespace in the grammar, (e.g. '_MMXX_SHADOW_' becomes _MMXX_SHADOW_foo in the case of class "foo".) NL stands for the newline token. A token marked with a * suffix can be repeated zero or more times (though the exact number of times it must be repeated might be specified by its context.) If a line is not marked with a | prefix, it represents a continuation of the rule on the previous line, whereas if it is marked with a | prefix it represents an alternative to the previous rule (the choice among alternatives might be specified by the context of the token.) A token surrounded by square brackets is optional (its presence might also be specified by its context.) /* the following are simply indicative: */ ::= ::= "#if !defined("") || defined(_MMXX_BREWING_)" NL "#define "" 1" NL ::= "#ifndef _MMXX_BREWING_" NL "#include \"mmxxapi.h\"" NL "#endif" NL ::= header file preparation, including all needed subinclusions of other headers and any other declarations not otherwise supposed to be enveloped in MMXX macros. ::= the convention is to translate the header file name into a macro name by replacing all punctuation marks into underscores, dropping the .h suffix, converting to upper case, then to prefix the result by two underscores and to suffix it with two more, e.g. "Foo.h" becomes __FOO__. At present this is only a convention, but it might later become a requirement. ::= * ::= NL "#endif" NL ::= "#if !defined(_MMXX_BREWING_) && defined(_MMXX_SHADOW_"") && _MMXX_SHADOW_""==0" NL /* redundant s */ NL "#endif" NL /* these are strictly required rather than merely indicative: */ ::= | ::= * ::= | ::= | | | | | ::= /* Class Declaration */ ::= "MMXX_CLASS_""_" "(" * /* quantity given by */ * /* quantity given by */ ")" ::= "0" .. "5" ::= "0" .. "5" ::= "," "," ::= "public" | "protected" ::= "," ::= ::= ::= "MMXX_CLASS_END" "(" [ "," ] /* iff is "_CCT" */ [ "," ] /* iff is "_AS" */ ")" ::= /* empty iff copy constructor not provided */ | "_CCT" /* iff copy constructor provided */ ::= /* empty iff copy assignment oper not provided */ | "_AS" /* iff copy assignment operator provided */ ::= /* empty iff class is not an exception class */ | "_EXC" /* iff class is an exception class */ /* (must publicly derive from MMXXException) */ ::= "public" | "protected" | "private" /* Method Declaration */ ::= "(" "," /* redundant, must match name of class being declared */ "," [ "," ] /* iff is "R" */ "," * /* quantity given by */ ")" ::= "MMXX_METHOD_" | "MMXX_OPER_" ::= "0" .. "10" ::= /* empty iff method returns void */ | "R" /* "R" iff method returns a result */ ::= /* empty iff method is not "const" */ | "C" /* "C" iff method is "const" */ ::= /* empty iff method can throw exceptions */ | "N" /* "N" iff method can't throw exceptions */ ::= "Pub" /* public non-virtual method */ | "Prot" /* protected non-virtual method */ | "PubV" /* public virtual method */ | "ProtV" /* protected virtual method */ | "PubPV" /* public pure virtual method */ | "ProtPV" /* protected pure virtual method */ ::= "None" /* no flags */ | "Req" /* iff method/ctor/static is required */ ::= /* iff a regular method */ | /* iff an operator */ ::= ::= "eq" | "ne" | "add" | "sub" | "mult" | "div" | "l" | "g" | "le" | "ge" | "and" | "or" | "not" | "bit_and" | "bit_or" | "bit_not" | "xor" | "ls" | "rs" | "mod" | "add_a" | "sub_a" | "mult_a" | "div_a" | "bit_and_a" | "bit_or_a" | "xor_a" | "ls_a" | "rs_a" | "mod_a" | "subscript" | "function" | "pointer" | "member" | "inc" | "dec" | "comma" | "nw" | "del" | "nw_arr" | "del_arr" | "as" ::= ::= "," "," ::= ::= restricted C++ type (see notes on parameter types for what's allowed) ::= "Pub" /* iff public */ | "Prot" /* iff protected */ /* Constructor Declaration */ ::= "MMXX_CONS_" "(" "," /* redundant, must match name of class being declared */ "," "," /* redundant from MMXX_CLASS_*() declaration, must match quantity of non-private superclasses given there */ "," "(" * /* quantity given by */ ")" * /* quantity given by */ ")" ::= "0" .. "10" ::= /* redundant, must match name of class being declared */ ::= [ "," ] /* iff this is not the first non-private superclass */ /* redundant from MMXX_CLASS_*() declaration, must match non-private superclasses given there */ ::= "," "," /* Static Method Declaration */ ::= "MMXX_STATIC_" "(" "," /* redundant, must match name of class being declared */ "," [ "," ] /* iff is "R" */ "," * /* quantity given by */ ")" /* Enumeration Declaration */ ::= * ::= "MMXX_ENUM_START" "(" /* redundant, must match name of class being declared */ "," "," "," "," ")" ::= /* name of enumeration, may not be empty */ ::= "0" /* iff linker should allow numbers to differ */ | "1" /* iff linker should require numbers to match */ ::= "0" /* iff linker should allow peer not to contain all tuples */ | "1" /* iff linker should require peer to contain all tuples */ ::= "0" /* iff linker should allow shadow not to contain all tuples */ | "1" /* iff linker should require shadow to contain all tuples */ ::= "MMXX_ENUM_TUPLE" "(" /* redundant, must match name of class being declared */ "," /* redundant, must match name of enumeration being declared */ "," "," ")" ::= ::= /* valid C++ enumeration expression */ /* (use literals if at all possible in MMXX 1.0) */ /* Member Struct Declaration */ ::= * ::= "MMXX_STRUCT_START" "(" /* redundant, must match name of class being declared */ "," ")" ::= ::= "MMXX_STRUCT_FIELD" "(" /* redundant, must match name of class being declared */ "," /* redundant, must match name of structure being declared */ "," "," ")" ::= /* Static Initializer Declaration */ ::= "MMXX_STATICINIT" "(" /* redundant, must match name of class being declared */ "," "," ")" ::= /* name of (static) class method to execute upon static */ /* initialization, automatically declared with signature */ /* void (*)(int). These staticinits execute in class derivation order as MMXX units are linked in. */ ::= "REAL" /* iff to execute for real classes only */ | "SHADOW" /* iff to execute for shadow classes only */ | "BOTH" /* iff to execute for both real and shadow */