GG
ReportParseError.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /* GG is a GUI for SDL and OpenGL.
3  Copyright (C) 2003-2008 T. Zachary Laine
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public License
7  as published by the Free Software Foundation; either version 2.1
8  of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free
17  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18  02111-1307 USA
19 
20  If you do not wish to comply with the terms of the LGPL please
21  contact the author as other terms are available for a fee.
22 
23  Zach Laine
24  whatwasthataddress@gmail.com */
25 
28 #ifndef _GG_ReportParseError_h_
29 #define _GG_ReportParseError_h_
30 
31 #include <GG/Export.h>
32 #include <GG/LexerFwd.h>
33 
34 #include <boost/algorithm/string/replace.hpp>
35 #include <boost/tuple/tuple.hpp>
36 
37 
38 namespace GG {
39 
40  namespace detail {
41 
42  inline void default_send_error_string(const std::string& str)
43  { std::cerr << str; }
44 
45  extern GG_API const char* s_filename;
46  extern GG_API text_iterator* s_text_it;
47  extern GG_API text_iterator s_begin;
48  extern GG_API text_iterator s_end;
49 
50  }
51 
52  template <typename TokenType>
53  struct report_error_
54  {
55  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
56  struct result
57  { typedef void type; };
58 
59  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
60  void operator()(Arg1 first, Arg2, Arg3 it, Arg4 rule_name) const
61  {
62  std::string error_string;
63  generate_error_string(first, it, rule_name, error_string);
64  send_error_string(error_string);
65  }
66 
67  static boost::function<void (const std::string&)> send_error_string;
68 
69  private:
70  std::pair<text_iterator, unsigned int> line_start_and_line_number(text_iterator error_position) const
71  {
72  unsigned int line = 1;
73  text_iterator it = detail::s_begin;
74  text_iterator line_start = detail::s_begin;
75  while (it != error_position) {
76  bool eol = false;
77  if (it != error_position && *it == '\r') {
78  eol = true;
79  line_start = ++it;
80  }
81  if (it != error_position && *it == '\n') {
82  eol = true;
83  line_start = ++it;
84  }
85  if (eol)
86  ++line;
87  else
88  ++it;
89  }
90  return std::pair<text_iterator, unsigned int>(line_start, line);
91  }
92 
93  std::string get_line(text_iterator line_start) const
94  {
95  text_iterator line_end = line_start;
96  while (line_end != detail::s_end && *line_end != '\r' && *line_end != '\n') {
97  ++line_end;
98  }
99  return std::string(line_start, line_end);
100  }
101 
102  template <typename TokenIter>
103  void generate_error_string(const TokenIter& first,
104  const TokenIter& it,
105  const boost::spirit::info& rule_name,
106  std::string& str) const
107  {
108  std::stringstream is;
109 
110  GG::text_iterator line_start;
111  unsigned int line_number;
112  GG::text_iterator text_it = it->matched().begin();
113  if (it->matched().begin() == it->matched().end()) {
114  text_it = *detail::s_text_it;
115  if (text_it != detail::s_end)
116  ++text_it;
117  }
118  boost::tie(line_start, line_number) = line_start_and_line_number(text_it);
119  std::size_t column_number = std::distance(line_start, text_it);
120 
121  is << detail::s_filename << ":" << line_number << ":" << column_number << ": "
122  << "Parse error: expected " << rule_name;
123 
124  if (text_it == detail::s_end) {
125  is << " before end of input.\n";
126  } else {
127  is << " here:\n"
128  << " " << get_line(line_start) << "\n"
129  << " " << std::string(column_number, ' ') << '^' << std::endl;
130  }
131 
132  str = is.str();
133  }
134  };
135 
136  template <typename TokenType>
137  boost::function<void (const std::string&)> report_error_<TokenType>::send_error_string =
138  &detail::default_send_error_string;
139 
140 }
141 
142 #endif