]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/binaryparser.cpp
Move all exception classes to a common header
[libs/datafile.git] / source / binaryparser.cpp
index fd918758294fd6c1d66ac497af5d5674d629c691..4ed2877a4424c2389c890473a0e71918418516ba 100644 (file)
@@ -2,90 +2,52 @@
 #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)
+       float_precision(32),
+       cur_info(0)
 {
-       dict[-1] = DictEntry("__kwd", "iss");
-       dict[-2] = DictEntry("__str", "is");
-       dict[-3] = DictEntry("__flt", "i");
+       dict[-1] = StatementInfo("__kwd", "iss");
+       dict[-2] = StatementInfo("__str", "is");
+       dict[-3] = StatementInfo("__flt", "i");
 }
 
 Statement BinaryParser::parse()
 {
-       while(1)
+       const StatementKey *key;
+       if(cur_info)
        {
-               Statement st = parse_statement();
-               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] = DictEntry(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;
+               key = &cur_info->key;
+               cur_info = 0;
        }
-}
-
-Statement BinaryParser::parse_statement()
-{
-       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 DictEntry &de = get_item(dict, id);
+               key = &get_item(dict, id).key;
+       }
 
        Statement result;
-       result.keyword = de.keyword;
+       result.keyword = key->keyword;
        result.source = src;
 
-       for(unsigned j = 0; j<de.args.size(); ++j)
+       for(unsigned j=0; j<key->signature.size(); ++j)
        {
-               switch(de.args[j])
+               switch(key->signature[j])
                {
                case IntType::signature:
                        result.args.push_back(parse_int());
@@ -105,15 +67,116 @@ Statement BinaryParser::parse_statement()
                }
        }
 
+       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());
 
+       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(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] = 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 = 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;