我有一个由混合变量($(name)
)和变量值对($(name:value)
)组成的简单语法。我有一个手工编码的递归解析器,但我有兴趣将它用作学习Spirit的练习,最终我需要更复杂的语法(/很快)。
无论如何,我正在使用的一组可能的表单(从完整语法中简化)是:
$(variable) // Uses simple look-up, recursion and inline replace
$(name:value) // Inserts a new variable into the local lookup table
我目前的规则如下:
typedef std::map<std::string, std::string> dictionary;
template <typename Iterator>
bool parse_vars(Iterator first, Iterator last, dictionary & vars, std::string & output)
{
using qi::phrase_parse;
using qi::_1;
using ascii::char_;
using ascii::string;
using ascii::space;
using phoenix::insert;
dictionary statevars;
typedef qi::rule<Iterator, std::string()> string_rule;
typedef qi::rule<Iterator, std::pair<std::string, std::string>()> pair_rule;
string_rule state = string >> ':' >> string; // Error 3
pair_rule variable =
(
char_('$') >> '(' >>
(
state[insert(phoenix::ref(statevars), _1)] |
string[output += vars[_1]] // Error 1, will eventually need to recurse
) >> ')'
); // Error 2
bool result = phrase_parse
(
first, last,
(
variable % ','
),
space
);
return r;
}
如果不是很明显,我不知道精神是如何工作的,而且文档除了实际解释之外还有其他所有内容,所以这是一个小时的例子。
我特别质疑的部分是变量规则中的前导char_('$')
,但删除它会导致移位运算符错误(编译器会将'$' >> '('
解释为右移)。
编译时,我收到与 state 规则相关的错误,特别是创建该对和查找:
将查找(vars[_1]
)更改为简单的+=
会产生:
3 。错误C2665:'boost :: spirit :: char_class :: classify :: is':15个重载中没有一个可以转换所有参数类型
错误1似乎与_1
占位符的类型(属性?)有关,但它应该是一个字符串,是用于打印或连接到输出字符串。 2似乎是由1引起的噪音。
错误3,挖掘模板错误堆栈,似乎与无法将 state 规则转换为一对相关,这似乎很奇怪,因为它几乎完全符合其中一条规则this example
如何修改变量规则以正确处理两种输入表单?
答案 0 :(得分:2)
有几点需要注意:
要调整std::pair
(以便您可以将它与地图一起使用),您应该包括(至少)
#include <boost/fusion/adapted/std_pair.hpp>
看起来您正在尝试创建符号表。您可以使用qi::symbols
作为
避免将输出生成与解析混合在一起,这会使事情过度复杂化
我没有“修复”上述所有内容(由于缺乏上下文),但我很乐意帮助解决其中的任何其他问题。
这是一个与OP非常接近的固定代码版本。 编辑现在也测试了它,输出如下:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::map<std::string, std::string> dictionary;
template <typename Iterator, typename Skipper = qi::space_type>
struct parser : qi::grammar<Iterator, Skipper>
{
parser(dictionary& statevars, std::string& output) : parser::base_type(start)
{
using namespace qi;
using phx::insert;
with_initializer = +~char_(":)") >> ':' >> *~char_(")");
simple = +~char_(")");
variable =
"$(" >> (
with_initializer [ insert(phx::ref(statevars), qi::_1) ]
| simple [ phx::ref(output) += phx::ref(statevars)[_1] ]
) >> ')';
start = variable % ',';
BOOST_SPIRIT_DEBUG_NODE(start);
BOOST_SPIRIT_DEBUG_NODE(variable);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(with_initializer);
}
private:
qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> with_initializer;
qi::rule<Iterator, std::string(), Skipper> simple;
qi::rule<Iterator, Skipper> variable;
qi::rule<Iterator, Skipper> start;
};
template <typename Iterator>
bool parse_vars(Iterator &first, Iterator last, dictionary & vars, std::string & output)
{
parser<Iterator> p(vars, output);
return qi::phrase_parse(first, last, p, qi::space);
}
int main()
{
const std::string input = "$(name:default),$(var),$(name)";
std::string::const_iterator f(input.begin());
std::string::const_iterator l(input.end());
std::string output;
dictionary table;
if (!parse_vars(f,l,table,output))
std::cerr << "oops\n";
if (f!=l)
std::cerr << "Unparsed: '" << std::string(f,l) << "'\n";
std::cout << "Output: '" << output << "'\n";
}
输出:
Output: 'default'
答案 1 :(得分:-2)
你必须有char _(&#39; $&#39;)否则&gt;&gt;是&#39; char&#39;在两边 - 你需要至少有一种精神类型来获得重载的运算符&gt;&gt ;.
您可能还需要使用凤凰城的_1。
另请看一下: http://boost-spirit.com/home/articles/qi-example/parsing-a-list-of-key-value-pairs-using-spirit-qi/