The twentifier header translator

twentifier is a tool that translates C++-like headers containing class declarations into MMXX-enabled headers that declare MMXX-enabled classes. It is a simple translator: it can only handle a small subset of the C++ grammar, and specifically disallows constructs that cannot be converted into MMXX declarations (though it isn't smart enough to disallow all such constructs.) Using it is fully optional; its intent is merely to make it easier to create MMXX-enabled headers, particularly for the beginning user.

For advanced users and applications, it can still be useful in that many people find C++-style declarations easier to read than their MMXX counterparts. For those situations where twentifier is unable to cope with a particular situation or construct, escape sequences can be used to force it to produce the correct output: the #quote { ... #} construct bypasses the translation and places the enclosed text directly into the output MMXX header, and the %inhibit { ... } construct forces twentifier to witness the enclosed declarations (usually typedefs and simplified forward declarations whose true declarations are present in other headers) without sending them to output.

Here are some of the major restrictions on what may be in a twentifier input file. Many of these restrictions reflect what is and isn't expressible in MMXX's header grammar, however occasionally twentifier will allow constructs that are indeed not allowed or reccomendable. Please note that this list is not exhaustive:

When twentifier encounters certain constructs that cannot yet be expressed in MMXX's header grammar, it will place them in the output class' private declarations section, guarded so that they're only available to the class' implementation. This is presently the case with typedefs and overloaded operators. Once the MMXX grammar is extended to allow these constructs, twentifier will also be revised accordingly.

Because of all these restrictions, the best way to use twentifier is to either refrain from using it for sophisticated classes, or to closely monitor its output to make sure the it's correct, while availing oneself of the #quote and %inhibit constructs to fix any problems along the way.

Here are the special twentifier directives:

#quote { ... #}
This directive sends the enclosed text (which may span multiple lines) directly to output. twentifier ensures that the text is appropriately surrounded by preprocessor guards and, if the directive occurs inside a class declaration, that its default access specifier is private: and that it's only available to the module where the class is implemented.
%inhibit { ... }
This directive interprets the enclosed text for its side effects (e.g. typedefs and class/enum/union/struct/template class forward declarations) but does not send it to output.
%optional
This can be prefixed as a qualifier to member methods to designate them as optional to the runtime linker for the purposes of revision management (e.g. by omitting the Req method attribute.) For example, %optional virtual void foo(int);
%header header_name ;
This directive specifies the name of the current header minus any .h/.mxh suffix. Note that the name should not be quoted. At present, this is only used for the purpose of naming the preprocessor guard macro. Note that this directive should really be used - twentifier will not default to the name of its input file, but rather to a randomly-generated identifier.
%include header_name ;
This directive generates appropriate preprocessor directives to #include the named header as part of the output header's preamble (it does not actually process the contents of the file.) Note that the name should not be quoted with either <...> or "..." and that an .h suffix is implicitly added so that none should be given. twentifier assumes that the header in question is a MMXX-enabled header - as such it will wrap the #include directive itself with preprocessor guards that follow the MMXX guard macro naming convention (if it's another kind of header, the guards won't matter.) Also note that all the %include directives are brought up to the beginning of the output file. Since twentifier always uses "...", this directive is not suitable for system headers. The latter may still be included by using #quote { #include <...> #} at the beginning of the file.
It's important to remember that the MMXX tools assume that all MMXX-enabled headers are freestanding, meaning that they must include any header whose declarations they rely on, with the exception of the prefix file. The mmxxsupgen tool relies heavily on this assumption.

twentifier's input files use the .mxh suffix by convention, and its output files default to the classic .h suffix.

Here are example input and output files:


Input:

%header MyHeader;
		
template <class Z> class Vector;		
		
%include BingoHeader;		
		
%inhibit {		
	typedef Vector<int> IntVector;		
	class Bingo;		
}		
		
#quote {		
		
typedef char *vodzilla;		
		
#}		
		
class MyClass : public Bingo {		
public:		
	struct stuff {		
		int elem1;		
		void *elem2;		
		char elem3[256];		
	};		
		
	enum famous_mafiosi {		
		oprah,		
		cher,		
		bill = 1000,		
		hillary,		
		gates = 0x23842UL,		
		ballmer,		
		herman = pee_wee		
	};		
		
	inline MyClass(int, double);		
	virtual ~MyClass();		
	static void Compute(const char *foo, Vector<float> &bar, double &aardvark) throw();		
		
/* we'll get a warning here, and this will be made private		
   (temporarily, till the next MMXX release) */		
	inline MyClass & operator = (const MyClass &);		
		
protected:		
	virtual int hello() const;		
	const int *&adriatic, mediterranean[2], *baltic;		
	virtual int pure_indeed() = 0;		
private:		
	char *mycstring;		
	IntVector myintvector;		
};		
		

Output:

#if !defined(__MYHEADER__) || defined(_MMXX_BREWING_)
#define __MYHEADER__ 1		
		
#ifndef _MMXX_BREWING_		
		
#ifndef __BINGOHEADER__		
#include "BingoHeader.h"		
#endif /* #ifndef __BINGOHEADER__ */		
		
  template <class Z > class Vector;		
  		
/* =-= begin quote: =-= */ 		
		
typedef char *vodzilla;		
/* =-= end quote =-= */		
		
#include "mmxxapi.h"		
		
#endif /* #ifndef _MMXX_BREWING_ */		
		
MMXX_CLASS_1_0(MyClass,public,Bingo)		
		
MMXX_STRUCT_START(MyClass,stuff)		
MMXX_STRUCT_FIELD(MyClass,stuff,            int,elem1)		
MMXX_STRUCT_FIELD(MyClass,stuff,            void*,elem2)		
MMXX_STRUCT_ARRAY(MyClass,stuff,            char,elem3,256)		
MMXX_STRUCT_END(MyClass,stuff)		
		
MMXX_ENUM_START(MyClass,famous_mafiosi)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     oprah,0)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     cher,1)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     bill,1000)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     hillary,1001)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     gates,0x23842UL)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     ballmer,0x23842UL+1)		
MMXX_ENUM_TUPLE(MyClass,famous_mafiosi,     herman,pee_wee)		
MMXX_ENUM_END(MyClass,famous_mafiosi)		
		
