#include <limits>
-#include <sys/param.h>
#include <msp/core/maputils.h>
#include <msp/strings/format.h>
+#include "argumentstore.h"
#include "binaryparser.h"
#include "binfloat.h"
+#include "except.h"
#include "input.h"
+#include "loaderaction.h"
using namespace std;
namespace Msp {
namespace DataFile {
-class bad_definition: public runtime_error
-{
-public:
- bad_definition(const std::string &w):
- runtime_error(w)
- { }
-
- virtual ~bad_definition() throw() { }
-};
-
-
BinaryParser::BinaryParser(Input &i, const string &s):
- ParserMode(i, s),
- first(true),
- float_precision(32)
+ ParserMode(i, s)
{
- 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(bool raw)
+Statement BinaryParser::parse()
{
- while(1)
+ const StatementKey *key;
+ if(cur_info)
{
- Statement st = parse_statement(raw);
- if(st.keyword=="__kwd")
- {
- int id = st.args[0].get<int>();
- if(id<=0)
- throw bad_definition("__kwd");
-
- const string &kw = st.args[1].get<const string &>();
- const string &args = st.args[2].get<const string &>();
- for(string::const_iterator i=args.begin(); i!=args.end(); ++i)
- for(unsigned j=0; valid_signatures[j]!=*i; ++j)
- if(!valid_signatures[j])
- throw bad_definition("__kwd");
-
- dict[id] = StatementKey(kw, args);
- }
- else if(st.keyword=="__str")
- {
- int id = st.args[0].get<int>();
- if(id<=0)
- throw bad_definition("__str");
-
- strings[id] = st.args[1].get<const string &>();
- }
- else if(st.keyword=="__flt")
- float_precision = st.args[0].get<unsigned>();
- else
- return st;
-
- if(raw)
- return st;
+ key = &cur_info->key;
+ cur_info = nullptr;
}
-}
-
-Statement BinaryParser::parse_statement(bool raw)
-{
- while(first && in.peek()=='\n')
- in.get();
- first = false;
-
- int id = parse_int();
- if(!in)
- return Statement();
+ 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());
result.args.push_back(parse_bool());
break;
case SymbolType::signature:
- result.args.push_back(parse_symbol());
+ result.args.push_back(Value(parse_symbol()));
break;
}
}
+ unsigned upper_nsub = (sub_remaining.empty() ? 0 : sub_remaining.back());
+
unsigned nsub = parse_int();
for(unsigned j = 0; j<nsub; ++j)
- result.sub.push_back(parse(raw));
+ result.sub.push_back(parse());
+
+ if(upper_nsub>0)
+ sub_remaining.back() = upper_nsub-1;
result.valid = true;
return result;
}
+void BinaryParser::process_control_statement(const Statement &st)
+{
+ if(st.keyword=="__kwd")
+ {
+ int id = st.args[0].get<int>();
+ if(id<=0)
+ throw bad_definition("__kwd");
+
+ const string &kw = st.args[1].get<const string &>();
+ const string &args = st.args[2].get<const string &>();
+ for(char c: args)
+ for(unsigned j=0; valid_signatures[j]!=c; ++j)
+ if(!valid_signatures[j])
+ throw bad_definition("__kwd");
+
+ dict[id] = StatementInfo(kw, args);
+ }
+ else if(st.keyword=="__str")
+ {
+ int id = st.args[0].get<int>();
+ if(id<=0)
+ throw bad_definition("__str");
+
+ strings[id] = st.args[1].get<const string &>();
+ }
+ else if(st.keyword=="__flt")
+ 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 = nullptr;
+ }
+
+ if(!sub_remaining.empty() && sub_remaining.back()==0)
+ {
+ // No more substatements on this level
+ cur_info = nullptr;
+ return nullptr;
+ }
+
+ if(cur_info)
+ return &cur_info->key;
+
+ int id = parse_int();
+ if(!in)
+ return nullptr;
+
+ 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 = nullptr;
+
+ act.execute(ldr, args);
+
+ return true;
+}
+
IntType::Store BinaryParser::parse_int()
{
IntType::Store result = 0;
FloatType::Store BinaryParser::parse_float()
{
- UInt64 encoded = 0;
+ uint64_t encoded = 0;
for(unsigned i=0; i<float_precision; i+=8)
{
int c = in.get();