From 85dbe3f2049dce7d43a1bd956d622f4ff5c0c156 Mon Sep 17 00:00:00 2001 From: Alexei Sheplyakov Date: Mon, 25 Aug 2008 19:08:36 +0400 Subject: [PATCH] parser: improve error reporting a little bit. Introduce class 'parse_error' (which contain some info about location of the error) and throw it on parse errors. N.B.: the actual info is a bit inaccurate because lexer doesn't track the location properly yet. --- ginac/parser/debug.hpp | 13 +++++++++++++ ginac/parser/lexer.cpp | 14 ++++++++++++++ ginac/parser/lexer.hpp | 3 +++ ginac/parser/parser.cpp | 20 ++++++-------------- ginac/parser/parser.hpp | 12 ++++++++++++ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/ginac/parser/debug.hpp b/ginac/parser/debug.hpp index a43cc7ad..5221580d 100644 --- a/ginac/parser/debug.hpp +++ b/ginac/parser/debug.hpp @@ -20,6 +20,19 @@ do { \ throw exception(err.str()); \ } while (0) +#define Parse_error_(message) \ +do { \ + std::ostringstream err; \ + err << "GiNaC: parse error at line " << scanner->line_num << \ + ", column " << scanner->column << ": "; \ + err << message << std::endl; \ + err << '[' << __PRETTY_FUNCTION__ << "(" << __FILE__ << ':' << __LINE__ << ")]" << std::endl; \ + throw parse_error(err.str(), scanner->line_num, scanner->column); \ +} while (0) + +#define Parse_error(message) \ + Parse_error_(message << ", got: " << scanner->tok2str(token)) + #define bug(message) bail_out(std::logic_error, message) #define dout(condition, message) \ diff --git a/ginac/parser/lexer.cpp b/ginac/parser/lexer.cpp index 894a2ad8..d8c49b8c 100644 --- a/ginac/parser/lexer.cpp +++ b/ginac/parser/lexer.cpp @@ -129,5 +129,19 @@ void lexer::switch_input(std::istream* in) c = ' '; } +/// Symbolic name of current token (for error reporting) +std::string lexer::tok2str(const int tok) const +{ + switch (tok) { + case lexer::token_type::identifier: + case lexer::token_type::number: + return std::string("\"") + str + "\""; + case lexer::token_type::eof: + return std::string("EOF"); + default: + return std::string("\"") + char(tok) + "\""; + } +} + } // namespace GiNaC diff --git a/ginac/parser/lexer.hpp b/ginac/parser/lexer.hpp index b53d08f3..0a00ed39 100644 --- a/ginac/parser/lexer.hpp +++ b/ginac/parser/lexer.hpp @@ -37,6 +37,9 @@ public: }; }; + + /// Symbolic name of the token (for error reporting) + std::string tok2str(const int tok) const; }; } // namespace GiNaC diff --git a/ginac/parser/parser.cpp b/ginac/parser/parser.cpp index b33261c2..1e905cf5 100644 --- a/ginac/parser/parser.cpp +++ b/ginac/parser/parser.cpp @@ -30,7 +30,7 @@ ex parser::parse_identifier_expr() break; if (token != ',') - throw std::invalid_argument("Expected ')' or ',' in argument list"); + Parse_error("expected ')' or ',' in argument list"); get_next_tok(); } @@ -40,9 +40,8 @@ ex parser::parse_identifier_expr() prototype the_prototype = make_pair(name, args.size()); prototype_table::const_iterator reader = funcs.find(the_prototype); if (reader == funcs.end()) { - bail_out(std::invalid_argument, - "no function \"" << name << "\" with " << args.size() - << " arguments"); + Parse_error_("no function \"" << name << "\" with " << + args.size() << " arguments"); } ex ret = reader->second(args); return ret; @@ -55,7 +54,7 @@ ex parser::parse_paren_expr() ex e = parse_expression(); if (token != ')') - throw std::invalid_argument("parser::parse_paren_expr: expected ')'"); + Parse_error("expected ')'"); get_next_tok(); // eat ). return e; } @@ -74,10 +73,7 @@ ex parser::parse_unary_expr(const int s) case '+': return v; default: - throw std::invalid_argument( - std::string(__func__) - + ": invalid unary operator \"" - + char(s) + "\""); + Parse_error_("invalid unary operator \"" << char(s) << "\""); } } @@ -98,12 +94,8 @@ ex parser::parse_primary() case lexer::token_type::literal: return parse_literal_expr(); case lexer::token_type::eof: - bail_out(std::invalid_argument, "got EOF while parsing the expression"); default: - bail_out(std::invalid_argument, "unknown token " << - token << " (\"" << - (token ? std::string("") + char(token) : "NULL") - << "\")"); + Parse_error("unexpected token"); } } diff --git a/ginac/parser/parser.hpp b/ginac/parser/parser.hpp index 81b78476..3e10b8fc 100644 --- a/ginac/parser/parser.hpp +++ b/ginac/parser/parser.hpp @@ -9,6 +9,18 @@ namespace GiNaC class lexer; +class parse_error : public std::invalid_argument +{ +public: + const std::size_t line; + const std::size_t column; + parse_error(const std::string& what_, + const std::size_t line_ = 0, + const std::size_t column_ = 0) throw () : + std::invalid_argument(what_), line(line_), column(column_) + { } +}; + /** * Recursive descent parser for GiNaC expressions. */ -- 2.44.0