// Warning: dropping 'inline' from MyClass::MyClass		
MMXX_CONS_2(    Pub,    MyClass,Req,		
                        1,(Bingo),          int,p33892634,		
                                            double,pa86fc21c)		
  // public: inline MyClass(int, double);		
		
// Warning: public virtual destructor is always implicitly declared		
  // public: virtual ~MyClass();		
		
MMXX_STATIC_3N( Pub,    MyClass,Req,		
                        Compute,            const char*,foo,		
                                            Vector< float >&,bar,		
                                            double&,aardvark)		
  // public: static void Compute(const char* foo, Vector< float >& bar, double& aardvark) throw();		
		
// Warning: making typedef/operator temporarily private		
MMXX_METHOD_0RC(ProtV,  MyClass,Req,		
        int,            hello               )		
  // protected: virtual int hello()const ;		
		
// Warning: making MyClass::adriatic private		
// Warning: making MyClass::mediterranean private		
// Warning: making MyClass::baltic private		
MMXX_METHOD_0R( ProtPV, MyClass,Req,		
        int,            pure_indeed         )		
  // protected: virtual int pure_indeed() = 0;		
		
#if !defined(_MMXX_BREWING_) && defined(_MMXX_SHADOW_MyClass) && _MMXX_SHADOW_MyClass==0		
private:		
    inline MyClass& operator = (const MyClass&);		
/* we'll get a warning here, and this will be made private		
   (temporarily, till the next MMXX release) */		
    const int*& adriatic;		
    const int mediterranean[2];		
    const int* baltic;		
    char* mycstring;		
    IntVector myintvector;		
#endif /* #if !defined(_MMXX_BREWING_) && defined(_MMXX_SHADOW_MyClass) && _MMXX_SHADOW_MyClass==0 */		
		
MMXX_CLASS_END(MyClass)		
		
		
#endif /* #if !defined(__MYHEADER__) || defined(_MMXX_BREWING_) */