I try to use code which is generating functions via a macro, which looks like this:
File A (Provided file I can't change anything here):
#define FUNCTION_GENERATOR(NUM) \
void MyGeneratedFunctionNo##NUM##(void) \
{ \
another_function_call(NUM); \
} \
FUNCTION_GENERATOR(1)
FUNCTION_GENERATOR(2)
FUNCTION_GENERATOR(3)
File B (My file where I wanna use function pointers to the generated functions from File A):
typedef void (*function_ptr) (void);
function_ptr func_array[3];
func_array[0] = MyGeneratedFunctionNo1;
func_array[1] = MyGeneratedFunctionNo2;
func_array[2] = MyGeneratedFunctionNo3;
...
Naturally the compiler complains that MyGeneratedFunctionNo1, MyGeneratedFunctionNo2, MyGeneratedFunctionNo3 are not defined.
Is there any way to use function pointers with this
generated functions?
The problem has nothing to do with function pointers per se. You will not be able to access these functions from other translation units in any way, pointers or not, because they are not declared in other translation units.
The typical macro based technique implies providing and using two macros: one for generating declarations and one for generating definitions
#define FUNCTION_GENERATOR_DECL(NUM) \
void MyGeneratedFunctionNo##NUM(void);
#define FUNCTION_GENERATOR_DEF(NUM) \
void MyGeneratedFunctionNo##NUM(void) \
{ \
another_function_call(NUM); \
}
After that you use the "definition" macro instantiations in some implementation file (as you already do)
FUNCTION_GENERATOR_DEF(1)
FUNCTION_GENERATOR_DEF(2)
FUNCTION_GENERATOR_DEF(3)
and you typically place the "declarator" macro instantiations into some header file.
FUNCTION_GENERATOR_DECL(1)
FUNCTION_GENERATOR_DECL(2)
FUNCTION_GENERATOR_DECL(3)
P.S. Also, note an important subtle point mentioned by #James Kanze in the comments (and which I missed initailly). The ## operator shall not be used to form invalid preprocessing tokens. In the preprocessor grammar ( is a separate independent preprocessing token (punctuator), while the function name is also a separate independent preprocessing token (identifier). If you attempt to forcefully concatenate the function name to the ( by using the ## operator, you'll end up with an invalid preprocessing token and undefined behavior.
Don't concatenate the ( to the function name. Remove the second ## from your macro definition. It will work as intended without it.
Just like any other function, you have to declare them. This is typically done in a header file.
You can do this directly, or you can define a macro similar to the one you have that defines the function.
Concretely, place this in a header file, which you include in both the file you define your functions in and in the file you use them:
extern void MyGeneratedFunctionNo1(void);
Related
I want to change yylex to alpha_yylex, that also takes in a vector as an argument.
.
.
#define YY_DECL int yyFlexLexer::alpha_yylex(std::vector<alpha_token_t> tokens)
%}
.
.
. in main()
std::vector<alpha_token_t> tokens;
while(lexer->alpha_yylex(tokens) != 0) ;
I think i know why this fails, because obviously in the FlexLexer.h there is NO alpha_yylex , but i don't know how to achieve what i want...
How can I make my own alpha_yylex() or modify the existing one?
It's true that you cannot edit the definition of yyFlexLexer, since FlexLexer.h is effectively a system-wide header file. But you can certainly subclass it, which will provide most of what you need.
Subclassing yyFlexLexer
Flex allows you to use %option yyclass (or the --yyclass command-line option) to specify the name of a subclass, which will be used instead of yyFlexLexer to define yylex. Subclassing yyFlexLexer allows you to include your own header which defines your subclass' members and maybe even additional functions, as well as its constructors; in short, if your intention was simply to fill in a std::vector<alpha_token_t> with the successive tokens, you could easily do that by defining AlphaLexer as a subclass of yyFlexLexer, with an instance member called tokens (or, perhaps, with accessor functions).
You can also add additional member functions to your new class, which might provide what you need those additional arguments for.
The thing which is not quite so straight-forward, although it could easily be accomplished using the YY_DECL macro in the C interface, is to change the name and prototype of the scanning function generated by flex. It can be done (see below) but it is not clear that it is actually supported. In any case, it is possibly less important in the case of C++.
Aside from a small wrinkle created by the curious organization of Flex's C++ classes [Note 1], subclassing the lexer class is simple. You need to derive your class from yyFlexLexer [Note 2], which is declared in FlexLexer.h, and you need to tell Flex what the name of your class is, either by using %option yyclass in your Flex file, or by specifying the name on the command line with --yyclass.
yyFlexLexer includes the various methods for manipulating input buffers, as well as all the mutable state for the lexical scanner used by the standard skeleton. (Much of this is actually derived from the base class FlexLexer.) It also includes a virtual yylex method with prototype
virtual int yylex();
When you subclass yyFlexLexer, yyFlexLexer::yylex() is defined to signal an error by calling yyFlexLexer::LexerError(const char*) and the generated scanner is defined as the override in the class defined as yyclass. (If you don't subclass, the generated scanner is yyFlexLexer::yylex().)
The one wrinkle is the way you need to declare your subclass. Normally, you would do that in a header file like this:
File: myscanner.h (Don't use this version)
#pragma once
// DON'T DO THIS; IT WON'T WORK (flex 2.6)
#include <yyFlexLexer.h>
class MyScanner : public yyFlexLexer {
// whatever
};
You would then #include "myscanner.h" in any file which needed to use the scanner, including the generated scanner itself.
Unfortunately, that won't work because it will result in FlexLexer.h being included twice in the generated scanner; FlexLexer.h does not have an include guard in the normal sense of the word because it is designed to be included multiple times in order to support the prefix option. So you need to define two header files:
File: myscanner-internal.h
#pragma once
// This file depends on FlexLexer.h having already been included
// in the translation unit. Don't use it other than in the scanner
// definition.
class MyScanner : public yyFlexLexer {
// whatever
};
File: myscanner.h
#pragma once
#include <FlexLexer.h>
#include "myscanner.h"
Then you use #include "myscanner.h" in every file which needs to know about the scanner except the scanner definition itself. In your myscanner.ll file, you will #include "myscanner-internal.h", which works because Flex has already included FlexLexer.h before it inserts the prologue C++ code from your scanner definition.
Changing the yylex prototype
You can't really change the prototype (or name) of yylex, because it is declared in FlexLexer.h and, as mentioned above, defined to signal an error. You can, however, redefine YY_DECL to create a new scanner interface. To do so, you must first #undef the existing YY_DECL definition, at least in your scanner definition, because a scanner with %option yyclass="MyScanner" contains #define YY_DECL int MyScanner::yylex(). That would make your myscanner-internal.h` file look like this:
#pragma once
// This file depends on FlexLexer.h having already been included
// in the translation unit. Don't use it other than in the scanner
// definition.
#undef YY_DECL
#define YY_DECL int MyScanner::alpha_yylex(std::vector<alpha_token_t>& tokens)
#include <vector>
#include "alpha_token.h"
class MyScanner : public yyFlexLexer {
public:
int alpha_yylex(std::vector<alpha_token_t>& tokens);
// whatever else you need
};
The fact that the MyScanner object still has a (not very functional) yylex method might not be a problem. There are some undocumented interfaces in FlexLexer which call yylex(), but those don't matter if you don't use them. (They're not all that useful, anyway.) But you should at least be aware that the interface exists.
In any case, I don't see the point of renaming yylex (but perhaps you have a different aesthetic sense). It's already effectively namespaced by being a member of a specific class (MyScanner, above), so yylex doesn't really create any confusion.
In the particular case of the std::vector<alpha_token_t>& argument, it seems to me that a cleaner solution would be to put the reference as a member variable in the MyScanner class and set it with the constructor or with an accessor method. Unless you actually use different vectors at different points in the lexical analysis -- not evident in the example code in your question -- there's no point burdening every call site with the need to pass the address of the vector into the yylex call. Since lexer actions are compiled inside yylex, which is a member function of MyScanner, instance variables -- even private instance variables -- are usable in the lexer actions. Of course, that's not the only use case for extra yylex arguments, but it's a pretty common one.
Notes
"The C++ interface is a mess," according to a comment in the generated code.
Using %option prefix, you can change yy to something else if you want to. This a feature which is supposedly intended to allow you to include multiple lexical scanners in the same project. However, if you're planning on subclassing, the base classes for all these lexical scanners will be identical (other than their names). Thus, there is little or no point having different base classes. Renaming the scanner class using %option prefix is less flexible and no more efficient than subclassing, and it creates an additional header complication. (See this older answer for details.) So I'd recommend sticking with subclassing.
I have simple delegate functions in my C++ test code. Since I cannot include the original implementation .cpp files(embedded ones), I use delegate .cpp file in the tests that are running on PC. My idea is to simply use the same macro as a body for the implementation, except the parentheses () and arguments which will supplied according to the signature.
I tried something like:
void Flash::init()
{
DELEGATE_DESTINATION();
}
bool Flash::write(args)
{
DELEGATE_DESTINATION(args);
}
bool Flash::read(args)
{
DELEGATE_DESTINATION(args);
}
Where
void Flash::init()
bool Flash::write(args)
bool Flash::read(args)
Are identical to the ones in the embedded project implementation ones. In the test files I simply relay the call to the fake implementations. One possible solution would be to already include the signature and implementation in the fake classes not using relaying, I know.
I am having hard time figuring out the macro. I tried something like:
#define FAKE_PREFIX fakes::device::Flash::
#define DELEGATE_DESTINATION FAKE_PREFIX##__FUNCTION__
Which expands to FAKE_PREFIX__FUNCTION__
Well then after going through C Preprocessor, Stringify the result of a macro
I can get only fakes expanding in place.
My goal would be to have a result like
fakes::device::Flash::init
and so on for read and write.
What you want to do can be done far simpler. You don't need the full power of the pre-processor:
You don't concatenate tokens (:: is not part of a valid token). You just need to print one macro next to another.
_FUNCTION_ isn't a pre-processor macro, it's a string literal (in gcc and other compilers).
So to do what you want, you need to pass the function name into your macro:
#define FAKE_PREFIX fakes::device::Flash::
#define DELEGATE_DESTINATION(func) FAKE_PREFIX func
Then you define your functions, like this:
bool Flash::write(args)
{
DELEGATE_DESTINATION(write)(args);
}
It's all live here.
I have a function in a header file:
template <int line>
inline void log() {}
And then I try this trick to make using it easier:
#define LOG_LINE log<__LINE__>()
And then in a .cpp file I do:
void main()
{
LOG_LINE;
}
And it seems that it works the way I'd like it to. I get the line from .cpp file, not the line at which LOG_LINE is declared in .h file. But I don't understand how it works. Does C++ perfrom double-pass preprocessing, leaving special macros like __LINE__ for second pass? Is this portable (standard) behavior? Should I expect this to work with all major C++ compilers? So far I've only tried MSVC.
One should distinguish between the number of passes through the entire input, which is what terms like single-pass normally refer to, and handling of nested expansions. The preprocessor normally expands all macros in a single pass through the file, but it correctly expands the expanded forms, until there is nothing left to expand.
That is, LOG_LINE gets expanded to log<__LINE__>(), where __LINE__ again gets expanded to 3, producing the final expansion log<3>() — all in a single pass through the compilation unit.
Yes, this is portable, standard behaviour. Yes you can depend on it.
The reason is that the #define command simply stores the tokens that constitute the expansion text without interpreting it or expanding it at all. Because they are tokens, white space and comments are not stored.
Then when the macro name is used in the program text, it is replaced by the expansion text (and any arguments as needed). Then any tokens in the substituted text are scanned and replaced, and so on (except there is no recursive replacement).
In your case it takes two expansions to get to the underlying line number.
See N3797 16.3. It's relatively readable, for a standards document. There are examples quite close to what you're asking.
This does not need double pass preprocessing. This is about the order of expansion of nested macros (well, in a sense, an expression is expanded in as many passes as needed to expand all the nested macros). A quote from an answer to this question:
All arguments which don't appear after the # operator or either side of a ## are fully macro expanded when they are replaced, not before the function-like macro is expanded.
I want to simplify things, by not creating a list of enum separately, but create the enums along the function call which creates the data where i point with those enums.
I tried to make #define which would create another #define, but it didnt work:
int defcounter = 0;
#define make_def(enumname, somedata) \
#define enumname defcounter \
defcounter++; \
func_call(somedata); \
void createstuff(){
make_def(MY_ENUM_NAME, mydata);
make_def(MY_OTHER_ENUMNAME, mydata);
}
void dostuff(){
somefunc_call(MY_ENUM_NAME);
somefunc_call(MY_OTHER_ENUMNAME);
}
But this will create error at the #define enumname:
error C2162: expected macro formal parameter
How can I make this work?
It is impossible to create new types (classes, enums, unions, whatever) at runtime in C++. One of the major features of C++ is that it is statically typed - all types must be known at compile time.
Preprocessor commands (#define, #if, #pragma, #include, ...) cannot appear in macros / defines. The problem is, that the CPP (C-Preprocessor) seperates commands by newlines, while C and C++ are unaware of newlines. In C/C++ you can write everything on one line, for preprocessor commands, you can't.
#define MY_MACRO(name) \
#define name##_macro something_cool \
enum name{ \
.... \
}
// somewhere else
void myfunc(){
MY_MACRO(myfunc_enum);
}
Now, at preprocessing time, those lines all get glued into one big line, thanks to the \ backslash:
#define MY_MACRO(name) #define name##_macro something_cool enum name{....}
Now, how would that macro look at usage?
void myfunc(){
#define name##_macro something_cool enum name{....};
}
Now, the preprocessor has to run over that #define again. But exactly what belongs to the #define, and what doesn't? For the coder it was clear when the macro was written in seperate lines, but now it isn't anymore.
What exactly is your desired output? You need to explain what you think you might get as output from the C preprocessor.
You have scope problems and an attempt to define a macro inside the replacement text of another macro.
Scope
The macro make_def() invokes an undefined function 'func_call'. The createstuff() function uses an undefined variable mydata. And function dostuff() seems to call an undefined function somefunc_call() with an enum that might, perhaps, have been defined inside a separate function.
If an enumeration is defined inside one function, that enumeration is not available to code outside that function, and specifically is not available to either called functions or calling functions. That alone limits the utility of what you seem to be attempting to do. (Yes, the enumeration values might be implicitly converted to int or some similar type, but it is not really the enumeration type that is being used.)
Defining macros in macros
You cannot create a macro that itself contains #define or any other preprocessor directive in its replacement text.
If the outer macro is invoked, the expansion does not interpret the inner #define as being a preprocessor directive, so it almost always ends up as an error, In context the # must be a stringize operator, and the word 'define' after it would have to be the name of an argument to the outer macro to have a chance of working.
// Does not work as intended
#define macro(define, prefix) #define another(name) foo(prefix ## name)
macro(something, other);
Generates:
"something" another(name) foo(othername);
The _Pragma in C99 is a partial exception to the 'a macro expansion cannot contain a preprocessor directive', but it (_Pragma) does not start with #.
Your macro is incorrect, since you cannot use a macro to create another macro, unfortunately, as the toke # has special meaning in the expansion-list: it can either quote a macro argument, or expand another macro. One easy (albeit poorly designed) way you could do this is just to use old c-style #define MY_ENUM_NAME valueas c macro do not respect scope, but this would not be good design. Another possibility is to pass in string arguments and hash on them, but all depends on what you want to do.
I'm used to this:
class Db {
_Commit(char *file, int line) {
Log("Commit called from %s:%d", file, line);
}
};
#define Commit() _Commit(__FILE__, __LINE__)
but the big problem is that I redefine the word Commit globally, and in a 400k lines application framework it's a problem. And I don't want to use a specific word like DbCommit: I dislike redundancies like db->DbCommit(), or to pass the values manually everywhere: db->Commit(__FILE__, __LINE__) is worst.
So, any advice?
So, you're looking to do logging (or something) with file & line info, and you would rather not use macros, right?
At the end of the day, it simply can't be done in C++. No matter what mechanism you chose -- be that inline functions, templates, default parameters, or something else -- if you don't use a macro, you'll simply end up with the filename & linenumber of the logging function, rather than the call point.
Use macros. This is one place where they are really not replaceable.
EDIT:
Even the C++ FAQ says that macros are sometimes the lesser of two evils.
EDIT2:
As Nathon says in the comments below, in cases where you do use macros, it's best to be explicit about it. Give your macros macro-y names, like COMMIT() rather than Commit(). This will make it clear to maintainers & debuggers that there's a macro call going on, and it should help in most cases to avoid collisions. Both good things.
Wait till C++20, you cal use source_location
https://en.cppreference.com/w/cpp/utility/source_location
You can use a combination of default parameter and preprocessor trick to pass the caller file to a functions. It is the following:
Function declaration:
static const char *db_caller_file = CALLER_FILE;
class Db {
_Commit(const char *file = db_caller_file) {
Log("Commit called from %s", file);
}
};
Declare db_caller_file variable in the class header file.
Each translation unit will have a const char *db_caller_file. It is static, so it will not interfere between translation units. (No multiple declarations).
Now the CALLER_FILE thing, it is a macro and will be generated from gcc's command line parameters. Actually if using automated Make system, where there is generic rule for source files, it is a lot easier: You can add a rule to define macro with the file's name as a value. For example:
CFLAGS= -MMD -MF $(DEPS_DIR)/$<.d -Wall -D'CALLER_FILE="$<"'
-D defines a macro, before compiling this file.
$< is Make's substitution for the name of the prerequisite for the rule, which in this case is the name of the source file. So, each translation unit will have it's own db_caller_file variable with value a string, containing file's name.
The same idea cannot be applied for the caller line, because each call in the same translation unit should have different line numbers.