I would like to define an expression in C++ with macros and I am having quite a bit of trouble.
The expression is :
MATCH string WITH other_string
where string and other_string do not require " "
For example: MATCH r1 WITH string1 is the result i desire.
The purpose of this macro would be to check if r1 string matches with r2.
(I already have the code for the matching)
UPDATE
I would like to call MATCH hello WITH hi
in my main function
int main(){
MATCH hello WITH hi
}
and call my function from this macro to compare them. **Both hello and hi are unquoted arguments and must be treated as variable names
It is always dubious to use macros to make your code look like a different language. It is probably better to consider using a separate parser for your "meta-language" that generates the C++ code for you.
In this case, since C++ syntax requires some way to indicate the end of a statement (close braces or semi-colon) you are in kind of a jam.
Consider your example:
int main () { MATCH hello WITH hi }
Since hi is the last token before the end of main, there is no chance to fix-up the syntax to match C++ requirements.
You can't do what you want, so you have to do something different
If you really intend to embed this syntax into your C++ code, you need sentinel tokens to allow you to fix-up the syntax. My proposed syntax is:
int main () {
BEGIN_MATCHING
MATCH hello WITH hi
MATCH hello WITH hi
END_MATCHING
};
If this syntax is acceptable, then you can use the following macros.
#define BEGIN_MATCHING ((void)0
#define MATCH ); my_function(
#define WITH ,
#define END_MATCHING );
This will cause the code in the proposed syntax example to expand to:
int main () {
((void)0
); my_function( hello , hi
); my_function( hello , hi
);
}
Live Demo
Simply stringify your arguments with #, something like:
#define MATCH_WITH(str1, str2) MATCH #str1 WITH #str2
That way:
MATCH_WITH(testing, testing)
becomes:
MATCH "testing" WITH "testing"
Related
So I discovered that writing an if statement with parentheses in Perl 6 results in it throwing this error at me:
===SORRY!===
Word 'if' interpreted as 'if()' function call; please use whitespace instead of parens
at C:/test.p6:8
------> if<HERE>(True) {
Unexpected block in infix position (two terms in a row)
at C:/test.p6:8
------> if(True)<HERE> {
This makes me assume that there is some sort of if() function? However, creating and running a script with if(); in it produces the following compiler error:
===SORRY!===
Undeclared routine:
if used at line 15
So like what's the deal?
I read here https://en.wikibooks.org/wiki/Perl_6_Programming/Control_Structures#if.2Funless that parens are optional but that seems to not to be the case for me.
My if statements do work without parens just wondering why it would stop me from using them or why it would think that if is a subroutine because of them.
EDIT: Well aren't I a bit daft... looks like I wasn't reading well enough at the link I linked which I assume is why you are confused. The link I linked points out the following which was basically what I was asking:
if($x > 5) { # Calls subroutine "if"
}
if ($x > 5) { # An if conditional
}
I've accepted the below answer as it does provide some insight.
Are you sure you created a sub with the name 'if'? If so, (no pun intended), you get the keyword if you use a space after the literal 'if', otherwise you get your pre-declared function if you use a paren after the literal 'if' - i.e. if your use of the term looks like a function call - and you have declared such a function - it will call it;
use#localhost:~$ perl6
> sub if(Str $s) { say "if sub says: arg = $s" };
sub if (Str $s) { #`(Sub|95001528) ... }
> if "Hello World";
===SORRY!=== Error while compiling <unknown file>
Missing block
at <unknown file>:1
------> if "Hello World"⏏;
expecting any of:
block or pointy block
> if("Hello World");
if sub says: arg = Hello World
>
> if 12 < 16 { say "Excellent!" }
Excellent!
>
You can see above, I've declared a function called 'if'.
if "Hello World"; errors as the space means I'm using the keyword and therefore we have a syntax error in trying to use the if keyword.
if("Hello World") successfully calls the pre-declared function.
if 12 < 18 { say "Excellent!" } works correctly as the space means 'if' is interpreted as the keyword and this time there is no syntax error.
So again, are you sure you have (or better - can you paste here) your pre-declared 'if' function?
The reference for keywords and whitespace (which co-incidentally uses the keyword 'if' as an example!) is here: SO2 - Keywords and whitespace
So, it's been a while since I have written anything in C++ and now I'm working on a project using C++11 and macros.
I know that by using the stringify operator I can do this:
#define TEXT(a) #a //expands to "a"
How am I supposed to use the preprocessor for recognizing the tokens like + and * to do this:
#define TEXT(a)+ ??? //want to expand to "a+"
#define TEXT(a)* ??? //want to expand to "a*"
when the input has to be in that syntax?
I have tried doing that:
#define + "+"
but of course it doesn't work. How can I make the preprocessor recognize those tokens?
NOTE:
This is actually part of a project for a small language that defines and uses regular expressions, where the resulting string of the macros is to be used in a regex. The syntax is given and we have to use it as it is without making any changes to it.
eg
TEXT(a)+ is to be used to make the regular expression: std::regex("a+")
without changing the fact that TEXT(a) expands to "a"
First,
#define TEXT(a) #a
doesn't “convert to "a"”. a is just a name for a parameter. The macro expands to a string that contains whatever TEXT was called with. So TEXT(42 + rand()) will expand to "42 + rand()". Note that, if you pass a macro as parameter, the macro will not be expanded. TEXT(EXIT_SUCCESS) will expand to "EXIT_SUCCESS", not "0". If you want full expansion, add an additional layer of indirection and pass the argument to TEXT to another macro TEXT_R that does the stringification.
#define TEXT_R(STUFF) # STUFF
#define TEXT(STUFF) TEXT_R(STUFF)
Second, I'm not quite sure what you mean with TEXT(a)+ and TEXT(a)*. Do you want, say, TEXT(foo) to expand to "foo+"? I think the simplest solution in this case would be to use the implicit string literal concatenation.
#define TEXT_PLUS(STUFF) # STUFF "+"
#define TEXT_STAR(STUFF) # STUFF "*"
Or, if you want full expansion.
#define TEXT_R(STUFF) # STUFF
#define TEXT_PLUS(STUFF) TEXT_R(STUFF+)
#define TEXT_STAR(STUFF) TEXT_R(STUFF*)
Your assignment is impossible to solve in C++. You either misunderstood something or there’s an error in the project specification. At any rate, we’ve got a problem here:
TEXT(a)+ is to be used to make the regular expression: std::regex("a+") without changing the fact that TEXT(a) expands to "a" [my emphasis]
TEXT(a) expands to "a" — meaning, we can just replace TEXT(a) everywhere in your example; after all, that’s exactly what the preprocessor does. In other words, you want the compiler to transform this C++ code
"a"+
into
std::regex("a+")
And that’s simply impossible, because the C++ preprocess does not allow expanding the + token.
The best we can do in C++ is use operator overloading to generate the desired code. However, there are two obstacles:
You can only overload operators on custom types, and "a" isn’t a custom type; its type is char const[2] (why 2? Null termination!).
Postfix-+ is not a valid C++ operator and cannot be overloaded.
If your assignment had just been a little different, it would work. In fact, if your assignment had said that TEXT(a)++ should produce the desired result, and that you are allowed to change the definition of TEXT to output something other than "a", then we’d be in business:
#include <string>
#include <regex>
#define TEXT(a) my_regex_token(#a)
struct my_regex_token {
std::string value;
my_regex_token(std::string value) : value{value} {}
// Implicit conversion to `std::regex` — to be handled with care.
operator std::regex() const {
return std::regex{value};
}
// Operators
my_regex_token operator ++(int) const {
return my_regex_token{value + "+"};
}
// more operators …
};
int main() {
std::regex x = TEXT(a)++;
}
You don't want to jab characters onto the end of macros.
Maybe you simply want something like this:
#define TEXT(a, b) #a #b
that way TEXT(a, +) gets expanded to "a" "+" and TEXT(a, *) to "a" "*"
If you need that exact syntax, then use a helper macro, like:
#define TEXT(a) #a
#define ADDTEXT(x, y) TEXT(x ## y)
that way, ADDTEXT(a, +) gets expanded to "a+" and ADDTEXT(a, *) gets expanded to "a*"
You can do it this way too:
#define TEXT(a) "+" // "a" "+" -> "a+"
#define TEXT(a) "*" // "a" "*" -> "a*"
Two string literals in C/C++ will be joined into single literal by specification.
Under Windows, I have an environment variable that contains a Windows-style path. I'd like to build that path into my program and print it out. So if my path is c:\top, I pass it into the compiler using -DTOP=$(TOP). Note I cannot convert it to c:\\top before I pass it into the compiler.
Right now, I have the equivalent of:
#define TOP=c:\top
I want the equivalent of:
char path[]="c:\\top";
I can't just use the stringafication operator:
#define WRAP1(X) #X
#define WRAP(X) WRAP1(X)
char path[] = WRAP(TOP);
That just results in the string "c:\top" which the compiler views as an escape sequence (i.e. \t).
I think a possible solution would be to construct a string literal, but other solutions will be also be fine. Is there a way to use macros to construct a string literal that would yield:
char path[] = R"foo(c:\top)foo";
So far, all my attempts have failed for reasons involving the variations of the " or ( ) or the \ .
Thanks.
You can convert your defined path to a string by prefixing it with the stringizing operator #. However, this only works in macros. You actually need a double-macro to make it work properly, otherwise it just prints TOP. Also placing the pathname in quotes is important - oh the example has the path stored under the env PathDirName
Defining the path for the compiler -
/DTOP="\"$(PathDirName)\\""
Using within the code
#define STRINGIZE2(x) #x
#define STRINGIZE(x) STRINGIZE2(x)
char path[] = STRINGIZE(TOP);
This has worked for me. You nearly had it working, so hope this helps.
[EDIT] I can see the problem now - within C:\top - its taking the 'backslash t' as a control code - '\t'. This appoarch is becoming a little bit of a nightmare to work out - as you really need to create the file name with two slashes or use forward slashes. I do feel I have confused issues here by answering before reviewing fully what has happened.
I have tried several methods - but not being able to change the passed in define - I can only suggest using a regex library or manual scanning the string - replacing the control charactors with the correct '\' letter.
I've knocked up an example showing this just with the '\t' in your example - It's not nice code, it's written to explain what is being done, hopefully it gives an visual example and it does (in a not so nice way) sort out the ONE issue you are having with 'C:\top' .. as I have said - if using this cough, method, you will need to handle all control codes. :-)
char stringName[256];
char* pRefStr = STRING(TOP);
char* pDestStr = stringName;
int nStrLen = strlen( pRefStr );
for( int nIndex = 0; nIndex < nStrLen; nIndex++ )
{
if ( *pRefStr == '\t' )
{
*pDestStr++ = '\\';
*pDestStr++ = 't';
pRefStr++;
}
else
{
*pDestStr++ = *pRefStr++;
}
}
*pDestStr = '\0';
Once again - sorry for any confusion - I've left my answer here as reference for you - and hopefully someone will come up with a way of handling the define-string (with the control charactors).
thanks, Neil
The rather bizarre syntax you're looking for performs on-the-fly substring replacement in variable expansion, as well as some quote mark escaping to make the definition a string. I found the substring replacement information here.
set DIR=C:\WINDOWS gets the env var set, and then we have a test prog:
#include <stdio.h>
#define STR(x) #x
#define STRING(x) STR(x)
int main( int argc, char* argv[] )
{
printf( "DIR: %s\n", STRING(DIR) );
return 0;
}
As you cannot quote in the shell, you can stringize here, but you must still do the variable substring replacement.
Pass the env var in through cmd.exe:
gcc -Wall -DDIR=%DIR:\=\\% main.c
See the link above for more information, or google substring replacement. I can't find a link to any Microsoft info on the function (what a surprise!)
I see this interesting question here asking for the possibility of a program without main(). There, I saw eon giving one answer as follows, which works well in C/C++.
#include<stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
int begin()
{
printf(" hello ");
}
Can someone explain how the above code works? Isn't really there a main() here or just hiding it from our eyes archly?
Have a close look at the macro: it just spliced together main from the characters in animate and gets them replaced for begin().
After the macro substitution:
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
begin becomes decode(a,n,i,m,a,t,e), which then becomes main. There you have it.
The compiler doesn't see "begin" whatsoever. It's completely substituted by the time it gets to the compiler, because macros are simply text-substitutions. Perhaps a helpful diagram to add on to the other great answers.
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)
Take a look at m, and see where m is in the argument list.
decode(s,t,u,m,p,e,d)
^
|
decode(a,n,i,m,a,t,e)
Therefore the first letter is m => m. Then repeat the process, s => a, u => i, t => n.
decode(s,t,u,m,p,e,d)
^ ^ ^
| | |
decode(a,n,i,m,a,t,e)
Then the resulting letters are "pasted" together with token concatenation, and it looks like main as far as the compiler is concerned.
This works because the compiler doesn't really see int begin(){}, The preprocessor will replace begin with main after performing macro substitution and concatenation operator.
First The preprocessor will replace begin with decode(a,n,i,m,a,t,e), after that it will do a rescanning on the replacement list for further replacement, it will find function-like macro decode which will be replaced by it's replacement list after performing the concatenation operator, like this:
m##a##i##n => main
So the compiler will only see the preprocessor output which contain int main(){} and not int begin(){} thus legal code.
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.
You can elide the parentheses as long as you are willing to accept two additions:
the whole code needs to be wrapped in a block macro
there needs to be something following the echo directive
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:
There is no way to make a function-like macro expand without parentheses. This is just a basic requirement of the macro language; if you want something else investigate a different macro processor
Therefore, we need to insert the parentheses; in turn we need to have something after the directive, like a done macro, that will expand to a form containinf the necessary close paren
Unfortunately, because the echo ... 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 text
Text is re-scanned, marked for expansion, and expanded again when it is the argument to a function-like macro, so wrapping the entire block with a block macro (here it's DSL) 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)
We need to hide the ( in the expansion of echo behind the simple macro LPAREN, because otherwise the unmatched parenthesis in the macro body will confuse the preprocessor
If 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.
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.
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.