Reputation: 340
I am trying to do something like:
custommacro x;
which would expand into:
declareSomething; int x; declareOtherthing;
Is this even possible?
I already tricked it once with operator=
to behave like that, but it can't be done with declarations.
Upvotes: 0
Views: 1896
Reputation: 376
You could use for-loop and GnuC statement expression extension.
#define MY_MACRO\
FOR_MACRO(_uniq##__COUNTER__##name,{/*declareSomething*/ },{ /* declareOtherthing */ }) int
#define FOR_MACRO(NAME,FST_BLOCK,SND_BLOCK)\
for(int NAME = ({FST_BLOCK ;0;}); NAME<1 ; NAME++,(SND_BLOCK))
It's "practically hygienic", though this means that whatever you do inside those code blocks wont escape the for-loop scope.
Upvotes: 1
Reputation: 13370
You can elide the parentheses as long as you are willing to accept two additions:
e.g. thusly:
#define LPAREN (
#define echo ECHO_MACRO LPAREN
#define done )
#define ECHO_MACRO(X) std::cout << (X) << "\n"
#define DSL(X) X
...
DSL(
echo "Look ma, no brains!" done;
)
...
Reasons for this:
done
macro, that will expand to a form containinf the necessary close parenecho ... done
form didn't look like a macro invocation to the preprocessor, it wasn't marked for expansion when the preprocessor entered it, and whether we put parens in or not is irrelevant. Just using echo ... done
will therefore dump an ECHO_MACRO call in the textDSL
) will cause the call to ECHO_MACRO to be expanded on this rescan pass (DSL
doesn't do anything with the result: it exists just to force the rescan)(
in the expansion of echo
behind the simple macro LPAREN
, because otherwise the unmatched parenthesis in the macro body will confuse the preprocessorIf you wanted to create an entire domain-specific language for such commands, you could also reduce the number of done
commands by making the core commands even more unwieldy:
#define LPAREN (
#define begin NO_OP LPAREN 0
#define done );
#define echo ); ECHO_MACRO LPAREN
#define write ); WRITE_MACRO LPAREN
#define add ); ADD_MACRO LPAREN
#define sub ); SUB_MACRO LPAREN
#define NO_OP(X)
#define ECHO_MACRO(X) std::cout << (X) << "\n"
#define WRITE_MACRO(X) std::cout << (X)
#define ADD_MACRO(D, L, R) (D) = (L) + (R)
#define SUB_MACRO(D, L, R) (D) = (L) - (R)
#define DSL(X) DSL_2 X
#define DSL_2(X) X
int main(void) {
int a, b;
DSL((
begin
add a, 42, 47
sub b, 64, 50
write "a is: "
echo a
write "b is: "
echo b
done
))
return 0;
}
In this form, each command is pre-designed to close the preceding command, so that only the last one needs a done
; you need a begin
line so that there's an open command for the first real operation to close, otherwise the parens will mismatch.
Messing about like this is much easier in C than in C++, as C's preprocessor is more powerful (it supports __VA_ARGS__
which are pretty much essential for complicated macro metaprogramming).
Oh yeah, and one other thing -
...please never do this in real code.
Upvotes: 6
Reputation: 96790
I understand what you're trying to do and it simply can't be done. A macro is only text replacement, it has no knowledge of what comes after it, so trying to do custommacro x
will expand to whatever custommacro
is, a space, and then x
, which just won't work semantically.
Also, about your echo
hack: this is actually very simple with the use of operators in C++:
#include <iostream>
#define echo std::cout <<
int main()
{
echo "Hello World!";
}
But you really shouldn't be writing code like this (that is, using macros and a psuedo-echo hack). You should write code that conforms to the syntax of the language and the semantics of what you're trying to do. If you want to write to standard output use std::cout
. Moreover, if you want to use echo
, make a function called echo
that invokes std::cout
internally, but don't hack the features of the language to create your own.
Upvotes: 2