--- /dev/null
+#include "argumentstore.h"
+
+namespace Msp {
+namespace DataFile {
+
+ArgumentStore::ArgumentStore(const StatementInfo &n):
+ info(n),
+ store(new char[info.args_size])
+{
+ for(unsigned i=0; i<info.key.signature.size(); ++i)
+ switch(info.key.signature[i])
+ {
+ case StringType::signature:
+ new(store+info.arg_offsets[i]) StringType::Store;
+ break;
+ case SymbolType::signature:
+ new(store+info.arg_offsets[i]) SymbolType::Store;
+ break;
+ }
+}
+
+ArgumentStore::~ArgumentStore()
+{
+ for(unsigned i=0; i<info.key.signature.size(); ++i)
+ switch(info.key.signature[i])
+ {
+ case StringType::signature:
+ reinterpret_cast<StringType::Store *>(store+info.arg_offsets[i])->~basic_string();
+ break;
+ case SymbolType::signature:
+ reinterpret_cast<SymbolType::Store *>(store+info.arg_offsets[i])->~Symbol();
+ break;
+ }
+}
+
+} // namespace DataFile
+} // namespace Msp
--- /dev/null
+#ifndef MSP_DATAFILE_ARGUMENTSTORE_H_
+#define MSP_DATAFILE_ARGUMENTSTORE_H_
+
+#include "statement.h"
+
+namespace Msp {
+namespace DataFile {
+
+class ArgumentStore
+{
+private:
+ const StatementInfo &info;
+ char *store;
+
+public:
+ ArgumentStore(const StatementInfo &);
+ ~ArgumentStore();
+
+ const StatementInfo &get_info() const { return info; }
+
+ template<typename T>
+ void set(unsigned i, const T &v)
+ {
+ *reinterpret_cast<typename TypeInfo<T>::Store *>(store+info.arg_offsets[i]) = v;
+ }
+
+ template<typename T>
+ typename TypeInfo<T>::Load get(unsigned i) const
+ {
+ return extract<typename TypeInfo<T>::Store>(store+info.arg_offsets[i], info.key.signature[i]);
+ }
+
+private:
+ template<typename T>
+ T extract(const char *, char) const;
+};
+
+template<typename T>
+inline T ArgumentStore::extract(const char *p, char) const
+{
+ return *reinterpret_cast<const T *>(p);
+}
+
+template<>
+inline FloatType::Store ArgumentStore::extract<FloatType::Store>(const char *p, char s) const
+{
+ if(s==IntType::signature)
+ return *reinterpret_cast<const IntType::Store *>(p);
+ else
+ return *reinterpret_cast<const FloatType::Store *>(p);
+}
+
+} // namespace DataFile
+} // namespace Msp
+
+#endif
#include <sys/param.h>
#include <msp/core/maputils.h>
#include <msp/strings/format.h>
+#include "argumentstore.h"
#include "binaryparser.h"
#include "binfloat.h"
#include "input.h"
+#include "loaderaction.h"
using namespace std;
virtual ~bad_definition() throw() { }
};
+class nesting_error: public logic_error
+{
+public:
+ nesting_error(const std::string &w):
+ logic_error(w)
+ { }
+
+ virtual ~nesting_error() throw() { }
+};
+
BinaryParser::BinaryParser(Input &i, const string &s):
ParserMode(i, s),
- float_precision(32)
+ float_precision(32),
+ cur_info(0)
{
- dict[-1] = StatementKey("__kwd", "iss");
- dict[-2] = StatementKey("__str", "is");
- dict[-3] = StatementKey("__flt", "i");
+ dict[-1] = StatementInfo("__kwd", "iss");
+ dict[-2] = StatementInfo("__str", "is");
+ dict[-3] = StatementInfo("__flt", "i");
}
Statement BinaryParser::parse()
{
- int id = parse_int();
- if(!in)
- return Statement();
+ const StatementKey *key;
+ if(cur_info)
+ key = &cur_info->key;
+ else
+ {
+ int id = parse_int();
+ if(!in)
+ return Statement();
- const StatementKey &key = get_item(dict, id);
+ key = &get_item(dict, id).key;
+ }
Statement result;
- result.keyword = key.keyword;
+ result.keyword = key->keyword;
result.source = src;
- for(unsigned j=0; j<key.signature.size(); ++j)
+ for(unsigned j=0; j<key->signature.size(); ++j)
{
- switch(key.signature[j])
+ switch(key->signature[j])
{
case IntType::signature:
result.args.push_back(parse_int());
}
}
+ if(!sub_remaining.empty())
+ --sub_remaining.back();
+
unsigned nsub = parse_int();
for(unsigned j = 0; j<nsub; ++j)
result.sub.push_back(parse());
result.valid = true;
+ cur_info = 0;
return result;
}
if(!valid_signatures[j])
throw bad_definition("__kwd");
- dict[id] = StatementKey(kw, args);
+ dict[id] = StatementInfo(kw, args);
}
else if(st.keyword=="__str")
{
float_precision = st.args[0].get<unsigned>();
}
+const StatementKey *BinaryParser::peek(unsigned level)
+{
+ if(level>sub_remaining.size())
+ throw nesting_error("bad level");
+ while(level<sub_remaining.size())
+ {
+ // Discard any substatements that haven't been parsed yet
+ for(unsigned i=sub_remaining.back(); i-->0; )
+ parse();
+ sub_remaining.pop_back();
+ cur_info = 0;
+ }
+
+ if(!sub_remaining.empty() && sub_remaining.back()==0)
+ {
+ // No more substatements on this level
+ cur_info = 0;
+ return 0;
+ }
+
+ if(cur_info)
+ return &cur_info->key;
+
+ int id = parse_int();
+ if(!in)
+ return 0;
+
+ cur_info = &get_item(dict, id);
+ return &cur_info->key;
+}
+
+bool BinaryParser::parse_and_load(unsigned level, Loader &ldr, const LoaderAction &act)
+{
+ if(!cur_info && !peek(level))
+ return false;
+
+ ArgumentStore args(*cur_info);
+ for(unsigned i=0; i<cur_info->key.signature.size(); ++i)
+ switch(cur_info->key.signature[i])
+ {
+ case IntType::signature:
+ args.set(i, parse_int());
+ break;
+ case FloatType::signature:
+ args.set(i, parse_float());
+ break;
+ case BoolType::signature:
+ args.set(i, parse_bool());
+ break;
+ case StringType::signature:
+ args.set(i, parse_string());
+ break;
+ case SymbolType::signature:
+ args.set(i, parse_symbol());
+ break;
+ }
+
+ if(!sub_remaining.empty())
+ --sub_remaining.back();
+ sub_remaining.push_back(parse_int());
+ cur_info = 0;
+
+ act.execute(ldr, args);
+
+ return true;
+}
+
IntType::Store BinaryParser::parse_int()
{
IntType::Store result = 0;
class BinaryParser: public ParserMode
{
private:
- typedef std::map<int, StatementKey> Dictionary;
+ typedef std::map<int, StatementInfo> Dictionary;
typedef std::map<unsigned, std::string> StringMap;
Dictionary dict;
StringMap strings;
unsigned float_precision;
+ StatementInfo *cur_info;
+ std::vector<unsigned> sub_remaining;
public:
BinaryParser(Input &i, const std::string &s);
virtual Statement parse();
virtual void process_control_statement(const Statement &);
+
+ virtual const StatementKey *peek(unsigned);
+ virtual bool parse_and_load(unsigned, Loader &, const LoaderAction &);
+
private:
IntType::Store parse_int();
FloatType::Store parse_float();
Loader::Loader():
cur_st(0),
+ direct(false),
check_sub_loads(false)
{ }
{
while(p)
{
- Statement st = p.parse();
- if(st.valid)
- load_statement(st);
+ if(p.peek(0))
+ load_direct(p, 0);
+ else
+ {
+ // Parse in raw mode so we can peek immediately after a mode change
+ Statement st = p.parse(true);
+ if(st.valid && !st.control)
+ load_statement(st);
+ }
}
finish();
}
finish();
}
+void Loader::load_direct(Parser &p, unsigned l)
+{
+ SetForScope<Parser *> set_parser(cur_parser, &p);
+ SetForScope<unsigned> set_level(cur_level, l);
+
+ while(p)
+ {
+ const StatementKey *key = p.peek(l);
+ if(!key)
+ break;
+
+ LoaderAction *act = find_action(*key);
+ if(act)
+ {
+ SetFlag set_direct(direct);
+ if(!p.parse_and_load(l, *this, *act))
+ throw logic_error("direct load failed");
+ }
+ else
+ load_statement(p.parse());
+ }
+}
+
void Loader::load_statement(const Statement &st)
{
SetForScope<const Statement *> set_cst(cur_st, &st);
void Loader::load_sub_with(Loader &ldr)
{
- if(!cur_st)
+ if(direct)
+ {
+ ldr.load_direct(*cur_parser, cur_level+1);
+ ldr.finish();
+ }
+ else if(cur_st)
+ {
+ ldr.load(*cur_st);
+ sub_loaded = true;
+ }
+ else
throw logic_error("no current statement");
-
- ldr.load(*cur_st);
- sub_loaded = true;
}
void Loader::add(const string &kwd, LoaderAction *act)
typedef std::map<StatementKey, LoaderAction *> ActionMap;
ActionMap actions;
+ Parser *cur_parser;
+ unsigned cur_level;
const Statement *cur_st;
bool sub_loaded;
+ bool direct;
std::list<Loader *> aux_loaders;
protected:
bool check_sub_loads;
/** Loads data from a statement. */
void load(const Statement &st);
+ /** Loads statemsnts from a parser, feeding them directly to actions. */
+ void load_direct(Parser &, unsigned);
+
/** Processes a single statement */
void load_statement(const Statement &st);
#ifndef MSP_DATAFILE_LOADERACTION_H_
#define MSP_DATAFILE_LOADERACTION_H_
+#include "argumentstore.h"
#include "statement.h"
namespace Msp {
/** Called to process a statement. */
virtual void execute(Loader &, const Statement &) const = 0;
+ virtual void execute(Loader &, const ArgumentStore &) const = 0;
+
virtual std::string get_signature() const = 0;
};
(dynamic_cast<L &>(l).*func)();
};
+ virtual void execute(Loader &l, const ArgumentStore &) const
+ {
+ (dynamic_cast<L &>(l).*func)();
+ };
+
virtual std::string get_signature() const
{ return std::string(); }
};
(dynamic_cast<L &>(l).*func)(st.args[0].get<A0>());
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ (dynamic_cast<L &>(l).*func)(as.get<A0>(0));
+ }
+
virtual std::string get_signature() const
{ return std::string(1, TypeInfo<A0>::signature); }
};
(dynamic_cast<L &>(l).*func)(values);
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ std::vector<A0> values;
+ unsigned n_args = as.get_info().key.signature.size();
+ values.reserve(n_args);
+ for(unsigned i=0; i<n_args; ++i)
+ values.push_back(as.get<A0>(i));
+ (dynamic_cast<L &>(l).*func)(values);
+ }
+
virtual std::string get_signature() const
{
std::string result;
(dynamic_cast<L &>(l).*func)(st);
}
+ virtual void execute(Loader &, const ArgumentStore &) const
+ {
+ throw std::logic_error("incompatible format");
+ }
+
virtual std::string get_signature() const
{ return "*"; }
};
(dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>());
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ (dynamic_cast<L &>(l).*func)(as.get<A0>(0), as.get<A1>(1));
+ }
+
virtual std::string get_signature() const
{
std::string result;
(dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>());
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ (dynamic_cast<L &>(l).*func)(as.get<A0>(0), as.get<A1>(1), as.get<A2>(2));
+ }
+
virtual std::string get_signature() const
{
std::string result;
(dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>(), st.args[3].get<A3>());
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ (dynamic_cast<L &>(l).*func)(as.get<A0>(0), as.get<A1>(1), as.get<A2>(2), as.get<A3>(3));
+ }
+
virtual std::string get_signature() const
{
std::string result;
(dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>(), st.args[3].get<A3>(), st.args[4].get<A4>());
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ (dynamic_cast<L &>(l).*func)(as.get<A0>(0), as.get<A1>(1), as.get<A2>(2), as.get<A3>(3), as.get<A4>(4));
+ }
+
virtual std::string get_signature() const
{
std::string result;
dynamic_cast<typename L::Loader &>(l).get_object().*ptr0 = st.args[0].get<T0>();
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ dynamic_cast<typename L::Loader &>(l).get_object().*ptr0 = as.get<T0>(0);
+ }
+
virtual std::string get_signature() const
{ return std::string(1, TypeInfo<T0>::signature); }
};
ldr.get_object().*ptr0 = &ldr.get_collection().template get<T0>(st.args[0].get<std::string>());
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ typename L::Loader &ldr = dynamic_cast<typename L::Loader &>(l);
+ ldr.get_object().*ptr0 = &ldr.get_collection().template get<T0>(as.get<std::string>(0));
+ }
+
virtual std::string get_signature() const
{ return std::string(1, TypeInfo<std::string>::signature); }
};
dynamic_cast<typename L::Loader &>(l).get_object().*ptr1 = st.args[1].get<T1>();
}
+ virtual void execute(Loader &l, const ArgumentStore &as) const
+ {
+ dynamic_cast<typename L::Loader &>(l).get_object().*ptr0 = as.get<T0>(0);
+ dynamic_cast<typename L::Loader &>(l).get_object().*ptr1 = as.get<T1>(1);
+ }
+
virtual std::string get_signature() const
{
std::string result;
mode->process_control_statement(st);
}
+const StatementKey *Parser::peek(unsigned level)
+{
+ while(1)
+ {
+ const StatementKey *key = mode->peek(level);
+ if(key && !key->keyword.compare(0, 2, "__"))
+ process_control_statement(mode->parse());
+ else
+ return key;
+ }
+}
+
+bool Parser::parse_and_load(unsigned level, Loader &ldr, const LoaderAction &act)
+{
+ // Peek first to get any control statements processed
+ peek(level);
+ return mode->parse_and_load(level, ldr, act);
+}
+
} // namespace DataFile
} // namespace Msp
namespace Msp {
namespace DataFile {
+class Loader;
+class LoaderAction;
class ParserMode;
class Statement;
+class StatementKey;
/**
Frontend for loading datafiles. Handles switching between text and binary
Parser(IO::Base &i, const std::string &s);
~Parser();
- /**
- Reads a statement from the input. If the end of input was reached, an empty
- invalid statement will be returned. If an error occurs, the parser will be
- marked as bad and no more statements may be read, even if the exception was
- caught.
- */
+ /** Reads a statement from the input. If the end of input was reached, an
+ empty invalid statement will be returned. If an error occurs, the parser
+ will be marked as bad and no more statements may be read, even if the
+ exception was caught. */
Statement parse(bool raw = false);
private:
void process_control_statement(const Statement &);
public:
+ /** Returns a key for the next statement, consisting of its keyword and
+ signature. Not supported in all modes. */
+ const StatementKey *peek(unsigned);
+
+ /** Parses a statement and feeds its arguments to an action. The action
+ must be appropriate for the statement. Use peek() to determine the
+ statement's signature. */
+ bool parse_and_load(unsigned, Loader &, const LoaderAction &);
+
operator bool() const { return good && in; }
};
namespace DataFile {
class Input;
+class Loader;
+class LoaderAction;
/**
Base class for parse modes.
virtual Statement parse() = 0;
virtual void process_control_statement(const Statement &) { }
+
+ virtual const StatementKey *peek(unsigned) { return 0; }
+ virtual bool parse_and_load(unsigned, Loader &, const LoaderAction &) { return false; }
};
} // namespace DataFile
#include <msp/strings/format.h>
#include "statement.h"
+#include "type.h"
using namespace std;
return result;
}
+
+StatementInfo::StatementInfo():
+ args_size(0)
+{ }
+
+StatementInfo::StatementInfo(const string &k, const string &s):
+ key(k, s),
+ args_size(0)
+{
+ for(string::const_iterator i=key.signature.begin(); i!=key.signature.end(); ++i)
+ {
+ arg_offsets.push_back(args_size);
+ switch(*i)
+ {
+ case IntType::signature:
+ args_size += sizeof(IntType::Store);
+ break;
+ case FloatType::signature:
+ args_size += sizeof(FloatType::Store);
+ break;
+ case BoolType::signature:
+ args_size += sizeof(BoolType::Store);
+ break;
+ case StringType::signature:
+ args_size += sizeof(StringType::Store);
+ break;
+ case SymbolType::signature:
+ args_size += sizeof(SymbolType::Store);
+ break;
+ }
+ }
+}
+
} // namespace DataFile
} // namespace Msp
{ return keyword<o.keyword || (keyword==o.keyword && signature<o.signature); }
};
+struct StatementInfo
+{
+ StatementKey key;
+ unsigned args_size;
+ std::vector<unsigned> arg_offsets;
+
+ StatementInfo();
+ StatementInfo(const std::string &, const std::string &);
+};
+
} // namespace DataFile
} // namespace Msp
{
std::string name;
+ Symbol() { }
+
template<typename T>
Symbol(const T &n): name(lexical_cast<std::string>(n)) { }