registered_functions_hack& operator=(const registered_functions_hack&);
};
-// Encode an integer into a pointer to a function. Since functions
-// are aligned (the minimal alignment depends on CPU architecture)
-// we can distinguish between pointers and integers.
-static reader_func encode_serial_as_reader_func(unsigned serial)
-{
- uintptr_t u = (uintptr_t)serial;
- u = (u << 1) | (uintptr_t)1;
- reader_func ptr = (reader_func)((void *)u);
- return ptr;
-}
-
const prototype_table& get_default_reader()
{
- using std::make_pair;
static bool initialized = false;
static prototype_table reader;
if (!initialized) {
-
- reader[make_pair("sqrt", 1)] = sqrt_reader;
- reader[make_pair("pow", 2)] = pow_reader;
- reader[make_pair("power", 2)] = power_reader;
- reader[make_pair("lst", 0)] = lst_reader;
+
+ reader.insert({{"sqrt", 1}, reader_func(sqrt_reader)});
+ reader.insert({{"pow", 2}, reader_func(pow_reader)});
+ reader.insert({{"power", 2}, reader_func(power_reader)});
+ reader.insert({{"lst", 0}, reader_func(lst_reader)});
unsigned serial = 0;
for (auto & it : registered_functions_hack::get_registered_functions()) {
- prototype proto = make_pair(it.get_name(), it.get_nparams());
- reader[proto] = encode_serial_as_reader_func(serial);
+ reader.insert({{it.get_name(), it.get_nparams()},
+ reader_func(serial)});
++serial;
}
initialized = true;
const prototype_table& get_builtin_reader()
{
- using std::make_pair;
static bool initialized = false;
static prototype_table reader;
if (!initialized) {
-
- reader[make_pair("sqrt", 1)] = sqrt_reader;
- reader[make_pair("pow", 2)] = pow_reader;
- reader[make_pair("power", 2)] = power_reader;
- reader[make_pair("lst", 0)] = lst_reader;
+
+ reader.insert({{"sqrt", 1}, reader_func(sqrt_reader)});
+ reader.insert({{"pow", 2}, reader_func(pow_reader)});
+ reader.insert({{"power", 2}, reader_func(power_reader)});
+ reader.insert({{"lst", 0}, reader_func(lst_reader)});
enum {
log,
exp,
auto it = registered_functions_hack::get_registered_functions().begin();
unsigned serial = 0;
for ( ; serial<NFUNCTIONS; ++it, ++serial ) {
- prototype proto = make_pair(it->get_name(), it->get_nparams());
- reader[proto] = encode_serial_as_reader_func(serial);
+ reader.insert({{it->get_name(), it->get_nparams()},
+ reader_func(serial)});
}
initialized = true;
}
* The parser uses (an associative array of) such functions to construct
* (GiNaC) classes and functions from a sequence of characters.
*/
-typedef ex (*reader_func)(const exvector& args);
+class reader_func {
+ enum { FUNCTION_PTR, GINAC_FUNCTION };
+public:
+ reader_func(ex (*func_)(const exvector& args))
+ : type(FUNCTION_PTR), serial(0), func(func_) {}
+ reader_func(unsigned serial_)
+ : type(GINAC_FUNCTION), serial(serial_), func(nullptr) {}
+ ex operator()(const exvector& args) const;
+private:
+ unsigned type;
+ unsigned serial;
+ ex (*func)(const exvector& args);
+};
+
+
/**
* Prototype table.
namespace GiNaC {
-// <KLUDGE>
-// Find out if ptr is a pointer to a function or a specially crafted integer.
-// It's possible to distinguish between these because functions are aligned.
-// Returns true if ptr is a pointer and false otherwise.
-static bool decode_serial(unsigned& serial, const reader_func ptr)
+ex reader_func::operator()(const exvector& args) const
{
- uintptr_t u = (uintptr_t)(void *)ptr;
- if (u & 1) {
- u >>= 1;
- serial = (unsigned)u;
- return false;
- }
- return true;
-}
-
-// Figures out if ptr is a pointer to function or a serial of GiNaC function.
-// In the former case calls that function, in the latter case constructs
-// GiNaC function with corresponding serial and arguments.
-static ex dispatch_reader_fcn(const reader_func ptr, const exvector& args)
-{
- unsigned serial = 0; // dear gcc, could you please shut up?
- bool is_ptr = decode_serial(serial, ptr);
- if (is_ptr)
- return ptr(args);
- else
+ switch (type) {
+ case FUNCTION_PTR:
+ return func(args);
+ case GINAC_FUNCTION:
return function(serial, args);
+ default:
+ abort();
+ }
}
-// </KLUDGE>
-
/// identifier_expr: identifier | identifier '(' expression* ')'
ex parser::parse_identifier_expr()
}
// Eat the ')'.
get_next_tok();
- prototype the_prototype = make_pair(name, args.size());
- auto reader = funcs.find(the_prototype);
+ auto reader = funcs.find({name, args.size()});
if (reader == funcs.end()) {
Parse_error_("no function \"" << name << "\" with " <<
args.size() << " arguments");
}
// reader->second might be a pointer to a C++ function or a specially
// crafted serial of a GiNaC::function.
- ex ret = dispatch_reader_fcn(reader->second, args);
- return ret;
+ return reader->second(args);
}
/// paren_expr: '(' expression ')'
get_next_tok();
ex ret = parse_expression();
// parse_expression() stops if it encounters an unknown token.
- // This is not a bug: since the parser is recursive checking
+ // This is not a bug: since the parser is recursive, checking
// whether the next token is valid is responsibility of the caller.
// Hence make sure nothing is left in the stream:
if (token != lexer::token_type::eof)