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)
if(st.keyword=="__kwd")
{
if(st.args.size()!=3)
- throw_at(TypeError("Keyword definition must have three arguments"), src);
+ throw bad_definition("__kwd");
const unsigned id = st.args[0].get<unsigned>();
const string &kw = st.args[1].get<const string &>();
else if(st.keyword=="__str")
{
if(st.args.size()!=2)
- throw_at(TypeError("String definition must have two arguments"), src);
+ throw bad_definition("__str");
const unsigned id = st.args[0].get<unsigned>();
strings[id] = st.args[1].get<const string &>();
--- /dev/null
+#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
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)
{ }
if(token.str.empty())
break;
else if(token.type!=Token::IDENTIFIER)
- throw_at(ParseError(format("Syntax error at token '%s' (expected an identifier)", token.str)), get_location());
+ throw syntax_error(token.str);
result.keyword = token.str;
result.valid = true;
result.source = src;
else if(finish)
{
if(token.str!=";")
- throw_at(ParseError(format("Syntax error at token '%s' (Expected a ';')", token.str)), get_location());
+ throw syntax_error(token.str);
break;
}
else if(token.str=="{")
else
result.append(Symbol(token.str));
}
- else if(token.str=="")
- throw_at(ParseError("Unexcepted end of input"), get_location());
else
- throw_at(ParseError("Syntax error"), get_location());
+ throw syntax_error(token.str);
}
return result;
}
if(comment>0) // EOF while in comment
- throw_at(ParseError("Unfinished comment at end of input"), get_location());
+ throw parse_error(string());
else if(comment==0) // Didn't hit any non-whitespace
return Token(Token::SPECIAL, "");
else if(isalpha(c) || c=='_' || c=='\\')
state = IDENTIFIER;
else
- parse_error(c, "0-9A-Za-z_\\.\"{};+-");
+ throw parse_error(buf);
break;
case SIGN:
else if(c=='.')
state = FLOAT;
else
- parse_error(c, "0-9.");
+ throw parse_error(buf);
break;
case ZERO:
else if(c=='.')
state = FLOAT;
else
- parse_error(c, "0-9A-Fa-f.");
+ throw parse_error(buf);
break;
case DECIMAL:
if(c=='.')
state = FLOAT;
else if(!isdigit(c))
- parse_error(c, "0-9.");
+ throw parse_error(buf);
break;
case HEXADECIMAL:
if(!isxdigit(c))
- parse_error(c, "0-9A-Fa-f");
+ throw parse_error(buf);
break;
case OCTAL:
if(!isodigit(c))
- parse_error(c, "0-7");
+ throw parse_error(buf);
break;
case FLOAT:
if(c=='e' || c=='E')
state = FLOATEXPINIT;
else if(!isdigit(c))
- parse_error(c, "0-9Ee");
+ throw parse_error(buf);
break;
case FLOATEXPINIT:
else if(isdigit(c))
state = FLOATEXP;
else
- parse_error(c, "0-9+-");
+ throw parse_error(buf);
break;
case FLOATEXPSIGN:
if(isdigit(c))
state = FLOATEXP;
else
- parse_error(c, "0-9");
+ throw parse_error(buf);
break;
case FLOATEXP:
if(!isdigit(c))
- parse_error(c, "0-9");
+ throw parse_error(buf);
break;
case STRING:
case IDENTIFIER:
if(!isalpha(c) && !isdigit(c) && c!='_' && c!='-' && c!='/')
- parse_error(c, "0-9A-Za-z_/-");
+ throw parse_error(buf);
break;
case STRING_END:
- throw_at(ParseError("Garbage after string"), get_location());
+ throw parse_error(buf);
default:
- throw_at(InvalidState("Internal error (bad state)"), get_location());
+ throw logic_error("bad parser state");
}
if(is_delimiter(next) && state>=ACCEPT)
if(state==IDENTIFIER && buf[0]=='\\')
return Token(Token::IDENTIFIER, buf.substr(1));
else if(state==STRING_END)
- {
- try
- {
- return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
- }
- catch(Exception &e)
- {
- e.at(get_location());
- throw;
- }
- }
+ return Token(Token::STRING, c_unescape(buf.substr(1, buf.size()-2)));
else
return Token(token_type[state], buf);
}
return (c>='0' && c<='7');
}
-string TextParser::get_location()
-{
- ostringstream ss;
- ss<<src<<':'<<in.get_line_number();
- return ss.str();
-}
-
-void TextParser::parse_error(int c, const char *e)
-{
- throw_at(ParseError(format("Parse error at '%c', expected one of \"%s\"", static_cast<char>(c), e)), get_location());
-}
-
} // namespace DataFile
} // namespace Msp