I'm trying to find the if-conditions in a C-code using Clang.
What I've learned till now is to find the declarations using HandleTopLevelDecl().
What I'm trying to do now is to find a function that is similar to HandleTopLevelDecl() but handles the If-Conditions.
My question is, am I on the right path? is there a function that can do this?
And if not, what do you advice me to do?
Thanks.
With the help of this awesome course: http://swtv.kaist.ac.kr/courses/cs453-fall13
Specially this tutorial: http://swtv.kaist.ac.kr/courses/cs453-fall13/Clang%20tutorial%20v4.pdf
I have solved the problem.
I needed to create a RecursiveASTVisitor and handle the If-Statements while visiting the Statements.
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
bool VisitStmt(Stmt *s) {
// Search for If-Statements
if(isa<IfStmt>(s))
{
cerr << "Found IF" << endl;
}
return true;
}
bool VisitFunctionDecl(FunctionDecl *f) {
// Print function name
cerr << f->getNameAsString().c_str() << endl;
return true;
}
};
And here are the complete code:
#include <cstdio>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <utility>
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace std;
// CompilerInstance
CompilerInstance TheCompInst;
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
bool VisitStmt(Stmt *s) {
// Search for If-Statements
if(isa<IfStmt>(s))
{
SourceManager &srcmgr = TheCompInst.getSourceManager();
SourceLocation startLocation = s->getLocStart();
unsigned int start_lineNum = srcmgr.getExpansionLineNumber(startLocation);
cerr << "Found IF # Line: " << start_lineNum << endl;
}
return true;
}
bool VisitFunctionDecl(FunctionDecl *f) {
// Print function name
cerr << f->getNameAsString().c_str() << endl;
return true;
}
};
class MyASTConsumer : public ASTConsumer
{
public:
MyASTConsumer()
: Visitor() //initialize MyASTVisitor
{}
virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
// Travel each function declaration using MyASTVisitor
Visitor.TraverseDecl(*b);
}
return true;
}
private:
MyASTVisitor Visitor;
};
int main(int argc, char *argv[])
{
if (argc != 2) {
llvm::errs() << "Usage: kcov-branch-identify <filename>\n";
return 1;
}
// Diagnostics manage problems and issues in compile
TheCompInst.createDiagnostics(NULL, false);
// Set target platform options
// Initialize target info with the default triple for our platform.
TargetOptions *TO = new TargetOptions();
TO->Triple = llvm::sys::getDefaultTargetTriple();
TargetInfo *TI = TargetInfo::CreateTargetInfo(TheCompInst.getDiagnostics(), TO);
TheCompInst.setTarget(TI);
// FileManager supports for file system lookup, file system caching, and directory search management.
TheCompInst.createFileManager();
FileManager &FileMgr = TheCompInst.getFileManager();
// SourceManager handles loading and caching of source files into memory.
TheCompInst.createSourceManager(FileMgr);
SourceManager &SourceMgr = TheCompInst.getSourceManager();
// Prreprocessor runs within a single source file
TheCompInst.createPreprocessor();
// ASTContext holds long-lived AST nodes (such as types and decls) .
TheCompInst.createASTContext();
// A Rewriter helps us manage the code rewriting task.
Rewriter TheRewriter;
TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts());
// Set the main file handled by the source manager to the input file.
const FileEntry *FileIn = FileMgr.getFile(argv[1]);
SourceMgr.createMainFileID(FileIn);
// Inform Diagnostics that processing of a source file is beginning.
TheCompInst.getDiagnosticClient().BeginSourceFile(TheCompInst.getLangOpts(),&TheCompInst.getPreprocessor());
// Create an AST consumer instance which is going to get called by ParseAST.
MyASTConsumer TheConsumer;
// Parse the file to AST, registering our consumer as the AST consumer.
ParseAST(TheCompInst.getPreprocessor(), &TheConsumer, TheCompInst.getASTContext());
return 0;
}
There are specific functions in clang for all kinds of Stmts and Decls. For this particular case, it is going to be VisitIfStmt. Check IfStmt being included in RecusiveASTVisitor.h.
RecursiveASTVisitor.h -
#define STMT(CLASS, PARENT) \
bool WalkUpFrom##CLASS(CLASS *S) { \
TRY_TO(WalkUpFrom##PARENT(S)); \
TRY_TO(Visit##CLASS(S)); \
return true; \
} \
bool Visit##CLASS(CLASS *S) { return true; }
#include "clang/AST/StmtNodes.inc"
clang/AST/StmtNodes.inc -
#ifndef IFSTMT
# define IFSTMT(Type, Base) STMT(Type, Base)
#endif
IFSTMT(IfStmt, Stmt)
#undef IFSTMT
These, together create the function VisitIfStmt(IfStmt*) in the class.
Related
Scenario: I have two classes, each contains a pointer to the other (when using them, being able to refer to the other is going to be important so I deemed this appropriate). When I try accessing a private variable from one class via using the pointer to the other and a getter function inside that, it works perfectly.
Problem: Using a setter (in this case, addPoints)/manipulating the variables however leads to no result.
I'm new so anything here might be "improper etiquette" and bad practice. Feel free to point them out! But please also try to provide a solution. This is also my first question on SO, so please be gentle!
Related code pieces:
Team.h
#include "Driver.h"
using namespace std;
class Team {
int Points = 0;
vector<Driver*> Drivers;
public:
void addPoints(int gained); //does not work
int getPoints(); //works perfectly
Driver getDriver(int nr);
void setInstance(vector<Driver*> drivers);
};
Team.cpp
#include "Team.h"
#include "Driver.h"
using namespace std;
void Team::addPoints(int gained) {
this->Points = this->Points + gained;
}
int Team::getPoints() {
return this->Points;
}
Driver Team::getDriver(int nr) {
return *Drivers[nr];
}
void Team::setInstance(vector<Driver*> drivers) {
this->Drivers = drivers;
}
Driver.h
using namespace std;
class Team;
class Driver {
int Points = 0;
Team* DriversTeam;
public:
void SetTeam(Team& team);
Team getTeam();
int getPoints(); //works
void addPoints(int gained); //doesn't work
};
Driver.cpp
#include "Driver.h"
#include "Team.h"
using namespace std;
void Driver::SetTeam(::Team& team) {
this->DriversTeam = &team;
}
Team Driver::getTeam() {
return *DriversTeam;
}
int Driver::getPoints() {
return this->Points;
}
void Driver::addPoints(int gained) {
this->Points = this->Points + gained;
}
Initializer.cpp (linking drivers to teams)
void InitializeData(vector<Team>& teams, vector<Driver> &drivers) {
//(...)
//reads each team in from data file to memory
//key part:
vector<Driver*> teamsDrivers;
for (auto& iter : drivers) { //this loop mainly determines which driver to link with which teams
if (iter.getName().compare(values[4]) == 0) { //values is csv line data in a string vector. I guess not the prettiest parsing method here but will be revised
teamsDrivers.push_back(&iter);
}else if(iter.getName().compare(values[5]) == 0) {
teamsDrivers.push_back(&iter);
}
}
tempTeam.setInstance(teamsDrivers);
teams.push_back(tempTeam);
}
(linking driver to team)
//drivers are linked to teams last, as they are declared first (so I cannot link them to the yet nonexisting teams)
void LinkTeam(vector<Driver>& drivers, vector<Team>& teams) {
for (auto& driverIter : drivers) { //iterate through drivers
for (auto& teamIter : teams) { // iterate through teams
bool found = 0;
for (size_t i = 0; i < teamIter.DriverAmount(); i++) {
if (driverIter.getName() == teamIter.getDriver(i).getName()) {
driverIter.SetTeam(teamIter);
found = 1;
break;
}
}
if (found) { //exit iterating if driver is found
break;
}
}
}
}
Example of use in main.cpp
teams[0].addPoints(10);
drivers[3].getTeam().addPoints(15); //driver 3 is linked to team 0
cout << teams[0].getPoints(); //15
cout << drivers[3].getTeam().getPoints(); //15
teams[0].getDriver(1).addPoints(20); //driver 1 of team 0=driver[3]
drivers[3].addPoints(25);
cout << drivers[3].getPoints(); //25
cout << teams[0].getDriver(1).getPoints(); //25
Thanks for the help in advance.
This is quite simple:
Your getTeam() and getDriver() functions are returning copies of the objects, not references, so the addPoints() are performed on temporary copies and not the real ones.
To fix it, simply change the return types to references (add &):
Team& getTeam();
and
Driver& getDriver();
I've been writing some code to try and model some kind of taxi service, but I've run into a bit of an issue.
I have a class RunServer, which looks at the state of commands given by the user (src::control::Global::stat_commandPath) and asks for additional input based on those commands before doing something with that input.
The problem is that I'm getting an "error: expected type-specifier" (GCC-7.3.0, C++11) and it looks like it might have something to do with how I've namespaced the classes. If namespace declarations are removed from src/Vehicle/Car.h, then this problem stops happening.
This is should be all the relevant code for this issue. Sorry there's so much of it, I've truncated everything that doesn't look like it has an impact. The problem is with src/control/RunServer.h lines 66, 70, and 74. src/vehicle/Pickup.h and src/vehicle/Van.h have the same structure as src/vehicle/Car.h.
src/control/Global.h
#ifndef INCLUDED_src_control_Global_h
#define INCLUDED_src_control_Global_h
#include <string>
#include "../vehicle/Vehicle.h"
namespace src {
namespace control {
class Global final
{
virtual void instantiable() = 0;
private:
static size_t
stat_vehicleArrayLength;
static src::Vehicle
** stat_vehicleArray;
public:
static std::string
stat_commandPath,
stat_stdcoutEnd;
public:
static bool
// Deletes the pointer argument if adding fails.
add_vehicle(
src::Vehicle *
),
exists_vehicle(
std::string
),
remove_vehicle(
std::string
);
static size_t
get_vehicleAmount(),
position_vehicle(
std::string
);
static src::Vehicle
** get_vehicles();
};
}}
#endif
src/control/RunServer.cpp
#include <iostream>
#include <stdlib.h> // exit()
#include <string>
#include <regex>
#include "../../lib/StringTools.h"
#include "../vehicle/Car.h"
#include "../vehicle/Pickup.h"
#include "../vehicle/Van.h"
#include "../vehicle/VehicleType.h"
#include "../person/Driver.h"
#include "../person/Passenger.h"
#include "Global.h"
#include "RunServer.h"
inline bool
src::control::RunServer::navigation(
std::string input)
{
if (input == "return")
{
src::control::Global::stat_commandPath.pop_back();
return true;
}
if (input == "exit")
{
exit(0);
return true;
}
return false;
}
void
src::control::RunServer::run()
{
std::string input;
// "0" ~ Create...
// "00" ~ Create > Vehicle...
// "000" ~ Create > Vehicle > Car
// "001" ~ Create > Vehicle > Pickup
// "002" ~ Create > Vehicle > Van
// "01" ~ Create > Person...
// "010" ~ Create > Person > Driver
// "011" ~ Create > Person > Passenger
// "1" ~ Destroy...
// "10" ~ Destroy > Vehicle
// "11" ~ Destroy > Passenger
// "2" ~ Print
if (src::control::Global::stat_commandPath == "000" || src::control::Global::stat_commandPath == "001" || src::control::Global::stat_commandPath == "002")
{
// Create > Vehicle > (Car|Pickup|Van).
std::cout << "\n";
std::cout << "<vehicle identification (char array)>" << src::control::Global::stat_stdcoutEnd;
getline(std::cin, input);
if (src::control::RunServer::navigation(input))
{
return;
}
if (std::regex_match(input, std::regex("\\w+")))
{
if (src::control::Global::stat_commandPath.back() == '0' && !src::control::Global::add_vehicle(new src::vehicle::Car(input)))
{
std::cout << "\nA vehicle with this identifier already exists!\n";
}
else if (src::control::Global::stat_commandPath.back() == '1' && !src::control::Global::add_vehicle(new src::vehicle::Pickup(input)))
{
std::cout << "\nA vehicle with this identifier already exists!\n";
}
else if (src::control::Global::stat_commandPath.back() == '2' && !src::control::Global::add_vehicle(new src::vehicle::Van(input)))
{
std::cout << "\nA vehicle with this identifier already exists!\n";
}
else
{
std::cout << "\nAn error occured!\n";
}
}
}
}
src/vehicle/Car.h
#ifndef INCLUDED_src_vehicle_Car_h
#define INCLUDED_src_vehicle_Car_h
#include <string>
#include "Vehicle.h"
namespace src {
namespace vehicle {
class Car final : public src::Vehicle
{
void instantiable() override {};
public:
Car();
Car(
std::string
);
int
canAddPassenger(
src::person::Passenger *
) override;
};
}}
#endif
This is completely wrong:
static bool
// Deletes the pointer argument if adding fails.
add_vehicle(
src::Vehicle *
),
exists_vehicle(
std::string
),
remove_vehicle(
std::string
);
What are you trying to accomplish here? Isn't this supposed to be 3 independent prototypes?
static bool
// Deletes the pointer argument if adding fails.
add_vehicle(
src::Vehicle *
);
static bool exists_vehicle(
std::string
);
static bool remove_vehicle(
std::string
);
Issue appears to be related to case. It seems like namespace lookup is not case sensitive while namespace declaration is. Changing the namespace of src::vehicle::Car to src::avehicle::Car fixed the issue.
I am trying to implement a SystemC basic TLM test bench for an adder module I created using basic simple_initiator_socket and simple_target_socket.
Currently the build is failing and I am having trouble diagnosing why.
Here are the implementations for the three main modules, the adder, the test bench, and the main module that instantiates both and initiates dataflow.
main.cc
#include "systemc.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
#include "tlm_utils/tlm_quantumkeeper.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "test_bench.h"
#include "adder.h"
SC_MODULE(Top)
{
test_bench *tb;
adder *ad;
sc_signal<bool> rst;
Top(sc_module_name name) :
rst("rst")
{
tb = new test_bench("test_bench");
ad = new adder("adder");
tb->socket.bind(ad->socket);
}
};
int sc_main(int argc, char *argv[])
{
Top *top = new Top("Top");
}
test_bench.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
using namespace sc_dt;
#include "test_bench.h"
#include <fstream>
#include <iostream>
test_bench::test_bench(sc_module_name name):
sc_module(name), socket("socket")
{
SC_THREAD(run_tests);
}
void test_bench::run_tests()
{
ifstream infile("../adder.golden.dat");
ofstream ofs;
ofs.open("../adder.dat", ofstream::out | ofstream::app);
while(infile >> data[0] >> data[1])
{
tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload;
sc_time delay = sc_time(10, SC_NS);
trans->set_data_ptr((unsigned char*)data);
socket->b_transport(*trans, delay);
ofs << data[0] << data[1] << data[2];
delete trans;
}
infile.close();
ofs.close();
printf ("Comparing against output data \n");
if (system("diff -w sha1.dat sha1.golden.dat"))
{
cout << "*******************************************" << endl;
cout << "FAIL: Output DOES NOT match the golden output" << endl;
cout << "*******************************************" << endl;
}
else
{
cout << "*******************************************" << endl;
cout << "PASS: The output matches the golden output!" << endl;
cout << "*******************************************" << endl;
}
}
adder.cc
#define SC_INCLUDE_DYNAMIC_PROCESS
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace std;
#include "adder.h"
adder::adder(sc_module_name name)
: sc_module(name), socket("socket")
{
socket.register_b_transport(this, &adder::b_transport);
socket.register_transport_dbg(this, &adder::transport_dbg);
}
void adder::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay)
{
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 addr = trans.get_address();
uint32_t *ptr = (uint32_t*)trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
addend1 = *ptr;
addend2 = *(ptr++);
add();
memcpy(ptr + sizeof(uint32_t) * 2, (char*) &sum, sizeof(uint32_t));
}
unsigned int adder::transport_dbg(tlm::tlm_generic_payload& trans)
{
return 0;
}
void adder::add()
{
sum = addend1 + addend2;
}
Here is the error I am seeing upon compilation.
In file included from
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:35:0,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/systemc:74,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/tlm:23,
from /home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/tlm_utils/simple_initiator_socket.h:23,
from /home/test_benches/adder/test_bench.cc:3:
/home/test_benches/adder/test_bench.cc:
In constructor ‘test_bench::test_bench(sc_core::sc_module_name)’:
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:463:29:
error: ‘SC_CURRENT_USER_MODULE’ has not been declared
SC_CURRENT_USER_MODULE, \
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_process.h:151:46: note: in definition of macro ‘SC_MAKE_FUNC_PTR’
static_cast(&callback_tag::func)
/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include/sysc/kernel/sc_module.h:461:5:
note: in expansion of macro ‘declare_thread_process’
declare_thread_process( func ## _handle, \
/home/test_benches/adder/test_bench.cc:17:2: note: in expansion of
macro ‘SC_THREAD’ SC_THREAD(run_tests);
make: ***
[/home//test_benches/adder/obj/test_bench.o]
Error 1
My best guess is that I did not set up the sockets correctly. The test bench has a simple_initiator_socket and the adder has a simple_target_socket. Do I need to register the simple_target_socket with a b_transport method for the module? I did so in the initiator but in the tutorial below I did not see a requirement to do so for the target. My guess was the dataflow was like this:
simple_initiator_socket (member of test_bench) registered to b_transport method of module and simple_target_socket of another module (in top module)
Initiator module (test_bench) sets up tlm_generic_payload with data it needs to send to target (adder)
b_transport method of simple_initiator_socket (member of test_bench) called with tlm_generic_payload being passed (with addends for adder)
Target socket (target) receives and decodes tlm_generic_payload (addend values) that was passed.
Target socket (adder) performs operations (adds decoded addends) and modifies the tlm_generic_payload (passed by value) (by writing the computed sum back to the payload memory)
Initiator (test_bench) looks at modified tlm_generic_payload (now contains sum) and does some process (checks against theoretical sum)
I was trying to follow this example.
https://www.doulos.com/knowhow/systemc/tlm2/tutorial__1/
UPDATE
test_bench.h
class test_bench:
public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<test_bench> socket;
sc_out<bool> irq;
test_bench(sc_core::sc_module_name name);
void run_tests();
private:
uint32_t data[3];
};
There are two ways to declare modules in SystemC.
The first one is through using SC_MODULE macro:
SC_MODULE(mymodule) {
SC_CTOR(mymodule)
{
}
};
And the second one without it:
class mymodule : public sc_core::sc_module {
SC_HAS_PROCESS(mymodule);
public:
mymodule(sc_core::sc_module_name)
{ }
};
I would prefer the second one because:
It avoids those nasty macros as much as possible.
It allows you to inherit from another module.
Now why you need SC_MODULE or SC_HAS_PROCESS macros. The reason is that macros SC_METHOD and SC_THREAD need to know type of module they are being used from to do their job. Since SystemC is based on old revision of C++ language released in 1998, there was no way to do this automatically. So helper macro SC_HAS_PROCESS was defined as:
#define SC_HAS_PROCESS(user_module_name) typedef user_module_name SC_CURRENT_USER_MODULE
This allows SC_METHOD and SC_THREAD to use SC_CURRENT_USER_MODULE as synonym for module they are being used in. Macro SC_MODULE already uses SC_HAS_PROCESS behind the curtain.
Another advise - if you are using C++11 compatible compiler you can declare a helper macro for yourself:
#define DECL(name, ...) name{#name, __VA_ARGS__}
This can help you declare named objects without typing their name twice:
sc_in<bool> DECL(clk);
Any error message mentioning this port with contain proper name for it.
Can also be used in constructor to initialize member field:
mymodule(sc_core::sc_module_name)
: DECL(clk)
{
}
So I am not sure why I am getting this error when in the .h files it was defined that format was a Parser*. The compiler tells me that in the method Parser::changeformat(int) I cannot convert an int* to a Parser* pointer(the cpp files aren't done yet so please ignore all the other methods if they throw errors or look weird). Why is this happening and how can I fix it. This may have something to do with inheritance so I'll point out a subclass of parser that would fit. Also, in any case if you have suggestions about other parts then be my guest.
Parser.h
#ifndef PARSER_H_
#define PARSER_H_
#include <string>
#include <iostream>
#include <fstream>
/*
* This is a parser for reading and writing files
* it takes in an integer for the file type it should read
* or none if you would like to change it later and reuse
* the parser
*/
class Parser {
public:
Parser();
Parser(int);
virtual ~Parser();
void open();
bool open(std::string&);
bool read();
bool write();
bool close();
void changeformat(int);
private:
int filetype = -1;
Parser* format = 0;
};
#endif /* PARSER_H_ */
Parser.cpp
#include "Parser.h"
Parser::Parser()
{
filetype = -1;
}
Parser::Parser(int filetype)
{
switch(filetype)
{
case 0:
{
//load xml format via instantiating xmlpar subclass and overloading methods
break;
}
case 1:
{
//load txt format
break;
}
}
}
Parser::~Parser()
{
if(this->format)
delete this->format;// TODO Auto-generated destructor stub
}
//the classes below are to be overloaded with a subclass's own method
void Parser::open()
{
return;
}
bool Parser::open(std::string& filename)
{
if(this->format->open(filename))
{
std::cout<<"OK: "+filename+" opened\n";
return true;
}
else
{
std::cout<<"Error: "+filename+" unable to be opened\n";
return false;
}
}
bool Parser::read()
{
//make failure checks for all past open in this cpp
return this->format->read();
}
bool Parser::write()
{
return this->format->write();
}
bool Parser::close()
{
return this->format->close();
}
void Parser::changeformat(int)
{
switch(filetype)
{
case -1:
break;
case 0:
{
this->format = new xmlpar();
break;
}
case 1:
{
//load txt format
break;
}
}
}
xmlpar.h
/*
* xmlpar.h
*
* Created on: Jul 22, 2015
* Author: root
*/
#ifndef XMLPAR_H_
#define XMLPAR_H_
#include "Parser.h"
#include <fstream>
#include <string>
class xmlpar: public Parser{
public:
xmlpar();
virtual ~xmlpar();
bool open(std::string&);//opens a stream and checks association
bool read(std::fstream&);//creats dom tree and hands it forward via reference
bool write(std::fstream&);//edits domtree but does not write to the physical file
bool close(std::fstream&);//the dom tree is flushed, the fstream associated to the file is closed and everyone is happy... I think
private:
std::fstream *file= 0;
bool flush();//write dom tree in memory to physical file
};
#endif /* XMLPAR_H_ */
xmlpar.cpp
/*
* xmlpar.cpp
*
* Created on: Jul 22, 2015
* Author: root
*/
#include "xmlpar.h"
xmlpar::xmlpar()
{
}
bool xmlpar::open(std::string& filename)
{
file = new std::fstream(filename, std::ios::in|std::ios::out);
return file->good();
}
bool xmlpar::close(std::fstream &file)
{
this->write(file);
file->close();
//write failcheck here
}
xmlpar::~xmlpar() {
this->close(file);
}
You are trying to instantiate an instance of xmlpar that is derived from Parser base class without including headers of derived class xmlpar at Parser.cpp. The compiler is not finding definition for xmlpar here:
this->format = new xmlpar();
I also doubt this is a good practice.
I am trying to implement a simple protocol for sending emails. Till, now I implemented four commands and a server class that receives all the commands and check whether the commands are in the right order. However, when I am creating an instance of the server class, it shows an error: SMTPServer was not declared in this scope.I don't know what else to do. Any help is appreciated as I can't complete my program without solving this error.
SMTPServer header file:
#include <string>
#include <iostream>
#include "HELO.h"
using namespace std;
#ifndef HELO_H_INCLUDED
#define HELO_H_INCLUDED
class SMTPServer
{
public: SMTPServer();
private: string newMessage;
private: string newRec;
private: string newSender;
private: string newData;
// overload constructor
// public: SMTPServer(string, string, string, string);
void SMTPServer:: send(HELO h1);
};
#endif // HELO_H_INCLUDED
SMTPServer cpp
#include "SMTPServer.h"
SMTPServer::SMTPServer()
{
newMessage = NULL;
newRec = NULL;
newSender = NULL;
newData = NULL;
};
void SMTPServer:: send(HELO h1)
{
}
Main class
#include <iostream>
#include <string>
#include "SMTPServer.h"
using namespace std;
int main() {
string mes;
string rec;
string sen;
string dat;
SMTPServer test;
//cout << endl << "HELO message: " << test.send() << endl;
return 0;
}
Thanks in advance.
Looks to me like you've reused the include guards from HELO.h in SMTPServer.h. That is, they should be changed to something like:
#ifndef SMTPSERVER_H_INCLUDED
#define SMTPSERVER_H_INCLUDED
...
#endif
If you use the same include guards in both, only one of them can ever be included in another file. And in fact, SMTPServer.h itself includes HELO.h, so instantly makes its own content never get past the preprocessing stage.
If it's not clear yet, just read the top of SMTPServer.h:
#include <string>
#include <iostream>
#include "HELO.h"
using namespace std;
#ifndef HELO_H_INCLUDED
So we're checking if HELO_H_INCLUDED is defined. Since it just included HELO.h, and that file presumably defines HELO_H_INCLUDED, we'll always say "Yes, it is defined!". We'll never use the content of this #ifndef.
You can initialize string as below:
SMTPServer::SMTPServer()
{
newMessage = "";
newRec = "";
newSender = "";
newData = "";
}
Change code below:
void SMTPServer:: send(HELO h1);
to
void send(HELO h1);
Remove Semicolon after:
SMTPServer::SMTPServer()
{
newMessage = NULL;
newRec = NULL;
newSender = NULL;
newData = NULL;
};