Calling a function from another file into another function C++ - c++

I have some header files which host functions and in other enums.
So in file Lexer.h, I have a function called getNextToken() which returns a token and in this function I need to call a function called reservedLookup(string tokenString) found in token.h
reservedWords is another header file called reservedWords.h which has enum declarations of the reserved Words
This function is found in token.h
reservedWords reservedLookup (string tokenString)
{
for(rIt = reservedMap.begin(); rIt!= reservedMap.end(); rIt++)
{
if(tokenString == (rIt->first))
{
return rIt->second;
}
}
}
in lexer.h I tried using this in private (and even in public:) :
reservedWords reservedLookup(string tokenString);
it compiles, but when in function Token* getNextToken() I use
int tokenType = reservedLookup(strBuffer);
it gives me an error stating:
obj\Release\main.o:main.cpp:(.text$_ZN5Lexer12getNextTokenEv[__ZN5Lexer12getNextTokenEv]+0x371)||undefined reference to `Lexer::reservedLookup(std::string)'|
I don't want my compiler to read reservedLookup as part of Lexer::reservedLookup(string str) but as Token::reservedLookup(string str)
Is there any way I can do it?
EDIT:
Token.h
class Token
{
.....
.....
public:
void reservedDeclare ()
{
// iterator used for looping through reservedWords
//Taking care of the Reserved Words first
reservedMap["function"] = reservedWords::tkfunction;
//if - then - else - while - halt
reservedMap["if"] = reservedWords::tkif;
reservedMap["else"] = reservedWords::tkelse;
reservedMap["while"] = reservedWords::tkwhile;
reservedMap["halt"] = reservedWords::tkhalt;
//and, or, not, true, else
reservedMap["and"] = reservedWords::tkand;
reservedMap["or"] = reservedWords::tkor;
reservedMap["not"] = reservedWords::tknot;
reservedMap["true"] = reservedWords::tktrue;
reservedMap["false"] = reservedWords::tkfalse;
//sets and read/write
reservedMap["set"] = reservedWords::tkset;
reservedMap["let"] = reservedWords::tklet;
reservedMap["read"] = reservedWords::tkread;
reservedMap["write"] = reservedWords::tkwrite;
//variable type
reservedMap["int"] = reservedWords::tkint;
reservedMap["char"] = reservedWords::tkchar;
reservedMap["bool"] = reservedWords::tkbool;
reservedMap["real"] = reservedWords::tkreal;
reservedMap["string"] = reservedWords::tkstring;
reservedMap["unit"] = reservedWords::tkunit;
}
reservedWords reservedLookup (string tokenString)
{
for(rIt = reservedMap.begin(); rIt!= reservedMap.end(); rIt++)
{
if(tokenString == (rIt->first))
{
return rIt->second;
}
}
}
reservedWords.h
#ifndef RESERVEDWORDS_H_INCLUDED
#define RESERVEDWORDS_H_INCLUDED
#include <string>
#include <vector> //std::vector
#include <algorithm> // std::find
using namespace std;
/**
All the reserved words used by the compiler
*/
/**
This file contains all the keywords or reserved words or reserved Symbols used by the compiler
In the lexer, we will check whether the string we are passing is either a Reserved word
or it is actually and identifier
*/
enum reservedWords
{
tkfunction,
tkif,
tkelse,
tkwhile,
tkhalt,
tkand,
tkor,
tknot,
tktrue,
tkfalse,
tkset,
tklet,
tkread,
tkwrite,
tkint,
tkchar,
tkbool,
tkreal,
tkstring,
tkunit,
tkreservedWord,
tkidentifier
};
#endif // RESERVEDWORDS_H_INCLUDED
PARTIAL Code of Lexer.h
class Lexer
{
private:
string strBuffer ="";//holds the current characters that have been read and waiting to be matched
int tokenType = 0;
reservedWords reservedLookup(string tokenString); // THIS DOES NOT WORK. SEES IT AS Lexer::reservedLookup
....
....
...
...
tokenType = reservedLookup(strBuffer); // GIVES ME ERROR BECAUSE OF ABOVE

Let's look at this part of your code first:
class Token
{
...
public:
...
reservedWords reservedLookup (string tokenString)
{ // start of function body
for(rIt = reservedMap.begin(); rIt!= reservedMap.end(); rIt++)
{
if(tokenString == (rIt->first))
{
return rIt->second;
}
}
} // end of function body
...
};
In this file you have declared a function whose fully-scoped name is Token::reservedLookup. (If you're unfamiliar with the term "fully scoped", OK; for our purposes here, the important thing is that this is a specific way of naming this function.) We can write Token:: at the front of this name because this function is a member of the class Token. You have also defined the function by providing a function body (the code enclosed in braces { and }). I have added comments on the lines where the function body begins and ends.
So far, so good. Now, this function is an ordinary member of the class Token, not a "static" function, so in order to call it, you must first have an object of type Token, and then you can call this function on that object, for example by writing code like this inside some other function:
Token token;
token.reservedDeclare();
reservedWords word = token.reservedLookup("read");
Now comes the part where things get confused. You wrote this code:
class Lexer
{
private:
...
reservedWords reservedLookup(string tokenString);
...
};
What this does is to declare a different function from the first one. This function's fully-scoped name is Lexer::reservedLookup. You have not provided any definition of the function, however (neither here, nor apparently anywhere else). So when you are within the code of the Lexer class and you write a line such as this,
tokenType = reservedLookup(strBuffer);
the compiler interprets this in the way the C++ language specification says it should, which is that this should be a call to the function reservedLookup that belongs to the class of the same function where this call appeared. In short, it is a call to Lexer::reservedLookup. Since you never defined that function, it is impossible to produce the code that calls the function correctly, and therefore you have an error.
So you probably do not want to define Lexer::reservedLookup at all. If you are not calling Token::reservedLookup from within one of the functions of the class Token itself, you may provide an object of type Token so that you may call the function, as I did in my example. Alternatively, you might want to make your definition of the function static so that you can call it this way, without requiring an object of type Token:
reservedWords word = Token::reservedLookup("read");
In order to make this work as desired, however, you would also have to make reservedDeclare a static function and make reservedMap a static variable of Token, or make some other changes so that the data used by Token::reservedLookup exists independently of a specific object of type Token.
You may also want to look at the answers to this question: The Definitive C++ Book Guide and List and read a recommended book to help understand the terminology of the language better so that you can get better advice about your programs.

Related

How to use custom C++ attributes with Clang libTooling without modifying Clang code?

I'm writing some kind of tool that extracts the interface definitions of C++ code.
In process of writing, I decided to restrict the parser to process only the code that was explicitly marked for processing, and I thought that C++ attributes are the best way to do it.
I'd prefer to add e.g. [[export]] annotations to entities I want to export, but I realised that libTooling is unable to see custom attributes without registering them in Clang code itself (I mean adding the attribute to tools/clang/include/clang/Basic/Attr.td).
Thus, my question is: is there a way to register the attribute without modifying that file (e.g. by registering the attribute programmatically or writing own Attr.td file)?
UPD: I'm using ASTMatchers library for source code analysis, so visitor-based approach probably does not work for me.
From what I can tell it is not possible to register custom attributes without directly modifying libtooling.
If you're willing to use pre-processor macros instead of attributes there is a workaround that I've done in the past. The basics are that we'll declare an empty macro, write a pre-processor callback to identify the location of the macro and store it in a queue, then in an AST visitor we'll visit records for either classes, methods, or variables, and check to see if preceeding the entity is our macro.
For the preprocessor you'll need to extend clang::PPCallbacks and implement the MacroExpands method.
void MyPreProcessorCallback::MacroExpands(const clang::Token& MacroNameTok, const clang::MacroDefinition&, const clang::SourceRange Range, const clang::MacroArgs* const Args)
{
// Macro is not named for some reason.
if(!MacroNameTok.isAnyIdentifier())
{ return; }
if(MacroNameTok.getIdentifierInfo()->getName() == "EXPORT")
{
// Save Range into a queue.
}
else
{
return;
}
// If you want arguments you can declare the macro to have varargs and loop
// through the tokens, you can have any syntax you want as they're raw tokens.
// /* Get the argument list for this macro, because it's a
// varargs function all arguments are stored in argument 0. */
// const ::clang::Token* token = Args->getUnexpArgument(0u);
// // All tokens for the argument are stored in sequence.
// for(; token->isNot(::clang::tok::eof); ++token)
// {
// }
}
Inside your RecursiveAstVisitor you can implement visitors that will pop off the top of the queue and check to see if the top macro is before in the translation unit. IIRC visitors of a type are all executed in order of declaration, so the queue should maintain the order. It is worth noting that all Decl's of a type are visited in order, so care has to be taken when distinguishing between function, variables, and classes.
bool MyAstVisitor::VisitFunctionDecl(::clang::FunctionDecl* const function)
{
if(::llvm::isa<::clang::CXXMethodDecl>(function))
{
// If you want to handle class member methods separately you
// can check here or implement `VisitCXXMethodDecl` and fast exit here.
}
if(ourExportTags.empty())
{
return true;
}
const ::clang::SourceLocation tagLoc = ourExportTags.front().getBegin();
const ::clang::SourceLocation declLoc = function->getBeginLoc();
if(getAstContext().getSourceManager().isBeforeInTranslationUnit(tagLoc, declLoc))
{
ourExportTags.pop_front();
// Handle export;
}
return true;
}
EDIT
I haven't used ASTMatchers before, but you could probably accomplish a similar result by writing a matcher, storing all of the declarations to a list, sorting based on location, and then comparing to the original export tag queue.
DeclarationMatcher matcher = functionDecl().bind("funcDecl");
class MyFuncMatcher : public clang::ast_matchers::MatchFinder::MatchCallback
{
public:
virtual void run(const clang::ast_matchers::MatchFinder::MatchResult& Result)
{
if(const FunctionDecl* func = Result.Nodes.getNodeAs<clang::FunctionDecl>("funcDecl"))
{
// Add to list for future processing
}
}
};
void joinTagsToDeclarations()
{
// Sort the declaration list
for(auto decl : myDeclList)
{
if(ourExportTags.empty())
{
break;
}
const ::clang::SourceLocation tagLoc = ourExportTags.front().getBegin();
const ::clang::SourceLocation declLoc = decl->getBeginLoc();
if(getAstContext().getSourceManager().isBeforeInTranslationUnit(tagLoc, declLoc))
{
ourExportTags.pop_front();
// Handle export;
}
}
}

LevelDB --- Code in C++

The below given code is taken from LevelDB. I am giving two blocks of code for better understanding. I am unable to understand what is happening.
ThreadState is a structure and I have written here to make it easy for the reader.
struct ThreadState {
int tid; // 0..n-1 when running in n threads
Random rand; // Has different seeds for different threads
Stats stats;
SharedState* shared;
ThreadState(int index)
: tid(index),
rand(1000 + index) {
}
};
Is the marked code below an object instantiation of class Benchmark? What is happening in the marked code below?
void Run() {
PrintHeader();
Open();
const char* benchmarks = FLAGS_benchmarks;
while (benchmarks != NULL) {
{
//code ommitted
}
// Reset parameters that may be overriddden bwlow
***void (Benchmark::*method)(ThreadState*) = NULL;*** // What does this code line mean? // Benchmark is a class.
bool fresh_db = false;
int num_threads = FLAGS_threads;
if (name == Slice("fillseq")) {
fresh_db = true;
method = &Benchmark::WriteSeq;
}
If required, I can give detailed implementation of Benchmark as well.
Thanks a lot for the help!
void (Benchmark::*method)(ThreadState*) = NULL;
// What does this code line mean?
// Benchmark is a class.
The above is a pointer to a member function. Since member functions are not like regular functions (they can only be called on a valid object), you cannot take their address it the same way you would for a free function.
Therefore the above syntax is introduced. It is similar to a regular function pointer except the class specifier Benchmark::. This is essentially the type of the implicit this pointer.
In your case, method is a pointer to a member function that takes ThreadState* as a parameter, and has a void return type. The reason for using it is most probably to simplify the call. First, and based on various parameters, a member function is chosen to be called, and its "address" stored in method. After all the checks are done, there is only a single call to the chosen function via the pointer to member.
Incidentally, &Benchmark::WriteSeq is how the code obtains the "address" of the member function WriteSeq. You must use the address-of operator on the qualified function name.

C++ method returns pointer to abstract class, need to use a method from the subclass

so I'm writing a compiler in C++. Currently on the scanner portion.
The method declaration inside the scanner is
Token * Scanner::next_token()
{
string * test = new string("Test");
IdToken * testToken = new IdToken(test);
return testToken;
}
The IdToken class has a method get_attribute() that returns the value of the private variable attr (which in this case is a string, the one passed in on creation). Token (the abstract class) does not have this method.
Inside the main of my testing I have this:
IdToken * testToken = testScanner->next_token();
But g++ doesn't like that, and says that it's an invalid conversion from Token* to IdToken*.
I need to turn the token returned by the method into an IdToken in order to get the attribute, since when I try to directly call get_attribute() on the token returned it tells me that Token::get_attribute() does not exist.
Not sure entirely how to go about fixing this since my knowledge of C++ inheritance and such is struggling. I did all the research I could but I couldn't find anything that I both understood and solved my problem.
Here is Scanner.cc
Scanner::Scanner (char * filename)
{
buf = new Buffer(filename);
}
//Destroy new things
Scanner::~Scanner()
{
delete buf;
}
//The huge DFA turned into code
Token * Scanner::next_token()
{
string * test = new string("Test");
IdToken * testToken = new IdToken(test);
return testToken;
}
And here is IdToken.cc
IdToken::IdToken() : Token()
{
set_token_type (TOKEN_ID);
attribute = new string("UNINITIALIZED IDENTIFIER ATTRIBUTE");
}
IdToken::IdToken (string *attr) : Token()
{
set_token_type (TOKEN_ID);
attribute = new string(*attr);
}
IdToken::~IdToken()
{ if (attribute != NULL) {
delete attribute;
}
}
string *IdToken::get_attribute() const
{
string *attr = new string(*attribute);
return attr;
}
void IdToken::set_attribute(string *attr)
{
if (attribute != NULL) {
delete attribute;
}
attribute = new string (*attr);
}
string *IdToken::to_string()
{
string *attribute_name = new string ("ID:" + *attribute);
return attribute_name;
}
And lastly token.cc
#include "token.h"
Token::Token()
{
type = TOKEN_NO_TYPE;
}
Token::~Token()
{}
void Token::set_token_type (token_type_type type)
{
this->type = type;
}
token_type_type Token::get_token_type() const
{
return type;
}
It's not nearly done, I just need help with figuring out how to access get_attribute.
Couple of options:
Create a virtual member function in Token.
virtual std::string get_attribute() const = 0;
Implement appropriately for the sub-classes of Token. Use it as:
Token * testToken = testScanner->next_token();
std::string attr = testToken->get_attribute();
Use dynamic_cast to get an IdToken* from a Token*. If the cast is successful, call get_attribute(). on the IdToken*.
Token * testToken = testScanner->next_token();
IdToken * testIdToken = dynamic_cast<IdToken*>(testToken);
if ( testIdToken )
{
std::string attr = testIdToken->get_attribute();
}
You can use a dynamic_cast
struct Token {
virtual ~Token() {}
};
struct IdToken : public Token {
int getAttribute() {return 1;}
};
int main(int argc, char** argv} {
Token* token = new IdToken();
dynamic_cast<IdToken*>(token)->getAttribute();
delete token;
}
Unfortunately, dynamic_cast tends to be rather slow and you would probably want to avoid frequent calls to it. It is safe, however. It returns a nullptr on failure. You could also use reinterpret_cast, which is faster, but isn't safe.
I personally wouldn't make a class hierarchy for the tokens. There's a relatively small set of attributes and parameters, and you could, potentially, use a union to store them, if you really have to.
But if you MUST, then use dynamic_cast to call your get_attribute:
Token* token = testScanner->next_token()
IdToken *idToken = dynamic_cast<IdToken*>(token);
if(idToken)
{
idToken->get_attribute();
}
Note that you do need the if, or your program will crash if the token you got wasn't an IdToken [or derived from an IdToken].
Oh, and dynamic_cast is not a trivial operation that takes no time at all. So avoiding it in preference for a base-class virtual function is nearly always better. My compiler uses a couple of dozen llvm::dyn_cast, for the AST that comes out of the parser, because doing a fully generic AST class that can cope with all the special cases of variable expressions, for-loops and function declarations in the same class would make a monster of a class with a few dozen virtual functions, most of which would require a single implementation for a single derived class, but a "null" value for most others - and most of the time I'd need to know what class it actually is anyway...
Here's my Token class - I'm sure there are faults there too, I'm not a compiler expert, this is my third language I've worked on, and the first one to actually compile to machine code, and I'm cheating by using llvm as the backend.
Don't do string *something = new string; use an empty or "unknown" string to mean "not yet set"
Also don't use if (pointer) delete pointer; - delete works just fine on pointers that are NULL - the redundant if is probably not removed by the compiler, since in a vanishingly small number of cases, the extra overhead of calling delete is worth saving - but not in a destructor. If you have an additional if (pointer) everywhere in a large project, it soon adds up to several thousand bytes of extra code - if the destructor then happens to be inlined, it's multiplied by the number of inlines it has, which could be quite a lot of useless code in your project. Compiler code tends to get large enough without useless bloat.

Insufficient contextual information to determine type

I've done research and I can't make sense of this message at all. Everything I find seems to be a bug with the compiler itself. I've also read somewhere 'insufficient contextual information to determine type' is not a helpful message.
My question: Does anyone have information on what this compile error message means?
I understand this question might be code specific. My code merely declares a global anonymous struct, and then once it tries to access it in a function I get this error (or so I've evaluated it).
EDIT: I got my code to compile! - But I still don't know what the error means, so I'll leave the question open.
EDIT: Here's my code, as far as I'd suppose is important:
typedef ofstream::pos_type ofilepos;
struct stack // stack is my own stack data-structure
{
// ...
// int L; struct N *l;
stack(): L(0), l(NULL) {}
}
// ...
struct
{
const char* zero;
stack<ofilepos> chunks; // it was 'chunks();' with (), and it didn't work
} _fileext = {"\0\0\0"};
// ...
ofstream& write_stack_pushsize(ofstream& f)
{
_fileext.chunks.push(new ofilepos(f.tellp()));
f.write(_fileext.zero,4);
return f;
}
I think it might have been because I was calling a constructor in a struct declaration, rather than later... or something... it could be a bug in C++03.
Regarding this code,
struct
{
const char* zero;
stack<ofilepos> chunks();
} _fileext = {"\0\0\0"};
there is no way to provide a definition of the chunks member function after the anonymous struct definition.
Considering also the following usage example,
ofstream& write_stack_pushsize(ofstream& f)
{
_fileext.chunks.push(new ofilepos(f.tellp()));
f.write(_fileext.zero,4);
return f;
}
apparently you meant to define chunks as a data member instead of as a function member.
By the way, using underscore at the start of a name can possibly conflict with names in the implementation of the standard library. E.g. these names are reserved in the global namespace (if I recall correctly). The usual convention is instead to have an underscore at the end of a name, to signify "member".
To signyfy "global" I simply use a namespace that I call g. :-)

Referencing members of an object within a class type vector

Ok guys this problem has been bugging me all day and I cant seem find a solution. I know Its a long post but I would be very grateful for any help you can offer.
I am working on a chatbot program that reads in from a .dat file to populate a library of keywords. Taking an object orientated approach I defined a class called "Keyword", the class definition is shown below:
class Keyword
{
public:
//_Word holds keyword
vector<string> _Word;
//_Resp holds strings of responses
vector<string> _Resp;
//_Antymn holds words that are the opposite to keyword
vector<string> _Antymn;
// Constructor
Keyword()
{
// Clears members when new instance created
_Word.clear();
_Resp.clear();
_Antymn.clear();
}
};
Therefore every time a new keyword is found in the .dat file, a new instance of the class keyword must be created. To store all these instances of keyword I create another vector but this time of type Keyword and call it library:
typedef vector<Keyword> Lib;
Lib library;// this is the same as saying vector<Keyword> library
Now this is the problem I have: After a user inputs a string I need to check if that string contains a keyword from the library i.e. I need to see if the string in _Word appears in the user input. Looking at it from a hierarchy of vectors you have:
The top level --> libary //*starting point
--> Keyword
--> _Word
-->"A single string" <-- I want to reference this one
--> _Resp
-->"Many strings"
--> _Antymn
-->"Many strings"
Phew! I hope that made sense.
This is the code I started to write:
size_t User::findKeyword(Lib *Library)
{
size_t found;
int count = 0;
for(count = 0; count<Library->size(); count++)
{
found = _Input.find(Library->at(count)); // this line needs to reference _Word from each keyword instance within library
if(found!= string.npos)
return found;
}
return 0;
}
I have also tried to use the "operator[]" method but that doesnt seem to do what I want either.
Does anyone have any idea ? I would be very suprised if it couldn't be done. Thank you in advance.
A bunch of issues first:
identifiers beginning with an underscore followed by a capital
letter are reserved in any namespace
the clear() call in the Keyword constructor are pointless and possibly
harmful to optimization
Why is word_ a vector? I though it is one keyword.
struct Keyword
{
// real words as identifiers, no underscores
//anywhere if they are public
std::string word;
std::vector<std::string> respones;
std::vector<std::string> antonym;
};
typedef std::vector<Keyword> Lib;
/// finding a keyword
#include <algorithm>
Lib::iterator findKeyword(const Lib& l, const std::string& x) {
return std::find_if(begin(l), end(l),
[](const Keyword& kw) { return kw.word == x; })
// if stuck on non C++11 compiler use a Functor
}
You have to change your code to this:
for(count = 0; count<Library->size(); count++)
{
for(int j = 0; j < Library->at(count)._Word.size(); ++j){
found = _Input.find(Library->at(count)._Word[j]);
^^^^^^^^^
if(found!= string.npos)
return found;
}
}
in order to access the member variable and to iterate through your vector of strings. Library->at(count) is an object of class the Keyword.
I assume that _Input.find() takes a string as argument.
If your Keyword instance stores just one keyword, you might as well change it to string _Word, so that you wold not need the second loop.
for(count = 0; count<Library->size(); count++)
{
found = _Input.find(Library->at(count)._Word);
if(found!= string.npos)
return found;
}
And to enforce the other comments: you should not use the preliminary _-underscore in your variable names since they are reserved by the implementation.