boost string type mismatch - c++

In the followring code,
class MonitorResult {
public:
void putDir(std::string && dir) { }
};
void listDir(boost::filesystem::path && dir, MonitorResult & result) {
for(boost::filesystem::directory_iterator it(dir);
it != boost::filesystem::directory_iterator(); ++it) {
if(boost::filesystem::is_symlink( it->path()) ) {
continue;
}
else if(boost::filesystem::is_directory(it->path())) {
result.putDir(it->path().string() ); // Error here
}
}
}
error: no matching function for call to MonitorResult::putDir(const string&)
candidate is void MonitorResult::putDir(std::string&&)
I am not getting std::string, but just string. How can type error be resolved? Thanks.

Related

error: call of overloaded 'basic_ofstream(int)' is ambiguous

std::shared_ptr<std::ostream> out_stream(const std::string &fname)
{
if (fname.length() > 0)
{
if ((fname.compare("stderr") == 0) || (fname.compare("cerr") == 0))
{
std::shared_ptr<std::ostream> p(&std::cerr, [](std::ostream*){});
return p;
}
if ((fname.compare("stdout") == 0) || (fname.compare("cout") == 0))
{
std::shared_ptr<std::ostream> p(&std::cout, [](std::ostream*){});
return p;
}
if ((fname.compare("null") == 0) || (fname.compare("/dev/null") == 0))
{
std::shared_ptr<std::ostream> p(new std::ofstream(0));//<<<<<<<<<<<<<<<<<<<<<
}
std::shared_ptr<std::ostream> p(new std::ofstream(fname));
io_utils_logger.log(utils::LogLevel::FILE, "opening a file ", fname, "\n");
return p;
}
else
{
std::shared_ptr<std::ostream> p(new std::ostream(std::cout.rdbuf()));
return p;
}
}
In the above source code, in the marked line, new std::ofstream(0) is showing the following error:
error: call of overloaded 'basic_ofstream(int)' is ambiguous
std::shared_ptr<std::ostream> p(new std::ofstream(0));
^
How can I fix it?

Is there an elegant way to traverse Clang AST Statements?

I am trying to traverse all function definitions and extract information from them. I have to iterate over all statements in the function body, and depending on the type, execute a specific function.
For the moment I have an ugly if-else block. Is there a more elegant way to do this?
void FunctionMatcher::processStatement(const clang::Stmt *statement) {
string type = statement->getStmtClassName();
if (type == "ReturnStmt") {
auto rs = dyn_cast<const ReturnStmt *>(statement);
processReturnStmt(rs);
} else if (type == "WhileStmt") {
auto ws = dyn_cast<WhileStmt>(statement);
processWhileStmt(ws);
} else if (type == "ForStmt") {
auto fs = dyn_cast<const ForStmt *>(statement);
processForStmt(fs);
} else if (type == "IfStmt") {
auto is = dyn_cast<const IfStmt *>(statement);
processIfStmt(is);
} else if (type == "SwitchStmt") {
auto ss = dyn_cast<const SwitchStmt *>(statement);
processSwitchStmt(ss);
} else if (type == "CompoundStmt") {
auto cs = dyn_cast<const CompoundStmt *>(statement);
for (auto child : cs->children())
processStatement(child);
} else {
// ...
}
By navigating through the code of clang::TextNodeDumper, I found a solution.
Apparently Clang has its own visitors for statements, declarations etc...
Simple example:
class StatementVisitor : public ConstStmtVisitor<StatementVisitor> {
public:
StatementVisitor();
void Visit(const Stmt *Node) {
ConstStmtVisitor<StatementVisitor>::Visit(Node);
}
void VisitIfStmt(const IfStmt *Node) {
llvm::outs() << " An if statement yay!\n";
}
void VisitWhileStmt(const WhileStmt *Node) {
llvm::outs() << " A While statement yay!\n";
}
};
you can use RecursiveASTVisitor
its traverse all statement in given code, recursively
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
bool VisitFunctionDecl(FunctionDecl* f)
{
...
}
bool VisitIfStmt(IfStmt* IF)
{
...
}
bool VisitForStmt(ForStmt* FS)
{
...
}
bool VisitWhileStmt(WhileStmt* WS)
{
...
}
}

Segmentation fault driven of a null reference in a c++ header file

