]> git.tdb.fi Git - libs/datafile.git/commitdiff
Merge remote-tracking branch 'origin/master'
authorMikko Rasa <tdb@tdb.fi>
Mon, 19 Sep 2016 14:00:06 +0000 (17:00 +0300)
committerMikko Rasa <tdb@tdb.fi>
Mon, 19 Sep 2016 14:00:06 +0000 (17:00 +0300)
14 files changed:
source/binaryparser.cpp
source/dataerror.cpp [deleted file]
source/dataerror.h [deleted file]
source/except.cpp [new file with mode: 0644]
source/except.h [new file with mode: 0644]
source/jsonparser.cpp [new file with mode: 0644]
source/jsonparser.h [new file with mode: 0644]
source/loader.cpp
source/objectloader.cpp [deleted file]
source/objectloader.h
source/parser.cpp
source/statement.cpp
source/statement.h
source/textparser.cpp

index e2ced82098e7b1472944dd4a2b626bef32211459..4ed2877a4424c2389c890473a0e71918418516ba 100644 (file)
@@ -5,6 +5,7 @@
 #include "argumentstore.h"
 #include "binaryparser.h"
 #include "binfloat.h"
+#include "except.h"
 #include "input.h"
 #include "loaderaction.h"
 
@@ -13,27 +14,6 @@ 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() { }
-};
-
-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),
diff --git a/source/dataerror.cpp b/source/dataerror.cpp
deleted file mode 100644 (file)
index b21b84f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <typeinfo>
-#include <msp/debug/demangle.h>
-#include <msp/strings/format.h>
-#include "dataerror.h"
-
-using namespace std;
-
-namespace Msp {
-namespace DataFile {
-
-data_error::data_error(const string &s, unsigned l, const string &w):
-       runtime_error(make_what(s, l, w)),
-       source(s),
-       line(l)
-{ }
-
-data_error::data_error(const string &s, unsigned l, const exception &e):
-       runtime_error(make_what(s, l, format("%s (%s)", Debug::demangle(typeid(e).name()), e.what()))),
-       source(s),
-       line(l)
-{ }
-
-string data_error::make_what(const string &s, unsigned l, const string &w)
-{
-       if(l)
-               return format("%s:%d: %s", s, l, w);
-       else
-               return format("%s: %s", s, w);
-}
-
-} // namespace DataFile
-} // namespace Msp
diff --git a/source/dataerror.h b/source/dataerror.h
deleted file mode 100644 (file)
index 5fca0c3..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef MSP_DATAFILE_DATAERROR_H_
-#define MSP_DATAFILE_DATAERROR_H_
-
-#include <stdexcept>
-
-namespace Msp {
-namespace DataFile {
-
-class data_error: public std::runtime_error
-{
-private:
-       std::string source;
-       unsigned line;
-
-public:
-       data_error(const std::string &, unsigned, const std::string &);
-       data_error(const std::string &, unsigned, const std::exception &);
-       virtual ~data_error() throw() { }
-
-       const std::string &get_source() const { return source; }
-       unsigned get_line() const { return line; }
-
-private:
-       std::string make_what(const std::string &, unsigned, const std::string &);
-};
-
-} // namespace DataFile
-} // namespace Msp
-
-#endif
diff --git a/source/except.cpp b/source/except.cpp
new file mode 100644 (file)
index 0000000..d3929f6
--- /dev/null
@@ -0,0 +1,66 @@
+#include <msp/debug/demangle.h>
+#include <msp/strings/format.h>
+#include "except.h"
+
+using namespace std;
+
+namespace Msp {
+namespace DataFile {
+
+data_error::data_error(const string &s, unsigned l, const string &w):
+       runtime_error(make_what(s, l, w)),
+       source(s),
+       line(l)
+{ }
+
+data_error::data_error(const string &s, unsigned l, const exception &e):
+       runtime_error(make_what(s, l, format("%s (%s)", Debug::demangle(typeid(e).name()), e.what()))),
+       source(s),
+       line(l)
+{ }
+
+string data_error::make_what(const string &s, unsigned l, const string &w)
+{
+       if(l)
+               return format("%s:%d: %s", s, l, w);
+       else
+               return format("%s: %s", s, w);
+}
+
+
+parse_error::parse_error(const string &t):
+       runtime_error(t.empty() ? "at end of input" : format("after '%s'", t))
+{ }
+
+
+syntax_error::syntax_error(const string &t):
+       runtime_error(t.empty() ? "at end of input" : format("at '%s'", t))
+{ }
+
+
+bad_definition::bad_definition(const string &w):
+       runtime_error(w)
+{ }
+
+
+nesting_error::nesting_error(const string &w):
+       logic_error(w)
+{ }
+
+
+unknown_keyword::unknown_keyword(const string &k):
+       runtime_error(k)
+{ }
+
+
+invalid_signature::invalid_signature(const string &k, const string &s):
+       runtime_error(format("%s %s", k, s))
+{ }
+
+
+no_collection::no_collection(const type_info &t):
+       runtime_error(Debug::demangle(t.name()))
+{ }
+
+} // namespace DataFile
+} // namespace Msp
diff --git a/source/except.h b/source/except.h
new file mode 100644 (file)
index 0000000..ed9ca23
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef MSP_DATAFILE_EXCEPT_H_
+#define MSP_DATAFILE_EXCEPT_H_
+
+#include <stdexcept>
+#include <typeinfo>
+
+namespace Msp {
+namespace DataFile {
+
+class data_error: public std::runtime_error
+{
+private:
+       std::string source;
+       unsigned line;
+
+public:
+       data_error(const std::string &, unsigned, const std::string &);
+       data_error(const std::string &, unsigned, const std::exception &);
+       virtual ~data_error() throw() { }
+
+       const std::string &get_source() const { return source; }
+       unsigned get_line() const { return line; }
+
+private:
+       std::string make_what(const std::string &, unsigned, const std::string &);
+};
+
+
+class parse_error: public std::runtime_error
+{
+public:
+       parse_error(const std::string &);
+       virtual ~parse_error() throw() { }
+};
+
+
+class syntax_error: public std::runtime_error
+{
+public:
+       syntax_error(const std::string &t);
+       virtual ~syntax_error() throw() { }
+};
+
+
+class bad_definition: public std::runtime_error
+{
+public:
+       bad_definition(const std::string &w);
+       virtual ~bad_definition() throw() { }
+};
+
+
+class nesting_error: public std::logic_error
+{
+public:
+       nesting_error(const std::string &);
+       virtual ~nesting_error() throw() { }
+};
+
+
+class unknown_keyword: public std::runtime_error
+{
+public:
+       unknown_keyword(const std::string &);
+       virtual ~unknown_keyword() throw() { }
+};
+
+
+class invalid_signature: public std::runtime_error
+{
+public:
+       invalid_signature(const std::string &, const std::string &);
+       virtual ~invalid_signature() throw() { }
+};
+
+
+class no_collection: public std::runtime_error
+{
+public:
+       no_collection(const std::type_info &);
+};
+
+} // namespace DataFile
+} // namespace Msp
+
+#endif
diff --git a/source/jsonparser.cpp b/source/jsonparser.cpp
new file mode 100644 (file)
index 0000000..4b93703
--- /dev/null
@@ -0,0 +1,377 @@
+#include <msp/stringcodec/utf8.h>
+#include "except.h"
+#include "input.h"
+#include "jsonparser.h"
+
+using namespace std;
+
+namespace Msp {
+namespace DataFile {
+
+JsonParser::JsonParser(Input &i, const string &s):
+       ParserMode(i, s),
+       toplevel_state(STATE_INIT)
+{ }
+
+Statement JsonParser::parse()
+{
+       if(toplevel_state==STATE_END)
+               return Statement();
+
+       bool was_init = (toplevel_state==STATE_INIT);
+       Token token = parse_token();
+       if(toplevel_state==STATE_INIT)
+       {
+               if(token.str=="[")
+                       toplevel_state = STATE_ARRAY;
+               else if(token.str=="{")
+                       toplevel_state = STATE_OBJECT;
+               else
+               {
+                       // TODO Standalone simple values; does anyone use them?
+                       toplevel_state = STATE_END;
+                       throw syntax_error(token.str);
+               }
+
+               token = parse_token();
+       }
+
+       if((toplevel_state==STATE_ARRAY && token.str=="]") || (toplevel_state==STATE_OBJECT && token.str=="}"))
+       {
+               toplevel_state = STATE_END;
+               return Statement();
+       }
+       else if(!was_init)
+       {
+               if(token.str!=",")
+                       throw syntax_error(token.str);
+
+               token = parse_token();
+       }
+
+       return parse_statement(&token, toplevel_state, string());
+}
+
+Statement JsonParser::parse_statement(const Token *t, State outer_state, const string &outer_kw)
+{
+       enum ParseState
+       {
+               INIT,
+               NAME,
+               VALUE,
+               ARRAY_INIT,
+               ARRAY,
+               ARRAY_ELEMENT,
+               OBJECT_INIT,
+               OBJECT,
+               OBJECT_MEMBER
+       };
+
+       Statement result;
+       ParseState state = INIT;
+
+       if(outer_state==STATE_ARRAY)
+       {
+               result.keyword = outer_kw+"[]";
+               state = VALUE;
+       }
+
+       while(in)
+       {
+               Token token;
+               if(t)
+               {
+                       token = *t;
+                       t = 0;
+               }
+               else
+                       token = parse_token();
+
+               if(!result.valid)
+               {
+                       result.valid = true;
+                       result.source = src;
+                       result.line = in.get_line_number();
+               }
+
+               if(state==INIT)
+               {
+                       if(token.type!=Token::STRING)
+                               throw syntax_error(token.str);
+
+                       result.keyword = token.str;
+                       state = NAME;
+               }
+               else if((state==ARRAY_INIT || state==ARRAY_ELEMENT) && token.str=="]")
+                       break;
+               else if((state==ARRAY_INIT || state==ARRAY))
+               {
+                       Statement ss = parse_statement(&token, STATE_ARRAY, result.keyword);
+                       result.sub.push_back(ss);
+                       state = ARRAY_ELEMENT;
+               }
+               else if(state==ARRAY_ELEMENT && token.str==",")
+                       state = ARRAY;
+               else if((state==OBJECT_INIT || state==OBJECT_MEMBER) && token.str=="}")
+                       break;
+               else if((state==OBJECT_INIT || state==OBJECT))
+               {
+                       Statement ss = parse_statement(&token, STATE_OBJECT, result.keyword);
+                       result.sub.push_back(ss);
+                       state = OBJECT_MEMBER;
+               }
+               else if(state==OBJECT_MEMBER && token.str==",")
+                       state = OBJECT;
+               else if(state==NAME && token.str==":")
+                       state = VALUE;
+               else if(state==VALUE)
+               {
+                       if(token.str=="[")
+                               state = ARRAY_INIT;
+                       else if(token.str=="{")
+                               state = OBJECT_INIT;
+                       else if(token.type!=Token::SPECIAL)
+                       {
+                               result.append_from_token(token);
+                               break;
+                       }
+                       else
+                               throw syntax_error(token.str);
+               }
+               else
+                       throw syntax_error(token.str);
+       }
+
+       return result;
+}
+
+Token JsonParser::parse_token()
+{
+       int c = 0;
+
+       while(in)
+       {
+               c = in.get();
+               if(!isspace(c))
+                       break;
+       }
+
+       if(!in)
+               return Token(Token::SPECIAL, "");
+
+       enum ParseState
+       {
+               INIT,
+               SIGN,
+               FLOATEXPINIT,
+               FLOATEXPSIGN,
+               STRING,
+               STRING_ESCAPE,
+               ACCEPT,
+               DECIMAL,
+               FLOAT,
+               FLOATEXP,
+               STRING_END,
+               IDENTIFIER
+       };
+
+       static Token::Type token_type[]=
+       {
+               Token::SPECIAL,
+               Token::SPECIAL,
+               Token::SPECIAL,
+               Token::SPECIAL,
+               Token::SPECIAL,
+               Token::SPECIAL,
+               Token::SPECIAL,
+               Token::INTEGER,
+               Token::FLOAT,
+               Token::FLOAT,
+               Token::STRING,
+               Token::IDENTIFIER
+       };
+
+       ParseState state = INIT;
+       string buf;
+
+       while(1)
+       {
+               if(state!=INIT)
+                       c = in.get();
+               int next = in.peek();
+
+               buf += c;
+
+               switch(state)
+               {
+               case INIT:
+                       if(c=='-' || c=='+')
+                               state = SIGN;
+                       else if(c=='.')
+                               state = FLOAT;
+                       else if(c=='"')
+                               state = STRING;
+                       else if(c=='{' || c=='}' || c=='[' || c==']' || c==':' || c==',')
+                               return Token(Token::SPECIAL, string(1, c));
+                       else if(isdigit(c))
+                               state = DECIMAL;
+                       else if(isalpha(c))
+                               state = IDENTIFIER;
+                       else
+                               throw parse_error(buf);
+                       break;
+
+               case SIGN:
+                       if(isdigit(c))
+                               state = DECIMAL;
+                       else if(c=='.')
+                               state = FLOAT;
+                       else
+                               throw parse_error(buf);
+                       break;
+
+               case DECIMAL:
+                       if(c=='.')
+                               state = FLOAT;
+                       else if(c=='e' || c=='E')
+                               state = FLOATEXPINIT;
+                       else if(!isdigit(c))
+                               throw parse_error(buf);
+                       break;
+
+               case FLOAT:
+                       if(c=='e' || c=='E')
+                               state = FLOATEXPINIT;
+                       else if(!isdigit(c))
+                               throw parse_error(buf);
+                       break;
+
+               case FLOATEXPINIT:
+                       if(c=='+' || c=='-')
+                               state = FLOATEXPSIGN;
+                       else if(isdigit(c))
+                               state = FLOATEXP;
+                       else
+                               throw parse_error(buf);
+                       break;
+
+               case FLOATEXPSIGN:
+                       if(isdigit(c))
+                               state = FLOATEXP;
+                       else
+                               throw parse_error(buf);
+                       break;
+
+               case FLOATEXP:
+                       if(!isdigit(c))
+                               throw parse_error(buf);
+                       break;
+
+               case STRING:
+                       if(c=='\\')
+                               state = STRING_ESCAPE;
+                       else if(c=='"')
+                               state = STRING_END;
+                       break;
+
+               case STRING_ESCAPE:
+                       state = STRING;
+                       break;
+
+               case IDENTIFIER:
+                       if(!isalpha(c))
+                               throw parse_error(buf);
+                       break;
+
+               case STRING_END:
+                       throw parse_error(buf);
+
+               default:
+                       throw logic_error("bad parser state");
+               }
+
+               if(is_delimiter(next) && state>=ACCEPT)
+               {
+                       if(state==STRING_END)
+                               return Token(Token::STRING, unescape(buf.substr(1, buf.size()-2)));
+                       else
+                               return Token(token_type[state], buf);
+               }
+       }
+}
+
+bool JsonParser::is_delimiter(int c)
+{
+       return (isspace(c) || c=='{' || c=='}' || c=='[' || c==']' || c==':' || c==',');
+}
+
+string JsonParser::unescape(const string &str)
+{
+       string result;
+       StringCodec::Utf8::Decoder dec;
+       StringCodec::Utf8::Encoder enc;
+       bool escape = false;
+
+       for(string::const_iterator i=str.begin(); i!=str.end(); )
+       {
+               StringCodec::unichar c = dec.decode_char(str, i);
+
+               if(escape)
+               {
+                       if(c=='\"')
+                               enc.encode_char('\"', result);
+                       else if(c=='\\')
+                               enc.encode_char('\\', result);
+                       else if(c=='/')
+                               enc.encode_char('/', result);
+                       else if(c=='b')
+                               enc.encode_char('\b', result);
+                       else if(c=='f')
+                               enc.encode_char('\f', result);
+                       else if(c=='n')
+                               enc.encode_char('\n', result);
+                       else if(c=='r')
+                               enc.encode_char('\r', result);
+                       else if(c=='t')
+                               enc.encode_char('\t', result);
+                       else if(c=='u')
+                       {
+                               unsigned code = 0;
+                               for(unsigned n=0; n<4; ++n)
+                               {
+                                       if(i==str.end())
+                                               throw invalid_argument("JsonParser::unescape");
+
+                                       c = dec.decode_char(str, i);
+
+                                       unsigned digit = 0;
+                                       if(c>='0' && c<='9')
+                                               digit = c-'0';
+                                       else if(c>='a' && c<='f')
+                                               digit = c-'a'+10;
+                                       else if(c>='A' && c<='F')
+                                               digit = c-'A'+10;
+                                       else
+                                               throw invalid_argument("JsonParser::unescape");
+
+                                       code = (code<<4)+digit;
+                               }
+
+                               enc.encode_char(code, result);
+                       }
+                       else
+                               throw invalid_argument("JsonParser::unescape");
+
+                       escape = false;
+               }
+               else if(c=='\\')
+                       escape = true;
+               else
+                       enc.encode_char(c, result);
+       }
+
+       return result;
+}
+
+} // namespace DataFile
+} // namespace Msp
diff --git a/source/jsonparser.h b/source/jsonparser.h
new file mode 100644 (file)
index 0000000..611eea0
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef MSP_DATAFILE_JSONPARSER_H_
+#define MSP_DATAFILE_JSONPARSER_H_
+
+#include "parsermode.h"
+#include "token.h"
+
+namespace Msp {
+namespace DataFile {
+
+class JsonParser: public ParserMode
+{
+private:
+       enum State
+       {
+               STATE_INIT,
+               STATE_ARRAY,
+               STATE_OBJECT,
+               STATE_END
+       };
+
+       State toplevel_state;
+
+public:
+       JsonParser(Input &, const std::string &);
+
+       virtual Statement parse();
+private:
+       Statement parse_statement(const Token *, State, const std::string &);
+       Token parse_token();
+       bool is_delimiter(int);
+       std::string unescape(const std::string &);
+};
+
+} // namespace DataFile
+} // namespace Msp
+
+#endif
index 81370687ffd7e32f35a413359ac47d90d01c6c5a..81fd27eecebf87c16e3418ae6d11e3ead9ba8d80 100644 (file)
@@ -1,6 +1,6 @@
 #include <msp/core/raii.h>
 #include <msp/strings/format.h>
