boost之spirit学习-mini_c(4)

时间:2021-07-29 20:01:06

今天看看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可以是:

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,具体情况下回分解