Can anyone find out what is wrong with the following part of code:
private:
TUcdFileReader& operator = (const TUcdFileReader& r) { Fail; return *((TUcdFileReader *) 0); }
TUcdFileReader(const TUcdFileReader& r) { Fail; }
This belongs to a header file in a c library (SNAP) which I use in my code. When I compile my code in a linux based system, the below warning shows up:
Snap-2.1/glib-core/unicode.h(1678): warning #327: NULL reference is not allowed
TUcdFileReader& operator = (const TUcdFileReader& r) { Fail; return *((TUcdFileReader *) 0); }
Which in overall lead me to a segmentation fault as follows: (and I suspect it is because of the above warning)
WARNING: Job died due to SIGSEGV - Invalid memory reference
I dont write the whole header file since it is long and makes confusion, but it is the address of it: http://snap.stanford.edu/snap/doc/snapuser-ref/dd/d90/unicode_8h_source.html
Here I wrote the bigger part of header file that uses TUcdFileReader:
protected:
class TUcdFileReader
{
protected:
TChA buf;
public:
TChA comment; // contains '#' and everything after it
protected:
FILE *f;
int putBackCh;
int GetCh() {
if (putBackCh >= 0) { int c = putBackCh; putBackCh = EOF; return c; }
return fgetc(f); }
void PutBack(int c) { Assert(putBackCh == EOF); putBackCh = c; }
// Returns 'false' iff the EOF was encountered before anything was read.
bool ReadNextLine() {
buf.Clr(); comment.Clr();
bool inComment = false, first = true;
while (true) {
int c = GetCh();
if (c == EOF) return ! first;
else if (c == 13) {
c = GetCh(); if (c != 10) PutBack(c);
return true; }
else if (c == 10) return true;
else if (c == '#') inComment = true;
if (! inComment) buf += char(c);
else comment += char(c); }
/*first = false;*/}
private:
TUcdFileReader& operator = (const TUcdFileReader& r) { Fail; return *((TUcdFileReader *) 0); }
TUcdFileReader(const TUcdFileReader& r) { Fail; }
public:
TUcdFileReader() : f(0) { }
TUcdFileReader(const TStr& fileName) : f(0), putBackCh(EOF) { Open(fileName); }
void Open(const TStr& fileName) { Close(); f = fopen(fileName.CStr(), "rt"); IAssertR(f, fileName); putBackCh = EOF; }
void Close() { putBackCh = EOF; if (f) { fclose(f); f = 0; }}
~TUcdFileReader() { Close(); }
bool GetNextLine(TStrV& dest) {
dest.Clr();
while (true) {
if (! ReadNextLine()) return false;
TStr line = buf; line.ToTrunc();
if (line.Len() <= 0) continue;
line.SplitOnAllCh(';', dest, false);
for (int i = 0; i < dest.Len(); i++) dest[i].ToTrunc();
return true; }}
static int ParseCodePoint(const TStr& s) {
int c; bool ok = s.IsHexInt(true, 0, 0x10ffff, c); IAssertR(ok, s); return c; }
static void ParseCodePointList(const TStr& s, TIntV& dest, bool ClrDestP = true) { // space-separated list
if (ClrDestP) dest.Clr();
TStrV parts; s.SplitOnWs(parts);
for (int i = 0; i < parts.Len(); i++) {
int c; bool ok = parts[i].IsHexInt(true, 0, 0x10ffff, c); IAssertR(ok, s);
dest.Add(c); } }
static void ParseCodePointRange(const TStr& s, int& from, int &to) { // xxxx or xxxx..yyyy
int i = s.SearchStr(".."); if (i < 0) { from = ParseCodePoint(s); to = from; return; }
from = ParseCodePoint(s.GetSubStr(0, i - 1));
to = ParseCodePoint(s.GetSubStr(i + 2, s.Len() - 1)); }
};
Further, the only place that TUcdFileReader is called :
class TSubcatHelper
{
public:
bool hasCat; TUniChSubCategory subCat;
TStrH invalidCatCodes;
TUniChDb &owner;
TSubcatHelper(TUniChDb &owner_) : owner(owner_) { }
void ProcessComment(TUniChDb::TUcdFileReader &reader)
{
....
The class TUcdFileReader is specifically defined as NOT having assignment or copy constructors, i.e.
private:
TUcdFileReader& operator = (const TUcdFileReader& r)
{ Fail; return *((TUcdFileReader *) 0); }
TUcdFileReader(const TUcdFileReader& r) { Fail; }
looks like they are meant to fail.
Somewhere in the code they are being called - if you replacing those with:
private:
TUcdFileReader& operator = (const TUcdFileReader& r); //**not implemented**
TUcdFileReader(const TUcdFileReader& r); //**not implemented**
then you'd get a linker error. Best fix would be (if possible) to implement them.

Building a math expression evaluator

I can't use boost::spirit in my environment. But I would like to use STL and boost as much as possible to build my own expression evaluator. Is there such an alternative to boost::spirit?
The following code includes unit tests and a complete parser I wrote in an about 90 minute session at ACCU 200x (8 or 9). If you need more, it might be easy enough to extend. You can make it do doubles by defining Parse::value_type, or extracting it into a separate header file and make it a template class.
Or you can take the test cases and try yourself. (it uses CUTE from http://cute-test.com)
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
#include <cctype>
#include <map>
namespace {
class Parser {
typedef int value_type;
typedef std::vector<value_type> valuestack;
typedef std::vector<char> opstack;
typedef std::map<std::string,value_type> memory;
public:
memory variables;
private:
void evaluateSingleOperator(char op,value_type &result,value_type operand) {
switch(op) {
case '+': result += operand; break;
case '-': result -= operand; break;
case '*': result *= operand; break;
case '/': result /= operand; break;
default: throw("invalid operand");
}
}
void evaluateStacks(valuestack &values, opstack &ops) {
while(ops.size() && values.size()>1) {
char op = ops.back(); ops.pop_back();
value_type operand = values.back(); values.pop_back();
evaluateSingleOperator(op,values.back(),operand);
}
}
bool higherPrecedenceOrLeftAssociative(char last, char current) {
return (last == current)||(last == '*' || last == '/') ;
}
bool shouldEvaluate(char op,opstack const &ops) {
return ops.size() > 0 && higherPrecedenceOrLeftAssociative(ops.back(),op);
}
std::string parseVariableName(std::istream &is) {
std::string variable;
char nextchar=0;
while ((is >> nextchar) && isalpha(nextchar)) {
variable += nextchar;
}
if (variable.size() == 0) throw std::string("internal parse error");
is.unget();
return variable;
}
int peekWithSkipWhiteSpace(std::istream &is) {
int nextchar = EOF;
while(isspace(nextchar = is.peek())) is.get();
return nextchar;
}
value_type getOperand(std::istream &is) {
int nextchar = peekWithSkipWhiteSpace(is);
if (nextchar == EOF) throw std::string("syntax error operand expected");
if (isdigit(nextchar)){
value_type operand=0;
if (!(is >> operand)) throw std::string("syntax error getting number") ;
return operand;
} else if ('(' == nextchar) {
is.get();
return parse(is);
} else if (isalpha(nextchar)) {
std::string variable= parseVariableName(is);
if( parseAssignmentOperator(is)) {
variables[variable] = parse(is);
} else {
if (!variables.count(variable)) throw std::string("undefined variable: ")+variable;
}
return variables[variable];
}
throw std::string("syntax error");
}
bool parseAssignmentOperator(std::istream &is) {
int nextchar = peekWithSkipWhiteSpace(is);
if ('=' != nextchar) {
return false;
}
is.get();
return true;
}
public:
value_type parse(std::istream &is) {
is >> std::skipws;
valuestack values;
opstack ops;
values.push_back(getOperand(is));
char op=')';
while((is >>op) && op != ')') {
if (shouldEvaluate(op, ops)) {
evaluateStacks(values, ops);
}
values.push_back(getOperand(is));
ops.push_back(op);
}
evaluateStacks(values,ops);
return values.back();
}
value_type eval(std::string s) {
std::istringstream is(s);
return parse(is);
}
};
int eval(std::string s) {
return Parser().eval(s);
}
void shouldThrowEmptyExpression() {
eval("");
}
void shouldThrowSyntaxError() {
eval("()");
}
void testSimpleNumber() {
ASSERT_EQUAL(5,eval("5"));
}
void testSimpleAdd() {
ASSERT_EQUAL(10,eval("5 +5"));
}
void testMultiAdd() {
ASSERT_EQUAL(10,eval("1 + 2 + 3+4"));
}
void testSimpleSubtract() {
ASSERT_EQUAL(5,eval("6-1"));
}
void testTenPlus12Minus100() {
ASSERT_EQUAL(-78,eval("10+12-100"));
}
void testMultiply() {
ASSERT_EQUAL(50,eval("10*5"));
}
void testDivision() {
ASSERT_EQUAL(7,eval("21/3"));
}
void testAddThenMultiply() {
ASSERT_EQUAL(21,eval("1+4 *5"));
}
void testAddThenMultiplyAdd() {
ASSERT_EQUAL(16,eval("1+4*5 -5"));
}
void testAddSubSub() {
ASSERT_EQUAL(-4,eval("1+2-3-4"));
}
void testSimpleParenthesis() {
ASSERT_EQUAL(1,eval("(1)"));
}
void testSimpleOperandParenthesis() {
ASSERT_EQUAL(2,eval("1+(1)"));
}
void testParenthesis() {
ASSERT_EQUAL(5,eval("2*(1+4)-5"));
}
void testNestedParenthesis() {
ASSERT_EQUAL(16,eval("2*(1+(4*3)-5)"));
}
void testDeeplyNestedParenthesis() {
ASSERT_EQUAL(8,eval("((2*((1+(4*3)-5)))/2)"));
}
void testSimpleAssignment() {
Parser p;
ASSERT_EQUAL(1, p.eval("a=1*(2-1)"));
ASSERT_EQUAL(8, p.eval("a+7"));
ASSERT_EQUAL(1, p.eval("2-a"));
}
void testLongerVariables() {
Parser p;
ASSERT_EQUAL(1, p.eval("aLongVariableName=1*(2-1)"));
ASSERT_EQUAL(42, p.eval("AnotherVariable=7*(4+2)"));
ASSERT_EQUAL(1, p.eval("2-(aLongVariableName*AnotherVariable)/42"));
}
void shouldThrowUndefined() {
eval("2 * undefinedVariable");
}
void runSuite(){
cute::suite s;
//TODO add your test here
s.push_back(CUTE_EXPECT(CUTE(shouldThrowEmptyExpression),std::string));
s.push_back(CUTE_EXPECT(CUTE(shouldThrowSyntaxError),std::string));
s.push_back(CUTE(testSimpleNumber));
s.push_back(CUTE(testSimpleAdd));
s.push_back(CUTE(testMultiAdd));
s.push_back(CUTE(testSimpleSubtract));
s.push_back(CUTE(testTenPlus12Minus100));
s.push_back(CUTE(testMultiply));
s.push_back(CUTE(testDivision));
s.push_back(CUTE(testAddThenMultiply));
s.push_back(CUTE(testAddSubSub));
s.push_back(CUTE(testAddThenMultiplyAdd));
s.push_back(CUTE(testSimpleParenthesis));
s.push_back(CUTE(testSimpleOperandParenthesis));
s.push_back(CUTE(testParenthesis));
s.push_back(CUTE(testNestedParenthesis));
s.push_back(CUTE(testDeeplyNestedParenthesis));
s.push_back(CUTE(testSimpleAssignment));
s.push_back(CUTE(testLongerVariables));
s.push_back(CUTE_EXPECT(CUTE(shouldThrowUndefined),std::string));
cute::ide_listener lis;
cute::makeRunner(lis)(s, "The Suite");
}
}
int main(){
runSuite();
}
YACC++ is a very good tool for parser generator for c++ applications. ANTLR is also agood option howver that does not have good documentation for its usage in C/C++.

"ambiguous symbol error" while building a C++/Tcl program using boost library

I have gone through the guides given out here & http://cpptcl.sourceforge.net/doc/compiling.html Hence I have pretty much done the basic stuffs.
Here's the code for Hello.cc given in the guide present in C++/Tcl:
#include "cpptcl.h"
#include <iostream>
using namespace std;
void hello()
{
cout << "Hello C++/Tcl!" << endl;
}
CPPTCL_MODULE(Mymodule, i)
{
i.def("hello", hello);
}
According to the guide, we need cpptcl.h & cpptcl.cc & few other files in details/ directory which I have included.
While building the code, it's giving me the following error:
1>Compiling...
1>cpptcl.cc
cpptcl.cc(35) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
cpptcl.cc(325) : error C2039: 'what' : is not a member of 'boost::exception'
1> c:\program files\boost\boost_1_44_0\boost\exception\exception.hpp(194) : see declaration of 'boost::exception'
1>cpptcl.cc(366) : error C2872: 'exception' : ambiguous symbol
1> could be 'c:\program files\boost\boost_1_44_0\boost\exception\exception.hpp(194) : boost::exception'
1> or 'c:\program files\microsoft visual studio 8\vc\include\exception(88) : std::exception'
1>cpptcl.cc(368) : error C2039: 'what' : is not a member of 'boost::exception'
1>c:\program files\boost\boost_1_44_0\boost\exception\exception.hpp(194) : see declaration of 'boost::exception'
1>3 error(s), 2 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
It's not able to resolve exception symbol. I am not sure whether the exception.hpp or the std::exception.
Below is the code for cpptcl.cc
//
// Copyright (C) 2004-2005, Maciej Sobczak
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
#include "cpptcl.h"
#include
#include
#include
#include
using namespace Tcl;
using namespace Tcl::details;
using namespace std;
using namespace boost;
result::result(Tcl_Interp *interp) : interp_(interp) {}
result::operator bool() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
int val, cc;
cc = Tcl_GetBooleanFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return static_cast(val);
}
result::operator double() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
double val;
int cc = Tcl_GetDoubleFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return val;
}
result::operator int() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
int val, cc;
cc = Tcl_GetIntFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return val;
}
result::operator long() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
long val;
int cc;
cc = Tcl_GetLongFromObj(interp_, obj, &val);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return val;
}
result::operator string() const
{
Tcl_Obj *obj = Tcl_GetObjResult(interp_);
return Tcl_GetString(obj);
}
result::operator object() const
{
return object(Tcl_GetObjResult(interp_));
}
void details::set_result(Tcl_Interp *interp, bool b)
{
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(b));
}
void details::set_result(Tcl_Interp *interp, int i)
{
Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
}
void details::set_result(Tcl_Interp *interp, long i)
{
Tcl_SetObjResult(interp, Tcl_NewLongObj(i));
}
void details::set_result(Tcl_Interp *interp, double d)
{
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(d));
}
void details::set_result(Tcl_Interp *interp, string const &s)
{
Tcl_SetObjResult(interp,
Tcl_NewStringObj(s.data(), static_cast(s.size())));
}
void details::set_result(Tcl_Interp *interp, void *p)
{
ostringstream ss;
ss (s.size())));
}
void details::set_result(Tcl_Interp *interp, object const &o)
{
Tcl_SetObjResult(interp, o.get_object());
}
void details::check_params_no(int objc, int required)
{
if (objc > callback_interp_map;
typedef map callback_map;
callback_map callbacks;
callback_map constructors;
// map of call policies
typedef map policies_interp_map;
typedef map policies_map;
policies_map call_policies;
// map of object handlers
typedef map > class_interp_map;
typedef map class_handlers_map;
class_handlers_map class_handlers;
// helper for finding call policies - returns true when found
bool find_policies(Tcl_Interp *interp, string const &cmdName,
policies_interp_map::iterator &piti)
{
policies_map::iterator pit = call_policies.find(interp);
if (pit == call_policies.end())
{
return false;
}
piti = pit->second.find(cmdName);
return piti != pit->second.end();
}
extern "C"
int object_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[]);
// helper function for post-processing call policies
// for both free functions (isMethod == false)
// and class methods (isMethod == true)
void post_process_policies(Tcl_Interp *interp, policies &pol,
Tcl_Obj * CONST objv[], bool isMethod)
{
// check if it is a factory
if (!pol.factory_.empty())
{
class_handlers_map::iterator it = class_handlers.find(interp);
if (it == class_handlers.end())
{
throw tcl_error(
"Factory was registered for unknown class.");
}
class_interp_map::iterator oit = it->second.find(pol.factory_);
if (oit == it->second.end())
{
throw tcl_error(
"Factory was registered for unknown class.");
}
class_handler_base *chb = oit->second.get();
// register a new command for the object returned
// by this factory function
// if everything went OK, the result is the address of the
// new object in the 'pXXX' form
// - the new command will be created with this name
Tcl_CreateObjCommand(interp,
Tcl_GetString(Tcl_GetObjResult(interp)),
object_handler, static_cast(chb), 0);
}
// process all declared sinks
// - unregister all object commands that envelopes the pointers
for (vector::iterator s = pol.sinks_.begin();
s != pol.sinks_.end(); ++s)
{
if (isMethod == false)
{
// example: if there is a declared sink at parameter 3,
// and the Tcl command was:
// % fun par1 par2 PAR3 par4
// then the index 3 correctly points into the objv array
int index = *s;
Tcl_DeleteCommand(interp, Tcl_GetString(objv[index]));
}
else
{
// example: if there is a declared sink at parameter 3,
// and the Tcl command was:
// % $p method par1 par2 PAR3 par4
// then the index 3 needs to be incremented
// in order correctly point into the 4th index of objv array
int index = *s + 1;
Tcl_DeleteCommand(interp, Tcl_GetString(objv[index]));
}
}
}
// actual functions handling various callbacks
// generic callback handler
extern "C"
int callback_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[])
{
callback_map::iterator it = callbacks.find(interp);
if (it == callbacks.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong interpreter?)",
TCL_STATIC);
return TCL_ERROR;
}
string cmdName(Tcl_GetString(objv[0]));
callback_interp_map::iterator iti = it->second.find(cmdName);
if (iti == it->second.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong cmd name?)",
TCL_STATIC);
return TCL_ERROR;
}
policies_map::iterator pit = call_policies.find(interp);
if (pit == call_policies.end())
{
Tcl_SetResult(interp,
"Trying to invoke callback with no known policies",
TCL_STATIC);
return TCL_ERROR;
}
policies_interp_map::iterator piti;
if (find_policies(interp, cmdName, piti) == false)
{
Tcl_SetResult(interp,
"Trying to invoke callback with no known policies",
TCL_STATIC);
return TCL_ERROR;
}
policies &pol = piti->second;
try
{
iti->second->invoke(interp, objc, objv, pol);
post_process_policies(interp, pol, objv, false);
}
catch (boost::exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
catch (...)
{
Tcl_SetResult(interp, "Unknown error.", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
// generic "object" command handler
extern "C"
int object_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[])
{
// here, client data points to the singleton object
// which is responsible for managing commands for
// objects of a given type
class_handler_base *chb = reinterpret_cast(cd);
// the command name has the form 'pXXX' where XXX is the address
// of the "this" object
string const str(Tcl_GetString(objv[0]));
istringstream ss(str);
char dummy;
void *p;
ss >> dummy >> p;
try
{
string methodName(Tcl_GetString(objv[1]));
policies &pol = chb->get_policies(methodName);
chb->invoke(p, interp, objc, objv, pol);
post_process_policies(interp, pol, objv, true);
}
catch (exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
catch (...)
{
Tcl_SetResult(interp, "Unknown error.", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
// generic "constructor" command
extern "C"
int constructor_handler(ClientData cd, Tcl_Interp *interp,
int objc, Tcl_Obj * CONST objv[])
{
// here, client data points to the singleton object
// which is responsible for managing commands for
// objects of a given type
class_handler_base *chb = reinterpret_cast(cd);
callback_map::iterator it = constructors.find(interp);
if (it == constructors.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong interpreter?)",
TCL_STATIC);
return TCL_ERROR;
}
string className(Tcl_GetString(objv[0]));
callback_interp_map::iterator iti = it->second.find(className);
if (iti == it->second.end())
{
Tcl_SetResult(interp,
"Trying to invoke non-existent callback (wrong class name?)",
TCL_STATIC);
return TCL_ERROR;
}
policies_interp_map::iterator piti;
if (find_policies(interp, className, piti) == false)
{
Tcl_SetResult(interp,
"Trying to invoke callback with no known policies",
TCL_STATIC);
return TCL_ERROR;
}
policies &pol = piti->second;
try
{
iti->second->invoke(interp, objc, objv, pol);
// if everything went OK, the result is the address of the
// new object in the 'pXXX' form
// - we can create a new command with this name
Tcl_CreateObjCommand(interp,
Tcl_GetString(Tcl_GetObjResult(interp)),
object_handler, static_cast(chb), 0);
}
catch (std::exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
catch (...)
{
Tcl_SetResult(interp, "Unknown error.", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
} // namespace anonymous
Tcl::details::no_init_type Tcl::no_init;
policies & policies::factory(string const &name)
{
factory_ = name;
return *this;
}
policies & policies::sink(int index)
{
sinks_.push_back(index);
return *this;
}
policies & policies::variadic()
{
variadic_ = true;
return *this;
}
policies Tcl::factory(string const &name)
{
return policies().factory(name);
}
policies Tcl::sink(int index)
{
return policies().sink(index);
}
policies Tcl::variadic()
{
return policies().variadic();
}
class_handler_base::class_handler_base()
{
// default policies for the -delete command
policies_["-delete"] = policies();
}
void class_handler_base::register_method(string const &name,
shared_ptr ocb, policies const &p)
{
methods_[name] = ocb;
policies_[name] = p;
}
policies & class_handler_base::get_policies(string const &name)
{
policies_map_type::iterator it = policies_.find(name);
if (it == policies_.end())
{
throw tcl_error("Trying to use non-existent policy: " + name);
}
return it->second;
}
object::object()
: interp_(0)
{
obj_ = Tcl_NewObj();
Tcl_IncrRefCount(obj_);
}
object::object(bool b)
: interp_(0)
{
obj_ = Tcl_NewBooleanObj(b);
Tcl_IncrRefCount(obj_);
}
object::object(char const *buf, size_t size)
: interp_(0)
{
obj_ = Tcl_NewByteArrayObj(
reinterpret_cast(buf),
static_cast(size));
Tcl_IncrRefCount(obj_);
}
object::object(double d)
: interp_(0)
{
obj_ = Tcl_NewDoubleObj(d);
Tcl_IncrRefCount(obj_);
}
object::object(int i)
: interp_(0)
{
obj_ = Tcl_NewIntObj(i);
Tcl_IncrRefCount(obj_);
}
object::object(long l)
: interp_(0)
{
obj_ = Tcl_NewLongObj(l);
Tcl_IncrRefCount(obj_);
}
object::object(char const *s)
: interp_(0)
{
obj_ = Tcl_NewStringObj(s, -1);
Tcl_IncrRefCount(obj_);
}
object::object(string const &s)
: interp_(0)
{
obj_ = Tcl_NewStringObj(s.data(), static_cast(s.size()));
Tcl_IncrRefCount(obj_);
}
object::object(Tcl_Obj *o, bool shared)
: interp_(0)
{
init(o, shared);
}
object::object(object const &other, bool shared)
: interp_(other.get_interp())
{
init(other.obj_, shared);
}
void object::init(Tcl_Obj *o, bool shared)
{
if (shared)
{
obj_ = o;
}
else
{
obj_ = Tcl_DuplicateObj(o);
}
Tcl_IncrRefCount(obj_);
}
object::~object()
{
Tcl_DecrRefCount(obj_);
}
object & object::assign(bool b)
{
Tcl_SetBooleanObj(obj_, b);
return *this;
}
object & object::resize(size_t size)
{
Tcl_SetByteArrayLength(obj_, static_cast(size));
return *this;
}
object & object::assign(char const *buf, size_t size)
{
Tcl_SetByteArrayObj(obj_,
reinterpret_cast(buf),
static_cast(size));
return *this;
}
object & object::assign(double d)
{
Tcl_SetDoubleObj(obj_, d);
return *this;
}
object & object::assign(int i)
{
Tcl_SetIntObj(obj_, i);
return *this;
}
object & object::assign(long l)
{
Tcl_SetLongObj(obj_, l);
return *this;
}
object & object::assign(char const *s)
{
Tcl_SetStringObj(obj_, s, -1);
return *this;
}
object & object::assign(string const &s)
{
Tcl_SetStringObj(obj_, s.data(), static_cast(s.size()));
return *this;
}
object & object::assign(object const &other)
{
object(other).swap(*this);
return *this;
}
object & object::assign(Tcl_Obj *o)
{
object(o).swap(*this);
return *this;
}
object & object::swap(object &other)
{
std::swap(obj_, other.obj_);
std::swap(interp_, other.interp_);
return *this;
}
template
bool object::get(interpreter &i) const
{
int retVal;
int res = Tcl_GetBooleanFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return static_cast(retVal);
}
template
vector object::get >(interpreter &) const
{
size_t size;
char const *buf = get(size);
return vector(buf, buf + size);
}
template
double object::get(interpreter &i) const
{
double retVal;
int res = Tcl_GetDoubleFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return retVal;
}
template
int object::get(interpreter &i) const
{
int retVal;
int res = Tcl_GetIntFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return retVal;
}
template
long object::get(interpreter &i) const
{
long retVal;
int res = Tcl_GetLongFromObj(i.get(), obj_, &retVal);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return retVal;
}
template
char const * object::get(interpreter &) const
{
return get();
}
template
string object::get(interpreter &) const
{
int len;
char const *buf = Tcl_GetStringFromObj(obj_, &len);
return string(buf, buf + len);
}
char const * object::get() const
{
return Tcl_GetString(obj_);
}
char const * object::get(size_t &size) const
{
int len;
unsigned char *buf = Tcl_GetByteArrayFromObj(obj_, &len);
size = len;
return const_cast(reinterpret_cast(buf));
}
size_t object::length(interpreter &i) const
{
int len;
int res = Tcl_ListObjLength(i.get(), obj_, &len);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return static_cast(len);
}
object object::at(interpreter &i, size_t index) const
{
Tcl_Obj *o;
int res = Tcl_ListObjIndex(i.get(), obj_, static_cast(index), &o);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
if (o == NULL)
{
throw tcl_error("Index out of range.");
}
return object(o);
}
object & object::append(interpreter &i, object const &o)
{
int res = Tcl_ListObjAppendElement(i.get(), obj_, o.obj_);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
object & object::append_list(interpreter &i, object const &o)
{
int res = Tcl_ListObjAppendList(i.get(), obj_, o.obj_);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
object & object::replace(interpreter &i, size_t index, size_t count,
object const &o)
{
int res = Tcl_ListObjReplace(i.get(), obj_,
static_cast(index), static_cast(count),
1, &(o.obj_));
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
object & object::replace_list(interpreter &i, size_t index, size_t count,
object const &o)
{
int objc;
Tcl_Obj **objv;
int res = Tcl_ListObjGetElements(i.get(), obj_, &objc, &objv);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
res = Tcl_ListObjReplace(i.get(), obj_,
static_cast(index), static_cast(count),
objc, objv);
if (res != TCL_OK)
{
throw tcl_error(i.get());
}
return *this;
}
void object::set_interp(Tcl_Interp *interp)
{
interp_ = interp;
}
Tcl_Interp * object::get_interp() const
{
return interp_;
}
interpreter::interpreter()
{
interp_ = Tcl_CreateInterp();
}
interpreter::interpreter(Tcl_Interp *interp, bool owner)
{
interp_ = interp;
owner_ = owner;
}
interpreter::~interpreter()
{
if (owner_)
{
// clear all callback info belonging to this interpreter
clear_definitions(interp_);
Tcl_DeleteInterp(interp_);
}
}
void interpreter::make_safe()
{
int cc = Tcl_MakeSafe(interp_);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
}
result interpreter::eval(string const &script)
{
int cc = Tcl_Eval(interp_, script.c_str());
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return result(interp_);
}
result interpreter::eval(istream &s)
{
string str(
istreambuf_iterator(s.rdbuf()),
istreambuf_iterator()
);
return eval(str);
}
result interpreter::eval(object const &o)
{
int cc = Tcl_EvalObjEx(interp_, o.get_object(), 0);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
return result(interp_);
}
void interpreter::pkg_provide(string const &name, string const &version)
{
int cc = Tcl_PkgProvide(interp_, name.c_str(), version.c_str());
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
}
void interpreter::create_alias(string const &cmd,
interpreter &targetInterp, string const &targetCmd)
{
int cc = Tcl_CreateAlias(interp_, cmd.c_str(),
targetInterp.interp_, targetCmd.c_str(), 0, 0);
if (cc != TCL_OK)
{
throw tcl_error(interp_);
}
}
void interpreter::clear_definitions(Tcl_Interp *interp)
{
// delete all callbacks that were registered for given interpreter
{
callback_map::iterator it = callbacks.find(interp);
if (it == callbacks.end())
{
// no callbacks defined for this interpreter
return;
}
callback_interp_map &imap = it->second;
for (callback_interp_map::iterator it2 = imap.begin();
it2 != imap.end(); ++it2)
{
Tcl_DeleteCommand(interp, it2->first.c_str());
}
callbacks.erase(interp);
}
// delete all constructors
{
callback_map::iterator it = constructors.find(interp);
if (it == constructors.end())
{
// no callbacks defined for this interpreter
return;
}
callback_interp_map &imap = it->second;
for (callback_interp_map::iterator it2 = imap.begin();
it2 != imap.end(); ++it2)
{
Tcl_DeleteCommand(interp, it2->first.c_str());
}
callbacks.erase(interp);
}
// delete all call policies
call_policies.erase(interp);
// delete all object handlers
// (we have to assume that all living objects were destroyed,
// otherwise Bad Things will happen)
class_handlers.erase(interp);
}
void interpreter::add_function(string const &name,
shared_ptr cb, policies const &p)
{
Tcl_CreateObjCommand(interp_, name.c_str(),
callback_handler, 0, 0);
callbacks[interp_][name] = cb;
call_policies[interp_][name] = p;
}
void interpreter::add_class(string const &name,
shared_ptr chb)
{
class_handlers[interp_][name] = chb;
}
void interpreter::add_constructor(string const &name,
shared_ptr chb, shared_ptr cb,
policies const &p)
{
Tcl_CreateObjCommand(interp_, name.c_str(),
constructor_handler, static_cast(chb.get()), 0);
constructors[interp_][name] = cb;
call_policies[interp_][name] = p;
}
int tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
int res;
int cc = Tcl_GetIntFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res;
}
long tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
long res;
int cc = Tcl_GetLongFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res;
}
bool tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
int res;
int cc = Tcl_GetBooleanFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res != 0;
}
double tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
double res;
int cc = Tcl_GetDoubleFromObj(interp, obj, &res);
if (cc != TCL_OK)
{
throw tcl_error(interp);
}
return res;
}
string tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
return Tcl_GetString(obj);
}
char const * tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
return Tcl_GetString(obj);
}
object tcl_cast::from(Tcl_Interp *interp, Tcl_Obj *obj)
{
object o(obj);
o.set_interp(interp);
return o;
}
How do I resolve this?
Thanks
The code seems to refer to the regular std::exception, but the symbol gets mixed because of using both the boost and std namespaces. Maybe it's some difference between VC and gcc headers.
In any case, adding the following lines to the file solves this compiler error and another similar conflict with shared_ptr in VC2010 (at least for me):
#define shared_ptr boost::shared_ptr
#define exception std::exception
Regards,
Miguel
A project has been started to fix the problems in this library here: https://github.com/wsong83/cpptcl
I notice cpptcl.cc has the following:
try
{
iti->second->invoke(interp, objc, objv, pol);
post_process_policies(interp, pol, objv, false);
}
catch (boost::exception const &e)
{
Tcl_SetResult(interp, const_cast(e.what()), TCL_VOLATILE);
return TCL_ERROR;
}
The compiler complains that boost::exceptiondoesn't have what() (which indeed it doesn't since that's in std::exception). So you have to change this to use get_error_info().
Also, I notice that the const_cast isn't taking a template argument. This is going to be problematic.