]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/parser.cpp
Move all exception classes to a common header
[libs/datafile.git] / source / parser.cpp
index 82ac0069b95d4f22e3d0de1ab0c0b66b04c76423..5972e2d98f832d312afa4373bfe66d4204d10f8f 100644 (file)
@@ -1,12 +1,6 @@
-/* $Id$
-
-This file is part of libmspdatafile
-Copyright © 2006  Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
-#include <cctype>
-#include <sstream>
+#include <msp/strings/format.h>
 #include "binaryparser.h"
+#include "except.h"
 #include "parser.h"
 #include "statement.h"
 #include "textparser.h"
@@ -16,8 +10,9 @@ using namespace std;
 namespace Msp {
 namespace DataFile {
 
-Parser::Parser(istream &i, const string &s):
+Parser::Parser(IO::Base &i, const string &s):
        in(i),
+       main_src(s),
        src(s),
        good(true),
        mode(new TextParser(in, src))
@@ -28,35 +23,88 @@ Parser::~Parser()
        delete mode;
 }
 
-Statement Parser::parse()
+Statement Parser::parse(bool raw)
 {
        if(!good)
-               throw Exception("Parser is not good");
+               throw logic_error("Parser::parse() !good");
 
        try
        {
                while(1)
                {
-                       Statement st=mode->parse();
-                       if(st.keyword=="__bin")
+                       Statement st = mode->parse();
+                       if(!st.keyword.compare(0, 2, "__"))
                        {
-                               delete mode;
-                               mode=new BinaryParser(in, src);
+                               st.control = true;
+                               process_control_statement(st);
                        }
-                       else if(st.keyword=="__text")
-                       {
-                               delete mode;
-                               mode=new TextParser(in, src);
-                       }
-                       else
+
+                       if(raw || !st.control)
                                return st;
+                       else if(!good)  // This will occur with an __end statement
+                               return Statement();
                }
        }
-       catch(const Exception &e)
+       catch(const exception &e)
+       {
+               good = false;
+               if(dynamic_cast<const data_error *>(&e))
+                       throw;
+               else
+                       throw data_error(src, in.get_line_number(), e);
+       }
+}
+
+void Parser::process_control_statement(const Statement &st)
+{
+       if(st.keyword=="__bin")
+       {
+               delete mode;
+               mode = new BinaryParser(in, src);
+
+               while(in.peek()=='\n')
+                       in.get();
+       }
+       else if(st.keyword=="__text")
        {
-               good=false;
-               throw;
+               delete mode;
+               mode = new TextParser(in, src);
        }
+       else if(st.keyword=="__z")
+               in.set_decompress();
+       else if(st.keyword=="__src")
+       {
+               string s = st.args[0].get<string>();
+               if(s.empty())
+                       src = main_src;
+               else
+                       src = format("%s[%s]", main_src, s);
+       }
+       else if(st.keyword=="__end")
+               good = false;
+       else
+               mode->process_control_statement(st);
+}
+
+const StatementKey *Parser::peek(unsigned level)
+{
+       while(good)
+       {
+               const StatementKey *key = mode->peek(level);
+               if(key && !key->keyword.compare(0, 2, "__"))
+                       process_control_statement(mode->parse());
+               else
+                       return key;
+       }
+
+       return 0;
+}
+
+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