-#include "dataerror.h"
+#include "except.h"
 #include "loader.h"
 #include "type.h"
 
@@ -47,28 +47,6 @@ bool signature_match(const string &st_sig, const string &act_sig)
 namespace Msp {
 namespace DataFile {
 
-class unknown_keyword: public runtime_error
-{
-public:
-       unknown_keyword(const std::string &k):
-               runtime_error(k)
-       { }
-
-       virtual ~unknown_keyword() throw() { }
-};
-
-
-class invalid_signature: public runtime_error
-{
-public:
-       invalid_signature(const std::string &k, const std::string &s):
-               runtime_error(format("%s %s", k, s))
-       { }
-
-       virtual ~invalid_signature() throw() { }
-};
-
-
 Loader::Loader():
        cur_st(0),
        direct(false),
diff --git a/source/objectloader.cpp b/source/objectloader.cpp
deleted file mode 100644 (file)
index 6d59812..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <msp/debug/demangle.h>
-#include "objectloader.h"
-
-using namespace std;
-
-namespace Msp {
-namespace DataFile {
-
-no_collection::no_collection(const type_info &t):
-       runtime_error(Debug::demangle(t.name()))
-{ }
-
-} // namespace DataFile
-} // namespace Msp
index 76fc412abed60db13c7b7e4b80837ffad0ca93df..e383109f791937739c7e80e5e3d10486bc1641ff 100644 (file)
@@ -1,18 +1,12 @@
 #ifndef MSP_DATAFILE_OBJECTLOADER_H_
 #define MSP_DATAFILE_OBJECTLOADER_H_
 
-#include <typeinfo>
+#include "except.h"
 #include "loader.h"
 
 namespace Msp {
 namespace DataFile {
 
-class no_collection: public std::runtime_error
-{
-public:
-       no_collection(const std::type_info &);
-};
-
 class Collection;
 
 /**
index a9bbbf22fe8ccb52cf8a60ede5d914f581fdcf04..7e4d3dd7f93942b9d4c9c3b69f2715d93b25b492 100644 (file)
@@ -1,6 +1,7 @@
 #include <msp/strings/format.h>
 #include "binaryparser.h"
-#include "dataerror.h"
+#include "except.h"
+#include "jsonparser.h"
 #include "parser.h"
 #include "statement.h"
 #include "textparser.h"
@@ -14,9 +15,14 @@ Parser::Parser(IO::Base &i, const string &s):
        in(i),
        main_src(s),
        src(s),
-       good(true),
-       mode(new TextParser(in, src))
-{ }
+       good(true)
+{
+       char c = in.peek();
+       if(c=='{' || c=='[')
+               mode = new JsonParser(in, src);
+       else
+               mode = new TextParser(in, src);
+}
 
 Parser::~Parser()
 {
index b1ff05826e314441fd3e93ced8c5117f295b5824..9dfb54421a47c6f041b344cc175a6c67e232f43c 100644 (file)
@@ -1,5 +1,6 @@
 #include <msp/strings/format.h>
 #include "statement.h"
+#include "token.h"
 #include "type.h"
 
 using namespace std;
@@ -36,6 +37,27 @@ string Statement::get_signature() const
        return result;
 }
 
+Statement &Statement::append_from_token(const Token &token)
+{
+       if(token.type==Token::INTEGER)
+               return append(lexical_cast<IntType::Store>(token.str));
+       else if(token.type==Token::FLOAT)
+               return append(lexical_cast<FloatType::Store>(token.str));
+       else if(token.type==Token::STRING)
+               return append(token.str);
+       else if(token.type==Token::IDENTIFIER)
+       {
+               if(token.str=="true")
+                       return append(true);
+               else if(token.str=="false")
+                       return append(false);
+               else
+                       return append(Symbol(token.str));
+       }
+       else
+               throw invalid_argument("Statement::append_from_token");
+}
+
 
 StatementInfo::StatementInfo():
        args_size(0)
index 184ef9955cbc78af80231eabda307bb45605be54..9aad48d953226ba0ab1b3b209d88d10460d56f39 100644 (file)
@@ -7,6 +7,8 @@
 namespace Msp {
 namespace DataFile {
 
+struct Token;
+
 class Statement
 {
 public:
@@ -32,6 +34,8 @@ public:
                return *this;
        }
 
+       Statement &append_from_token(const Token &);
+
        template<typename T>
        Statement &operator,(const T &v)
        { return append(v); }
index 05521a90456a617e2e82b1fb664225d512a22af4..7dc4bde7e46ed659368498798bf0b6b3b62fa246 100644 (file)
@@ -1,5 +1,6 @@
 #include <msp/strings/format.h>
 #include <msp/strings/utils.h>
+#include "except.h"
 #include "input.h"
 #include "textparser.h"
 #include "token.h"
@@ -9,28 +10,6 @@ using namespace std;
 namespace Msp {
 namespace DataFile {
 
-class parse_error: public runtime_error
-{
-public:
-       parse_error(const std::string &t):
-               runtime_error(t.empty() ? "at end of input" : format("after '%s'", t))
-       { }
-
-       virtual ~parse_error() throw() { }
-};
-
-
-class syntax_error: public runtime_error
-{
-public:
-       syntax_error(const std::string &t):
-               runtime_error(t.empty() ? "at end of input" : format("at '%s'", t))
-       { }
-
-       virtual ~syntax_error() throw() { }
-};
-
-
 TextParser::TextParser(Input &i, const string &s):
        ParserMode(i, s)
 { }
@@ -43,8 +22,7 @@ Statement TextParser::parse()
 Statement TextParser::parse_statement(const Token *t)
 {
        Statement result;
-       bool sub = false;
-       bool finish = false;
+       unsigned sub = 0;
 
        while(in)
        {
@@ -68,44 +46,28 @@ Statement TextParser::parse_statement(const Token *t)
                        result.source = src;
                        result.line = in.get_line_number();
                }
-               else if(sub)
+               else if(sub==1)
                {
                        if(token.str=="}")
-                       {
-                               sub = false;
-                               finish = true;
-                       }
+                               sub = 2;
                        else
                        {
                                Statement ss = parse_statement(&token);
                                result.sub.push_back(ss);
                        }
                }
-               else if(finish)
+               else if(sub==2)
                {
                        if(token.str!=";")
                                throw syntax_error(token.str);
                        break;
                }
                else if(token.str=="{")
-                       sub = true;
+                       sub = 1;
                else if(token.str==";")
                        break;
-               else if(token.type==Token::INTEGER)
-                       result.append(lexical_cast<IntType::Store>(token.str));
-               else if(token.type==Token::FLOAT)
-                       result.append(lexical_cast<FloatType::Store>(token.str));
-               else if(token.type==Token::STRING)
-                       result.append(token.str);
-               else if(token.type==Token::IDENTIFIER)
-               {
-                       if(token.str=="true")
-                               result.append(true);
-                       else if(token.str=="false")
-                               result.append(false);
-                       else
-                               result.append(Symbol(token.str));
-               }
+               else if(token.type!=Token::SPECIAL)
+                       result.append_from_token(token);
                else
                        throw syntax_error(token.str);
        }
@@ -150,6 +112,7 @@ Token TextParser::parse_token()
                FLOATEXPINIT,
                FLOATEXPSIGN,
                STRING,
+               STRING_ESCAPE,
                ACCEPT,
                ZERO,
                DECIMAL,
@@ -169,6 +132,7 @@ Token TextParser::parse_token()
                Token::SPECIAL,
                Token::SPECIAL,
                Token::SPECIAL,
+               Token::SPECIAL,
                Token::INTEGER,
                Token::INTEGER,
                Token::INTEGER,
@@ -181,7 +145,6 @@ Token TextParser::parse_token()
 
        ParseState state = INIT;
        string buf;
-       bool escape = false;
 
        while(in || state==INIT)
        {
@@ -283,11 +246,13 @@ Token TextParser::parse_token()
 
                case STRING:
                        if(c=='\\')
-                               escape = !escape;
-                       else if(c=='"' && !escape)
+                               state = STRING_ESCAPE;
+                       else if(c=='"')
                                state = STRING_END;
-                       else
-                               escape = false;
+                       break;
+
+               case STRING_ESCAPE:
+                       state = STRING;
                        break;
 
                case IDENTIFIER: