今天看看error_handler.hpp,先把这些周边的东西搞清楚。
///////////////////////////////////////////////////////////////////////////////
// The error handler
///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct error_handler
{
template <typename, typename, typename>
struct result { typedef void type; };
error_handler(Iterator first, Iterator last)
: first(first), last(last) {}
//...
Iterator first;
Iterator last;
std::vector<Iterator> iters;
};
error_handler.hpp比较简单,只定义了error_handler一个模板类。包含三个成员变量:first、last和iters。first和last代表要解析的字符串的起始位置。iters比较奇怪,它在error_handler里定义,但在error_handler里一次都没用。翻翻其它代码,发现这个iters由annotation类使用,annotation类保存对这个iters数组的引用。每次出现一个需要标记的语法对象,annotation类就在iters里记录下该对象的位置,而对象的id就是iters数组的下标。从而通过对象id可以直接查到对象对代码中的确切位置。
struct result是为了boost::result_of准备的。error_handler是个函数对象,因此它的返回值需要通过这种特殊方法标记。
template <typename Message, typename What>
void operator()(
Message const& message,
What const& what,
Iterator err_pos) const
{
int line;
Iterator line_start = get_pos(err_pos, line);
if (err_pos != last)
{
std::cout << message << what << " line " << line << ':' << std::endl;
std::cout << get_line(line_start) << std::endl;
for (; line_start != err_pos; ++line_start)
std::cout << ' ';
std::cout << '^' << std::endl;
}
else
{
std::cout << "Unexpected end of file. ";
std::cout << message << what << " line " << line << std::endl;
}
}
上面这个函数是函数对象方法的实现。message和what的类型都是泛型的。大概就是通过出错的位置找到出错行的起始位置和行号,再判断出错位置是否达到待解析字符串末尾。根据情况给出不同的提示。
Iterator get_pos(Iterator err_pos, int& line) const
{
line = 1;
Iterator i = first;
Iterator line_start = first;
while (i != err_pos)
{
bool eol = false;
if (i != err_pos && *i == '\r') // CR
{
eol = true;
line_start = ++i;
}
if (i != err_pos && *i == '\n') // LF
{
eol = true;
line_start = ++i;
}
if (eol)
++line;
else
++i;
}
return line_start;
}
Iterator get_pos(Iterator err_pos, int& line) const { line = 1; Iterator i = first; Iterator line_start = first; while (i != err_pos) { bool eol = false; if (i != err_pos && *i == '\r') // CR { eol = true; line_start = ++i; } if (i != err_pos && *i == '\n') // LF { eol = true; line_start = ++i; } if (eol) ++line; else ++i; } return line_start; }
Iterator get_pos(Iterator err_pos, int& line) const { line = 1; Iterator i = first; Iterator line_start = first; while (i != err_pos) { bool eol = false; if (i != err_pos && *i == '\r') // CR { eol = true; line_start = ++i; } if (i != err_pos && *i == '\n') // LF { eol = true; line_start = ++i; } if (eol) ++line; else ++i; } return line_start; }
根据出错位置找出出错行的起始位置和行号。从头开始一个字符一个字符地找,很简单。
std::string get_line(Iterator err_pos) const
{
Iterator i = err_pos;
// position i to the next EOL
while (i != last && (*i != '\r' && *i != '\n'))
++i;
return std::string(err_pos, i);
}
获取从出错位置开始到出错行末的字符串。也很简单。
error_handler用于定义rule出错时的处理。定义出错处理的函数:
on_error<Action>(rule, handler)
其中Action可以是:
|
Description |
---|---|
fail |
Quit and fail. Return a no_match. |
retry |
Attempt error recovery, possibly moving the iterator position. |
accept |
Force success, moving the iterator position appropriately. |
rethrow |
Rethrows the error. |
handler可以是函数或函数对象(error_handler类即用于此处),接受4个参数:
Arg |
Description |
---|---|
first |
The position of the iterator when the rule with the handler was entered. |
last |
The end of input. |
error-pos |
The actual position of the iterator where the error occured. |
what |
What failed: a string describing the failure. |
但error_handler只接受3个参数。因此中间需要用类似boost::bind的技巧转换一下。
bind(error_handler, "Erorr! Expecting ", _4, _3)
但mini_c里用的是boost::phoenix::function,具体情况下回分解