Ответ 1
Это действительно хороший вопрос (а также банда червей), потому что он попадает в интерфейс ци и феникса. Я тоже не видел примера, поэтому я немного расширю статью в этом направлении.
Как вы говорите, функции для семантических действий могут принимать до трех параметров
- Соответствующий атрибут - рассматривается в статье
- Контекст - содержит интерфейс qi-phoenix
- флаг соответствия - манипулировать состоянием соответствия
Флажок соответствия
Как говорится в статье, второй параметр не имеет смысла, если выражение не является частью правила, поэтому давайте начнем с третьего. Заполнитель для второго параметра все еще необходим, и для этого используйте boost::fusion::unused_type
. Поэтому для использования третьего параметра используется модифицированная функция:
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>
void f(int attribute, const boost::fusion::unused_type& it, bool& mFlag){
//output parameters
std::cout << "matched integer: '" << attribute << "'" << std::endl
<< "match flag: " << mFlag << std::endl;
//fiddle with match flag
mFlag = false;
}
namespace qi = boost::spirit::qi;
int main(void){
std::string input("1234 6543");
std::string::const_iterator begin = input.begin(), end = input.end();
bool returnVal = qi::phrase_parse(begin, end, qi::int_[f], qi::space);
std::cout << "return: " << returnVal << std::endl;
return 0;
}
который выводит:
matched integer: '1234' match flag: 1 return: 0
Весь этот пример - это переключение соответствия на несоответствие, которое отражается в выходе парсера. Согласно hkaiser, в boost 1.44 и up, если флаг соответствия false, приведет к тому, что совпадение завершится неудачно. Если альтернативы определены, синтаксический анализатор отступит и попытается сопоставить их, как можно было бы ожидать. Однако в boost <= 1.43 ошибка Spirit предотвращает обратное отслеживание, что вызывает странное поведение. Чтобы увидеть это, добавьте phoenix include boost/spirit/include/phoenix.hpp
и измените выражение на
qi::int_[f] | qi::digit[std::cout << qi::_1 << "\n"]
Вы ожидаете, что когда qi:: int parser завершится с ошибкой, альтернативный qi:: digit будет соответствовать началу ввода на "1", но на выходе будет:
matched integer: '1234' match flag: 1 6 return: 1
6
- это первая цифра второго int на входе, которая указывает, что альтернатива берется с помощью шкипера и без обратного слежения. Также обратите внимание, что матч считается успешным на основе альтернативы.
После того, как форвард 1.44 отсутствует, флаг соответствия будет полезен для применения критериев соответствия, которые в противном случае трудно выразить в последовательности парсера. Обратите внимание, что флаг соответствия можно манипулировать в выражениях феникса с помощью _pass
placeholder.
Контекстный параметр
Более интересным параметром является второй, который содержит интерфейс qi-phoenix или qi-язык, контекст семантического действия. Чтобы проиллюстрировать это, сначала проверьте правило:
rule<Iterator, Attribute(Arg1,Arg2,...), qi::locals<Loc1,Loc2,...>, Skipper>
Параметр контекста воплощает параметры шаблона Attribute, Arg1,... ArgN и qi:: locals, завернутые в тип шаблона boost:: spirit:: context. Этот атрибут отличается от параметра функции: атрибут параметра функции - это разобранное значение, а этот атрибут - значение самого правила. Семантическое действие должно сопоставить первое с последним. Здесь приведен пример возможного типа контекста (эквивалент выражения феникса):
using namespace boost;
spirit::context< //context template
fusion::cons<
int&, //return int attribute (phoenix: _val)
fusion::cons<
char&, //char argument1 (phoenix: _r1)
fusion::cons<
float&, //float argument2 (phoenix: _r2)
fusion::nil //end of cons list
>,
>,
>,
fusion::vector2< //locals container
char, //char local (phoenix: _a)
unsigned int //unsigned int local (phoenix: _b)
>
>
Обратите внимание, что атрибут return и список аргументов принимают форму списка lisp -style (
qi::rule<std::string::const_iterator,int(void),ascii::space_type>
intRule %= qi::int_;
Изменить: доступ к контексту правила w/Phoenix
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
int main(void){
std::string input("1234, 6543, 42");
std::string::const_iterator begin = input.begin(), end = input.end();
qi::rule<
std::string::const_iterator,
int(int), //output (_val) and input (_r1)
qi::locals<int>, //local int (_a)
ascii::space_type
>
intRule =
qi::int_[qi::_a = qi::_1] //local = x1
>> ","
>> qi::int_[qi::_a += qi::_1] //local = x1 + x2
>> ","
>> qi::int_
[
qi::_val = qi::_a*qi::_1 + qi::_r1 //output = local*x3 + x0
];
int ruleValue, x0 = 10;
qi::phrase_parse(begin, end, intRule(x0), ascii::space, ruleValue);
std::cout << "rule value: " << ruleValue << std::endl;
return 0;
}
namespace ph = boost::phoenix;
...
qi::rule<
std::string::const_iterator,
int(int),
ascii::space_type
>
intRule =
(qi::int_ % ",")
[
qi::_val = (ph::at(qi::_1,0) + ph::at(qi::_1,1))
* ph::at(qi::_1,2) + qi::_r1
];
....
(qi::int_ >> "," >> qi::int_ >> "," >> qi::int_)
[
qi::_val = (qi::_1 + qi::_2) * qi::_3 + qi::_r1
];