From: Mikko Rasa Date: Mon, 25 Jul 2011 14:10:57 +0000 (+0300) Subject: Exception rework for parser components X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=d14b7ddd81404b909a4c4763a36a23b94998a089;p=libs%2Fdatafile.git Exception rework for parser components --- diff --git a/source/binaryparser.cpp b/source/binaryparser.cpp index d2fca32..550319f 100644 --- a/source/binaryparser.cpp +++ b/source/binaryparser.cpp @@ -9,6 +9,17 @@ 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) @@ -25,7 +36,7 @@ Statement BinaryParser::parse() 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(); const string &kw = st.args[1].get(); @@ -35,7 +46,7 @@ Statement BinaryParser::parse() 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(); strings[id] = st.args[1].get(); diff --git a/source/dataerror.cpp b/source/dataerror.cpp new file mode 100644 index 0000000..b21b84f --- /dev/null +++ b/source/dataerror.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#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 new file mode 100644 index 0000000..7b53c65 --- /dev/null +++ b/source/dataerror.h @@ -0,0 +1,27 @@ +#ifndef MSP_DATAFILE_DATAERROR_H_ +#define MSP_DATAFILE_DATAERROR_H_ + +#include + +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() { } + +private: + std::string make_what(const std::string &, unsigned, const std::string &); +}; + +} // namespace DataFile +} // namespace Msp + +#endif diff --git a/source/parser.cpp b/source/parser.cpp index 99ece49..443c3c8 100644 --- a/source/parser.cpp +++ b/source/parser.cpp @@ -1,5 +1,6 @@ #include #include "binaryparser.h" +#include "dataerror.h" #include "parser.h" #include "statement.h" #include "textparser.h" @@ -25,7 +26,7 @@ Parser::~Parser() Statement Parser::parse() { if(!good) - throw Exception("Parser is not good"); + throw logic_error("Parser::parse() !good"); try { @@ -54,10 +55,13 @@ Statement Parser::parse() return st; } } - catch(const Exception &e) + catch(const exception &e) { good = false; - throw; + if(dynamic_cast(&e)) + throw; + else + throw data_error(src, in.get_line_number(), e); } } diff --git a/source/textparser.cpp b/source/textparser.cpp index 56c9bb2..c4eb03c 100644 --- a/source/textparser.cpp +++ b/source/textparser.cpp @@ -9,6 +9,28 @@ 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) { } @@ -40,7 +62,7 @@ Statement TextParser::parse_statement(const Token *t) 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; @@ -62,7 +84,7 @@ Statement TextParser::parse_statement(const Token *t) 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=="{") @@ -84,10 +106,8 @@ Statement TextParser::parse_statement(const Token *t) 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; @@ -119,7 +139,7 @@ Token TextParser::parse_token() } 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, ""); @@ -189,7 +209,7 @@ Token TextParser::parse_token() else if(isalpha(c) || c=='_' || c=='\\') state = IDENTIFIER; else - parse_error(c, "0-9A-Za-z_\\.\"{};+-"); + throw parse_error(buf); break; case SIGN: @@ -200,7 +220,7 @@ Token TextParser::parse_token() else if(c=='.') state = FLOAT; else - parse_error(c, "0-9."); + throw parse_error(buf); break; case ZERO: @@ -211,31 +231,31 @@ Token TextParser::parse_token() 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: @@ -244,19 +264,19 @@ Token TextParser::parse_token() 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: @@ -270,14 +290,14 @@ Token TextParser::parse_token() 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) @@ -285,17 +305,7 @@ Token TextParser::parse_token() 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); } @@ -314,17 +324,5 @@ bool TextParser::isodigit(int c) return (c>='0' && c<='7'); } -string TextParser::get_location() -{ - ostringstream ss; - ss<(c), e)), get_location()); -} - } // namespace DataFile } // namespace Msp diff --git a/source/textparser.h b/source/textparser.h index eb45233..ef7d68e 100644 --- a/source/textparser.h +++ b/source/textparser.h @@ -19,8 +19,6 @@ protected: Token parse_token(); bool is_delimiter(int); bool isodigit(int); - std::string get_location(); - void parse_error(int, const char *); }; } // namespace DataFile