An option is defined (value = 1 or 2) to chose between two instructions and I would like to use with an instruction which have a comma.
#define option 1
#if option == 1
#define my_instr(instr1, instr2) instr1
#else if option == 2
#define my_instr(instr1, instr2) instr2
#endif
It works but when there is a comma in the instruction, I have a problem.
For example :
program main
my_instr(print *,"opt 1", print * ,"opt 2")
end program main
does not compile (gftran -cpp) : Too much args. I am ok.
Thus, to escape the comma, parentheses are added : my_instr((print *,"opt 1"), (print * ,"opt 2"))
But it does not compile any more because of parentheses.
How can I solve that ?
Using the answer (https://stackoverflow.com/a/46311121/7462275), I found a " solution ".
#define option 2
#define unparen(...) __VA_ARGS__
#if option == 1
#define my_instr(instr1, instr2) unparen instr1
#elif option == 2
#define my_instr(instr1, instr2) unparen instr2
#endif
program main
my_instr((print *,"opt 1"), (print * ,"opt 2"))
end program main
But,
gfortran -cpp does not compile (problem with __VA_ARGS__). So, cpp -P is used before gfortran
__VA_ARGS__ : It is not standard to use __VA_ARGS__ without something before (cf comments of :Matthew D. Scholefield in the answer used :
Just something to note, this still doesn't conform to the C standard because of the use of a variadic macro.
and KamilCuk in this question)
Even instructions without comma need to be enclosed between parentheses
This will select the correct string.
#ifdef my_instr
#undef my_instr
#endif
#define my_instr(x) print *, x
#if option == 1
#define str "Opt 1"
#else if option == 2
#define str "Opt 2"
#endif
program foo
my_instr(str)
end program foo
% gfortran -E -Doption=2 a.F90 | cat -s
# 1 "a.F90"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "a.F90"
program foo
print *, "Opt 2"
end program foo
Related
I was trying to check some single line macros which have 2 pre-processor directives.
#define REPLACE { \
#if EXT == 42 \
#warning "Got 42" \
#endif \
}
int main(void){
REPLACE;
return 0;
}
The pre-processor parses this fine yielding:
$g++ -E includetest.cpp
# 1 "includetest.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "includetest.cpp"
int main(void){
{ #if EXT == 42 #warning "Got 42" #endif };
return 0;
}
which of course is illegal code, since just macro substitution occurs and the ifdef lookalike macro isn't processed again even though it looks like one.
Now if I slightly alter the macro to look something like
#define REPLACE(a) { a + 2 ; \
#if EXT == 42 \
#warning "Got 42" \
#endif \
}
int main(void){
REPLACE(0);
return 0;
}
Which yields this pre-processor error:
$g++ -E includetest.cpp
# 1 "includetest.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "includetest.cpp"
includetest.cpp:1:18: error: '#' is not followed by a macro parameter
#define REPLACE(a) { a + 2 ; \
^
int main(void){
REPLACE(0);
return 0;
}
Why does this error come up ? Of course, this won't compile but I want to know why addition of a parameter ensues in a parsing error from pre-processor ?
People would say " You can't nest another directive in another", but in the first case too they are nested, why doesn't pre-processor error out then ? Or is that responsibility delegated to the compiler ?
EDIT: I am not trying to achieve any functionality per se, this is just an exercise (in futility?) to understand the pre-processor.
Only inside a function macro does a # have special meaning ([cpp.stringize]p1). The standard says that a # needs to be followed by a function argument, which is not happening in your second case (if, warning and endif are not parameters).
Your first case is valid (you can actually have directives inside the replacement list of object macros) exactly because there # doesn't have any special meaning.
I have an header with a lot of #defines, like this:
#define XY_ABC_FOO 1
#define XY_ABC_BAR 3
#define XY_ABC_PIPPO 5
#define XY_ABC_PLUTO 7
#define XY_ABC_ETC 19
...
and so on and on.
I'd like to put all those in a vector.I can do it by hand (in a few minutes).
std::vector<int> defs = { 1, 3, 5, 7, 19 , ... }
But then, next time definition are added in the header, someone will have to remember to add them in my code too.
Is there any very clever preprocessor/metaprogramming trick to catch them all at compile time?
I don't particularly care about fast compilation, it's test code so it will be compiled seldom and mostly overnight.
You could do it with awk:
awk '/^#define XY_ABC_\w+ \d+$/ {
if(line) {
line = line ", " $2
} else {
line = "std::vector<int> defs = { " $2
}
END { print line " };" }' < header.hpp > defs.hpp
Then in your main program use #include defs.hpp to get the declaration.
You seem to want to achieve that using only #defines, but I'm almost completely sure that it's impossible.
But if you'd allow those values to be constexprs, then you'd be able to do following. (And it's probably a best thing you can get without external tools.)
#define DEFS \
C(XY_ABC_FOO, 1) \
C(XY_ABC_BAR, 3) \
C(XY_ABC_PIPPO, 5) \
C(XY_ABC_PLUTO, 7) \
C(XY_ABC_ETC, 19)
#define C(name, value) constexpr int name = value;
DEFS
#undef C
/* ... */
#define C(name, value) value,
std::vector<int> defs = {DEFS};
#undef C
I'm working on several versions of the same code in FORTRAN 77 and in every code I print the file name and version number, but after so many versions it has become tedious to have to change that line. I was wondering if there is a way for the code to return its own file name since the file name has the version number in it? The line I have now looks something like this, codevers='testfile_v009' and print *, 'Code Version: ', codevers
The only problem with this is that I copy the previous version of the code and make changes to it as the new version but often forget to update those lines in the code.
Any help appreciated! Thanks.
As suggested in the comments, one approach will be to use compiler preprocessors. For example, if you make test_ver1.F90 (free format) or test_ver1.F (fixed format)
program main
print *, "current file = ", __FILE__
print *, "current line = ", __LINE__
end program
and compile it as
gfortran test_ver1.F90
./a.out
you will get
current file = test_ver1.F90
current line = 3
How to invoke a preprocessor depends on the compiler used, so please consult the manual. (For many compilers, the preprocessor will be invoked if the file name has a suffix like .F90 and .F, or by using options like -cpp or -fpp.)
An application of this is to define a code-checking macro, for example
#ifdef __GFORTRAN__
#define _assert_(x) if (.not.(x)) then; print*, "In ",__FILE__,", line ",__LINE__; stop "assertion failed: " // "x"; endif
#else
#define _assert_(x) if (.not.(x)) then; print*, "In ",__FILE__,", line ",__LINE__; stop "assertion failed: " // #x; endif
#endif
With this saved in mymacro.inc, the following program (test_ver2.F90)
#include "mymacro.inc"
program main
integer :: x, y
x = 7 ; y = 8
_assert_( x == y )
end program main
gives
In test_ver2.F90, line 6
STOP assertion failed: x == y
which is convenient for sanity check. (You can turn this off by defining a blank macro #define _assert_(x) so that the overhead becomes zero in production runs.)
I have a bunch of C files and I need to count how many #ifdef clauses have an #elif clause but do not have an #else clause in those files, including possible nested #ifdef clauses. For instance, in the first code snippet there are no matches, while in the second code snippet, there are two matches:
1: No matches (the #ifdef contains an #else clause)
#ifdef A
...
#elif B
...
#else
...
#endif
2: Two matches (there are two #ifdef clauses with #elif clauses but without a corresponding #else)
#ifdef X1
...
#elif X2
...
#endif
...
#ifdef Y1
...
#elif Y2
...
#elif Y3
...
#endif
I'm looking for a way to do this using some command line tool, such as grep, awk or sed, but no luck so far. So, I'm still open for easier alternatives, if any.
I have tried this regular expression using grep: '^(?=.*#elif)((?!#elif|#else).)(?=.*\#endif).)*$' (an #elif that is not followed by another #elif or #else and have a corresponding #endif), but it does not work, since clauses are in different lines.
You need to write a recursive-descent parser that descends every time it finds a "#ifdef" and returns every time it finds "#endif". See How to compare and substitute strings in different lines in unix for an example of one written in awk.
You didn't provide useful sample input or expected output so I had to make up my own to test it (and so it might not be exactly what you need), but you will want something like:
$ cat tst.awk
function descend(cond, numElifs,numElses,gotEndif) {
while ( !gotEndif && (getline > 0) ) {
if ( /#ifdef/ ) { descend($2) }
else if ( /#elif/ ) { numElifs++ }
else if ( /#else/ ) { numElses++ }
else if ( /#endif/ ) { gotEndif++ }
}
print cond, numElses+0, numElifs+0, ((numElifs>0)&&(numElses==0) ? "UhOh" : "")
return
}
/#ifdef/ { descend($2) }
.
$ cat file
#ifdef A
#elif B
#else
#ifdef C
#elif D
#endif
#ifdef E
#elif F
#else
#endif
#ifdef G
#elif H
#ifdef I
#else
#endif
#elif J
#endif
#endif
.
$ awk -f tst.awk file
C 0 1 UhOh
E 1 1
I 1 0
G 0 2 UhOh
A 1 1
Note that this IS an appropriate use of getline but see http://awk.info/?tip/getline before using it elsewhere.
All the usual caveats about really needing a parser for the language (to handle e.g. #ifdef inside comments or string) instead of a script like this apply.
Solution
Apart from the assumptions that #if, #ifdef, etc. doesn't appear in string or comments, and that the code is written in a sane manner, i.e. no crazy stuffs like:
#i\
fdef
I made at least another assumption that if, ifdef must be immediately preceded by #, while there can be arbitrary tab or space characters in between.
The regex below has been tested to work for PCRE and Perl flavors.
# Look-ahead to allow overlapping matches
(?=
(
# Just define patterns. Doesn't match anything.
(?(DEFINE)
(?<re>
# Match lines not ifdef, if, elif, else, endif macro
(?![ \t]* [#](?:if(?:def)?|elif|else|endif)) .*\R
|
# Recurse into another if or ifdef
(?1)
)
)
# Only match ifdef at top level, and allow if and ifdef nested
^[ \t]* [#](?(R)if(?:def)?|ifdef) .*\R
(?&re)*
# Match elif clause at least once at top level
(?(R)
|
(?:
[ \t]* [#]elif .*\R
(?&re)*
)
)
# Match 0 or more elif clauses
(?:
[ \t]* [#]elif .*\R
(?&re)*
)*
# Optional else clause nested
# else clause not allowed at top level
(?(R)
(?:
[ \t]* [#]else. *\R
(?&re)*
)?
)
# Match endif
[ \t]*[#]endif.*\R?+
)
)
Required flags: m (multiline, for the ^), and x (free-spacing syntax and comment).
Demo on regex101
The construct (?(R)...) is a conditional construct, which tests if we are currently inside any routine call. It is used to check the current nesting level of if/ifdef.
Technically, (?&re) which calls into the pattern defined in (?(DEFINE)...) counts as routine call, but except for (?1) which enters into another nested if/ifdef, the first alternation only operates on lines without if/ifdef, so it doesn't affect the final result.
Appendix
General purpose version
This is the regex for general case, without the restrictions on else and elif clause as required in the question. It is simpler, since we don't have to take care of the restrictions.
If you have a hard time digesting the regex above, this could be a good starting point.
(?=
(
(?(DEFINE)
(?<re>
(?![ \t]* [#](?:if(?:def)?|elif|else|endif)) .*\R
|
(?1)
)
)
^[ \t]* [#]if(?:def)? .*\R
(?&re)*
(?:
[ \t]* [#]elif .*\R
(?&re)*
)*
(?:
[ \t]* [#]else. *\R
(?&re)*
)?
[ \t]*[#]endif.*\R?+
)
)
Demon on regex101
Test case
#ifdef X1
#elif X2
#endif
#ifdef Y1
#define DEF
#if defined(X) && U == 0
#elif
#endif
#elif Y2
#ifdef Y1
#elif Y2
#else
#endif
#elif Y3
#endif
#ifdef X
#ifdef Y
#else
#endif
#ifdef K
#elif
#ifdef N1
#elif
#endif
#ifdef N2
#elif
#endif
#endif
#elif defined Z
#ifdef T
#elif
#endif
#endif
#ifdef Y
#ifdef E1
#endif
#ifdef E2
#elif
#endif
#endif
#ifdef Y
#elif
#endif
If you just want to count them this should work.
As far as my testing it should work fine with nesting.
awk '/#ifdef/{x++}
/#elif/&&a[x]!="q"{a[x]="s"}
/#else/{a[x]="q"}
/#endif/{total+=a[x]=="s";delete a[x];x--}
END{print total}' file
For EdMortons input file this would result in
2
I am compiling my code in AIX env.. it givs me error "std::to_string" is not declared
successfully compiled same code in Windows.
define LOG_MSG(message) CLogManager::LogMessage(CLogManager::CurrentDateTime() + " - " + std::string(__FILE__) + "[" + std::to_string(static_cast<_ULonglong>(__LINE__)) + "] : " + std::string(message) + "\n")
This is the macro and i am using this as
LOG_MSG(" ** BEGIN StorePasswordFromFile()");
This macro is for logging purpose
I'm not sure how much support the latest xlC 14.1 (or whatever version you're using) has for std::to_string().
If the support is incomplete, C has a hideous double macro method (a) of turning __LINE__ into a C-string so that you can just use std::string, the same as you have for the __FILE__ and message items, and it appears the C++ pre-processor has stayed faithful to its hideous roots :-)
The code:
#include <stdio.h>
#define STR1(x) # x
#define STR2(x) STR1(x)
int main(void) {
char x[] = __FILE__;
char y[] = STR2(__LINE__);
printf("file = %s, line = %s\n",x,y);
return 0;
}
outputs:
file = qq.c, line = 6
showing that the __LINE__ has been successfully morphed into a C-string value.
You should be able to use a similar method in your macro:
#define STR1(x) # x
#define STR2(x) STR1(x)
#define LOG_MSG(message) CLogManager::LogMessage( \
CLogManager::CurrentDateTime() + " - " + \
std::string(__FILE__) + "[" + \
std::string(STR2(__LINE__)) + "] : " + \
std::string(message) + "\n")
int main() {
LOG_MSG ("My hovercraft is full of eels");
return 0;
}
Pre-processing that with g++ -E qq.cpp gives you:
CLogManager::LogMessage( CLogManager::CurrentDateTime() + " - " + std::string("qq.cpp") + "[" + std::string("10") + "] : " + std::string("My hovercraft is full of eels") + "\n");
(showing relevant line only) which seems to match what you want.
As a side note however, since you seem to be okay adding C-strings like "[" without needing to construct strings explicitly, I'm not sure that you need the std::string() calls at all for those. You still need the C macro hack to turn the integer into a C-string but, once that's been done, you should just be able to use that as-is.
Changing the final macro to:
#define LOG_MSG(message) CLogManager::LogMessage( \
CLogManager::CurrentDateTime() + " - " + \
__FILE__ + "[" + \
STR2(__LINE__) + "] : " + \
message + "\n")
will give you:
CLogManager::LogMessage( CLogManager::CurrentDateTime() + " - " + "qq.cpp" + "[" + "10" + "] : " + "My hovercraft is full of eels" + "\n");
Whether that's a good idea, I'll leave to the wider community but it at least gets around your immediate problem. I'd probably place the whole lot inside an #if/#else/#endif so that C++11 compilers that know about std::to_string() can use the more accepted approach.
(a) If you're interested in why this works, I'll explain below.
The # and ## macro operators actually take precedence over the recursive nature of macro replacement, as per C11 6.10.3.4 /1:
After all parameters in the replacement list have been substituted and # and ##
processing has taken place, all placemarker preprocessing tokens are removed. The
resulting preprocessing token sequence is then rescanned, along with all subsequent
preprocessing tokens of the source file, for more macro names to replace.
That means that the code:
#define STR(x) # x
STR(__LINE__)
will actually result in "__LINE__" because the # happens first and, once that's happened, the __LINE__ within the string literal is not subject to further replacement. By doing the two-step process:
#define STR1(x) # x
#define STR2(x) STR1(x)
STR2(__LINE__)
the first level of replacement turns STR2(__LINE__) into STR1(3) because __LINE__ on its own is subject to expansion.
Then the second level turns STR1(3), via # 3, into "3".
Perhaps the following may help:
#define STR1(x) # x
#define STR2a(x) STRn(x)
#define STR2b(x) STR1(x)
STR1(__LINE__)
STR2a(__LINE__)
STR2b(__LINE__)
The output of that, annotated, is:
"__LINE__" - stringise, no further processing of __LINE__ inside literal.
STRn(6) - shows first stage of replacement, line number replacement.
"7" - shows full process.