我在编写一个小精神/ qi语法时遇到了问题.我正在使用boost 1.43和g ++ 4.4.1.
输入语法标题:构建错误似乎指向'指令'规则的定义,也许是'[sp :: _ val = sp :: _ 1]'以某种方式破坏了它,但这或多或少基于关于精神文档教程使用xml节点解析器做了什么
inputGrammar.h
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
using namespace boost::spirit::ascii;
//using namespace boost::spirit::arg_names;
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
using phoenix::at_c;
using phoenix::push_back;
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), space_type> …Run Code Online (Sandbox Code Playgroud) 看看这个用于实现Spirit解析器的示例,当我尝试编写类似的东西时,有些事情让我感到困惑.
语法(std::map<std::string, std::string>())的属性模板参数和规则的签名模板参数(例如qi::rule<Iterator, std::string()> key, value)包含括号.
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct keys_and_values
: qi::grammar<Iterator, std::map<std::string, std::string>()> // <- parentheses here
{
keys_and_values()
: keys_and_values::base_type(query)
{
query = pair >> *((qi::lit(';') | '&') >> pair);
pair = key >> -('=' >> value);
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
value = +qi::char_("a-zA-Z_0-9");
}
qi::rule<Iterator, std::map<std::string, std::string>()> query; // <- parentheses here
qi::rule<Iterator, std::pair<std::string, std::string>()> pair; // <- parentheses here
qi::rule<Iterator, std::string()> key, …Run Code Online (Sandbox Code Playgroud) 要实现对typedef的支持,当lexer识别标识符并返回不同的标记时,您需要查找符号表.这在flex lexer中很容易完成.我试图使用boost Spirit来构建解析器并在示例中查看,但它们都没有在词法分析器和解析器之间传递任何上下文信息.在mini c编译器教程示例中,最简单的方法是什么?
我有以下符合预期的语法。
struct query_term {
std::string term;
bool is_tag;
query_term(const std::string &a, bool tag = false): term(a), is_tag(tag) { } };
template<typename Iterator> struct query_grammar: grammar<Iterator, std::vector<query_term>(), space_type> {
query_grammar():
query_grammar::base_type(query) {
word %= +alnum;
tag = (omit[word >> ':'] >> word[_val = phoenix::construct<query_term>(_1, true)]);
non_tag = word[_val = phoenix::construct<query_term>(_1, false)];
query = (
(omit[word >> ':'] >> word[push_back(_val, phoenix::construct<query_term>(_1, true))])
|
word[push_back(_val,
phoenix::construct<query_term>(_1))
]
) % space;
};
qi::rule<Iterator, std::string(), space_type> word;
qi::rule<Iterator, query_term, space_type> tag;
qi::rule<Iterator, query_term, space_type> non_tag; …Run Code Online (Sandbox Code Playgroud) 我有一个非常简单的路径构造,我试图用boost spirit.lex解析.
我们有以下语法:
token := [a-z]+
path := (token : path) | (token)
Run Code Online (Sandbox Code Playgroud)
所以我们这里只讨论冒号分隔的小写ASCII字符串.
我有三个例子"xyz","abc:xyz","abc:xyz:".
前两个应被视为有效.第三个,有一个尾随结肠,不应被视为有效.不幸的是,解析器我已经认识到这三个都是有效的.语法不应该允许空令牌,但显然精神就是这样做的.为了让第三个被拒绝,我错过了什么?
此外,如果您阅读下面的代码,则在注释中还有另一个版本的解析器要求所有路径以分号结尾.当我激活那些线时,我可以得到适当的行为(即拒绝"abc:xyz:;"),但这不是我想要的.
有人有主意吗?
谢谢.
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
using boost::phoenix::val;
template<typename Lexer>
struct PathTokens : boost::spirit::lex::lexer<Lexer>
{
PathTokens()
{
identifier = "[a-z]+";
separator = ":";
this->self.add
(identifier)
(separator)
(';')
;
}
boost::spirit::lex::token_def<std::string> identifier, separator;
};
template <typename Iterator>
struct PathGrammar
: boost::spirit::qi::grammar<Iterator>
{
template <typename TokenDef>
PathGrammar(TokenDef const& tok)
: PathGrammar::base_type(path)
{
using boost::spirit::_val; …Run Code Online (Sandbox Code Playgroud) 我正在尝试为数学表达式编写一个解析器,其中命名变量是boost::spirit(版本1_51_0)中的nullaries,我完全是新的.我定义typedef boost::function<double()> Value,我的规则将被声明如下:qi::rule<Iterator, Value()> expression, term, others, ...;
我用这个宏定义了nullaries上的二元运算符
#define BINARY_FUNCTOR(name, op) \
struct name \
{ \
name(Value x, Value y): x_(x), y_(y) {} \
double operator()() { return x_() op y_(); } \
Value x_, y_; \
};
Run Code Online (Sandbox Code Playgroud)
并且有ADD,SUB等从我所看到的例子,我期望的规则,这样的定义:
expression = term
>> *( (lit('+') >> term[ADD(_val, _1)])
| (lit('-') >> term[SUB(_val, _1)])
);
Run Code Online (Sandbox Code Playgroud)
但这似乎不是正确的语法,因为我得到一个错误
boost/spirit/home/support/action_dispatch.hpp:162: error: no match for call to ‘(const<unnamed>::SUB) (boost::function<double ()()>&, boost::spirit::context<boost::fusion::cons<boost::function<double ()()>&, boost::fusion::nil>, boost::fusion::vector0<void> …Run Code Online (Sandbox Code Playgroud) 在比较boost :: lexical_cast和boost spirit解析时,我注意到了一些奇怪的东西.我正在尝试将字符串解析为float.由于某种原因,精神给出了非常不精确的结果.例如:当使用lexical_cast解析字符串"219721.03839999999"时,我得到219721.03,这或多或少都可以.但是当我使用精神(见下面的代码)时,我得到了"219721.11",这远远不是好的.知道为什么会这样吗?
template<>
inline float LexicalCastWithTag(const std::string& arg)
{
float result = 0;
if(arg.empty())
{
throw BadLexicalCast("Cannot convert from to std::string to float");
}
auto itBeg = arg.begin();
auto itEnd = arg.end();
if(!boost::spirit::qi::parse(itBeg, itEnd, boost::spirit::qi::float_, result) || itBeg != itEnd)
{
throw BadLexicalCast("Cannot convert from to std::string to float");
}
return result;
}
Run Code Online (Sandbox Code Playgroud) 我和Spirit Qi有另一个阻碍问题.
我在一个名为error_handler的functor结构中实现了错误处理.这通过引用传递给语法构造函数(参见Qi的MiniC示例).
然后我on_error<fail>在语法的构造函数中定义了:
typedef boost::phoenix::function<error_handler<> > error_handler_function;
on_error<fail>(gr_instruction,
error_handler_function(err_handler)(L"Error: Expecting ", _4, _3));
// more on_error<fail>s...
Run Code Online (Sandbox Code Playgroud)
但是,我error_handler有私人会员.似乎每次都on_error被调用,err_handler对象被复制,因此一旦仿函数离开,局部变量就会被破坏.
我尝试通过引用传递处理程序:
typedef boost::phoenix::function<error_handler<>& > error_handler_function; // <--- Note the ampersand!
on_error<fail>(gr_instruction,
error_handler_function(err_handler)(L"Error: Expecting ", _4, _3));
// more on_error<fail>s...
Run Code Online (Sandbox Code Playgroud)
然而,问题仍然存在:on_error()适用于副本err_handler,而不是单个实例!
我也尝试过boost::phoenix::ref(err_handler)只有编译错误的变体.
当然,必须有一个简单的解决方案来通过引用传递处理程序?
我很感激任何意见.谢谢您的帮助.
我有一个类似的问题,比如如何使用boost :: spirit来解析UTF-8?以及如何使用boost :: spirit匹配unicode字符?但这些都没有解决我面临的问题.我有一个std::stringUTF-8字符,我用它u8_to_u32_iterator来包装std::string和使用这样的unicode终端:
BOOST_NETWORK_INLINE void parse_headers(std::string const & input, std::vector<request_header_narrow> & container) {
using namespace boost::spirit::qi;
u8_to_u32_iterator<std::string::const_iterator> begin(input.begin()), end(input.end());
std::vector<request_header_narrow_utf8_wrapper> wrapper_container;
parse(
begin, end,
*(
+(alnum|(punct-':'))
>> lit(": ")
>> +((unicode::alnum|space|punct) - '\r' - '\n')
>> lit("\r\n")
)
>> lit("\r\n")
, wrapper_container
);
BOOST_FOREACH(request_header_narrow_utf8_wrapper header_wrapper, wrapper_container)
{
request_header_narrow header;
u32_to_u8_iterator<request_header_narrow_utf8_wrapper::string_type::iterator> name_begin(header_wrapper.name.begin()),
name_end(header_wrapper.name.end()),
value_begin(header_wrapper.value.begin()),
value_end(header_wrapper.value.end());
for(; name_begin != name_end; ++name_begin)
header.name += *name_begin;
for(; value_begin != value_end; …Run Code Online (Sandbox Code Playgroud) 我想在语义操作中更改局部变量值,如下所示:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::ref;
using boost::phoenix::bind;
void dummy(const std::vector<char>& v, int& var)
{
var = 7;
}
template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
{
using namespace qi;
int local_var = 0;
start_rule = (+(char_ - ";"))[bind(dummy, _1, ref(local_var))];
//repeat(ref(local_var))[some_rule];
}
private:
qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
};
int main()
{
typedef std::string::const_iterator …Run Code Online (Sandbox Code Playgroud) boost-spirit ×10
c++ ×9
boost ×7
parsing ×2
lexical-cast ×1
reference ×1
templates ×1
utf-8 ×1