Your first problem is that
#define end_methods } ## ;
is a syntax error (if the macro is expanded), because the result of the token paste is not a single valid token. You should have gotten error messages like
error: pasting "}" and ";" does not give a valid preprocessing token
Your second problem is that token pastes are executed before nested macro expansion. That means your macro
#define decl_methods struct class ## Methods {
is effectively the same as if you had written
#define decl_methods struct classMethods {
To get it to do what you want, class
must be a formal parameter to a function-like macro:
#define decl_class(class) struct class {
#define end_class(class) }; typedef struct class class;
#define decl_methods(class) struct class ## Methods {
#define end_methods(class) };
#define method(class, returnType, methodName, ...) \
returnType (*methodName)(struct class *self, __VA_ARGS__);
and then
decl_class(Double)
double value;
decl_methods(Double)
method(Double, double, get_value);
end_methods(Double)
end_class(Double)
I suppose you could avoid having to repeat the name of the class in every macro invocation by having an additional set of macros that stick the class
pseudo-argument in there, but (for reasons too tedious to get into here; read the "Argument Prescan" section of the GNU CPP manual very carefully) you will need two layers of nested expansion to get the effect you want:
#define decl_class__(class_) struct class_ {
#define decl_class_(class_) decl_class__(class_)
#define decl_class decl_class_(class)
#define decl_methods__(class_) struct class_ ## Methods {
#define decl_methods_(class_) decl_methods__(class_)
#define decl_methods decl_methods_(class)
/* etc */
This is technically only required when the innermost macro needs to use ##
(or #
) but if you're seriously going to use these macros in a real program, you should do it uniformly for all of them otherwise you'll be tearing your hair out six months later.
And after you get past all of that you will discover that your method
macro doesn't work right for zero-argument methods, e.g.
#define class Integer
method(int, getValue)
either throws an error because, in standard C, ...
in a macro parameter list must receive at least one argument, or it expands to a syntactically invalid declaration,
int (*getValue)(struct Integer *self, );
The only way to work around this one is to use a GNU extension:
#define method__(class_, returnType, methodName, ...) \
returnType (*methodName)(struct class_ *self, ##__VA_ARGS__);
In GNU extended C, ##
in between ,
and __VA_ARGS__
has the special effect of causing the comma to be deleted when the ...
received no arguments. (This extension was proposed for standardization about 15 years ago, but the committee wasn't interested.)
At this point I invite you to reconsider the possibility of just using C++ instead.