Devon - 2015-08-13

Hi there,

First off, what a great product. Thanks for all the work you’ve done on this.

I’ve run into an issue parsing a particular style of programming we employ and hope you can offer a suggestion.

In the example header below, we're using macros to inject code snippets at compile time.

The issue I'm having is the token processor does not see a closing bracket (or semi-colon) at the end of the last macro so it attempts to process the first public enum as part of the nameStack created by the macro processing.

E.g:

Evaluating stack ['SCIOBJ_BEGIN_IFC_MAP', '(', 'SCIWizard', ')', 'SCIOBJ_CHAIN_IFC_MAP', '(', 'BASE_CLASS', ')', 'SCIOBJ_END_IFC_MAP', ':', 'typedef', 'enum', '_SomeMode']

Instead of:

Evaluating stack ['SCIOBJ_BEGIN_IFC_MAP', '(', 'SCIWizard', ')', 'SCIOBJ_CHAIN_IFC_MAP', '(', 'BASE_CLASS', ')', 'SCIOBJ_END_IFC_MAP’]

The net result is the _SomeMode enum gets swallowed and doesn’t appear anywhere in the resulting CppHeader class.

Note adding a semi-colon after MACRO_FUNCTION_END below does allow the parser to see the typedef enum, but I am not able to add this semi-colon to all the files that use this programming style.

Is there anything I can do (short of modifying the header files) to get the CppHeaderParser to properly parse these headers?

Thank you,

// devon

Example header file

#define MY_CLASS_H_
#include “macro_header.h"

class MyClass : public MyGenericClass<AnotherClass, MyClass> {
    typedef MyGenericClass<AnotherClass, MyClass> BASE_CLASS;

    MACRO_FUNCTION_BEGIN(AnotherClass)
        MACRO_FUNCTION_MAP(BASE_CLASS)
    MACRO_FUNCTION_END // <— missing ';' creates parsing issue

public:
    typedef enum _SomeMode {
        MODE_ONE,
        MODE_TWO
    } SomeMode;

    enum SomeState {
        STATE_ONE,
        STATE_TWO
    };
};

In the macro_header.h file, we have these macros defined:

#define MACRO_FUNCTION_BEGIN(IfName) public: \
    virtual MyRetPtr<MyObj> queryInterface(const MyStr &sIfID) { \
        typedef IfName __ifNameBaseType; \
        if (sIfID == getIID<IfName>()) \
            return MyRetPtr<MyObj>(static_cast<IfName *>(this));

#define MACRO_FUNCTION_MAP(base) \
        MyRetPtr<MyObj> result = base::queryInterface(sIfID); \
        if (result) \
            return result;

#define MACRO_FUNCTION_END \
        if (sIfID == MYOBJ_INTERFACE) \
            return MyRetPtr<MyObj>(static_cast<MyObj *>(static_cast<__ifNameBaseType *>(this))); \
        \
        return NULL; \
    }

So, basically, after pre-processing we end up with:

#define MY_CLASS_H_
#include "macro_header.h"

class MyClass : public MyGenericClass<AnotherClass, MyClass> {
    typedef MyGenericClass<AnotherClass, MyClass> BASE_CLASS;

    virtual MyRetPtr<MyObj> queryInterface(const MyStr &sIfID) {
        typedef IfName __ifNameBaseType;
        if (sIfID == getIID<IfName>())
            return MyRetPtr<MyObj>(static_cast<IfName *>(this));
        MyRetPtr<MyObj> result = base::queryInterface(sIfID);
        if (result)
           return result;
        if (sIfID == MYOBJ_INTERFACE)
            return MyRetPtr<MyObj>(static_cast<MyObj *>(static_cast<__ifNameBaseType *>(this)));

        return NULL;
    }
public:
    typedef enum _SomeMode {
        MODE_ONE,
        MODE_TWO
    } SomeMode;

    enum SomeState {
        STATE_ONE,
        STATE_TWO
    };
};