我有一个记录解析器,它会抛出几个异常中的一个来指示哪个规则失败了.
前面的事:
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>
using namespace boost::spirit;
using namespace boost::spirit::ascii;
using namespace boost::spirit::qi;
using namespace boost::spirit::qi::labels;
using boost::phoenix::function;
using boost::phoenix::ref;
using boost::spirit::qi::eol;
using boost::spirit::qi::fail;
using boost::spirit::qi::lit;
using boost::spirit::qi::on_error;
using BOOST_SPIRIT_CLASSIC_NS::file_position;
using BOOST_SPIRIT_CLASSIC_NS::position_iterator;
Run Code Online (Sandbox Code Playgroud)
我们使用position_iterator来自Spirit.Classic,因此以下流插入运算符非常方便.
std::ostream&
operator<<(std::ostream& o, const file_position &fp)
{
o << fp.file << ": " << fp.line << ',' << fp.column;
return o;
}
Run Code Online (Sandbox Code Playgroud)
模板会err_t因为抛出与不同形式的解析失败相关的异常而触发样板.
template <typename Exception>
struct err_t { …Run Code Online (Sandbox Code Playgroud) 我一直在努力尝试(逐步)修改文档中的示例代码,但没有太大的不同,我没有得到我期望的行为.具体来说,"if"语句在(我的意图是)它应该传递时失败(有一个"else"但是在调试期间删除了部分解析器).赋值语句工作正常.我有一个"while"语句,它与"if"语句有同样的问题,所以我相信如果我能得到帮助来弄清楚为什么一个不工作它应该很容易让另一个去.它必须是一种微妙的,因为这几乎是逐字逐句的,其中一个例子.
#include <iostream>
#include <fstream>
#include <string>
#define BOOST_SPIRIT_DEBUG
#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 <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
inline std::string read_from_file( const char* infile )
{
std::ifstream instream( infile );
if( !instream.is_open() )
{
std::cerr << "Could not open file: \"" << infile << "\"" << std::endl;
exit( -1 );
}
instream.unsetf( std::ios::skipws );
return( std::string(
std::istreambuf_iterator< char >( instream.rdbuf() ),
std::istreambuf_iterator< char >()
) );
}
template< typename …Run Code Online (Sandbox Code Playgroud) 我正在阅读Boost Spirit(和Boost Fusion)教程(版本1.48.0).我一直在玩玩具员工的例子.链接到源是这里:
http://www.boost.org/doc/libs/1_48_0/libs/spirit/example/qi/employee.cpp
这是示例的语法:
employee_parser() : employee_parser::base_type(start)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using ascii::char_;
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>> int_ >> ','
>> quoted_string >> ','
>> quoted_string >> ','
>> double_
>> '}'
;
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
qi::rule<Iterator, employee(), ascii::space_type> start;
Run Code Online (Sandbox Code Playgroud)
我的修改删除了引号的处理,只解析分隔符之间的任何字符,并将其分配给解析器映射到的结构.
//quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>> int_ >> ','
>> +(char_) …Run Code Online (Sandbox Code Playgroud) 我正在攻击的一个简单的骨架实用程序的一部分我有一个语法来触发文本中的替换.我认为这是一种很好的方式来适应Boost.Spirit,但模板错误是一种独特的喜悦.
以下是完整的代码:
#include <iostream>
#include <iterator>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace bsq = boost::spirit::qi;
namespace {
template<typename Iterator>
struct skel_grammar : public bsq::grammar<Iterator> {
skel_grammar();
private:
bsq::rule<Iterator> macro_b;
bsq::rule<Iterator> macro_e;
bsq::rule<Iterator, bsq::ascii::space_type> id;
bsq::rule<Iterator> macro;
bsq::rule<Iterator> text;
bsq::rule<Iterator> start;
};
template<typename Iterator>
skel_grammar<Iterator>::skel_grammar() : skel_grammar::base_type(start)
{
text = bsq::no_skip[+(bsq::char_ - macro_b)[bsq::_val += bsq::_1]];
macro_b = bsq::lit("<<");
macro_e = bsq::lit(">>");
macro %= macro_b >> id >> macro_e;
id %= -(bsq::ascii::alpha | bsq::char_('_'))
>> +(bsq::ascii::alnum | bsq::char_('_'));
start = *(text | macro); …Run Code Online (Sandbox Code Playgroud) 所以我想用boost :: spirit :: qi编写一个......那么......不那么简单的解析器.我知道提升精神的基本知识,在过去的几个小时里第一次熟悉它.
基本上我需要解析这个:
# comment
# other comment
set "Myset A"
{
figure "AF 1"
{
i 0 0 0
i 1 2 5
i 1 1 1
f 3.1 45.11 5.3
i 3 1 5
f 1.1 2.33 5.166
}
figure "AF 2"
{
i 25 5 1
i 3 1 3
}
}
# comment
set "Myset B"
{
figure "BF 1"
{
f 23.1 4.3 5.11
}
}
set "Myset C"
{
include "Myset …Run Code Online (Sandbox Code Playgroud) 假设我有一个我想用Spirit Qi解析的结构,定义如下:
struct data_
{
bool export;
std::wstring name;
data_() : export(false) {}
};
Run Code Online (Sandbox Code Playgroud)
另外,假设结构已适应融合,如下所示:
BOOST_FUSION_ADAPT_STRUCT(
data_,
(bool, export)
(std::wstring, name)
)
Run Code Online (Sandbox Code Playgroud)
相关规则是:
qi::rule<Iterator, data_(), skipper<Iterator> > rule_data;
rule_data = -lexeme["SpecialText" >> !(alnum | '_')] [ boost::phoenix::at_c<0> = true ] // If this string is found, , set "export" to true
> lexeme["Name" >> !(alnum | '_')] // this is supposed to go into the "name" member
Run Code Online (Sandbox Code Playgroud)
到目前为止,这编译得非常好.但是,"名字"现在保持空白!
基本上,我问:鉴于"SpecialText"在"Name"之前,我如何正确地合成"export"的布尔属性,而不是字符串?
编辑 把我的头发拉出来之后,我随机偶然发现了"匹配[]"解析器,这似乎做了我想要的.
尽管如此,问题仍然存在于一般形式中,例如,如果我想返回某个字符串或其他数据类型而不是bool.本质上,如何通过语义操作设置struct属性的特定成员.
我想将一些旧的手写解析代码转换为Boost Spirit,并在此过程中学习(更多)精神.旧代码使用流和模板来解析某些数据类型和某些容器的定义.
一些典型的格式:
VECTOR[number_of_items,(item_1, item_2 .... item_n)]
PAIR(p1, p2)
RECT[(left,top)-(right,bottom)]
Point( x, y )
Size( x, y )
Run Code Online (Sandbox Code Playgroud)
解析函数是模板,其中项目的类型作为模板参数,并使用流作为输入,例如
template<class T> std::istream& operator>>(std::Stream& in, std::vector<T>& v);
template<class T1, class T2> std::istream& operator>>(std::istream& in, std::pair<T1, T2>& p);
template<class T1, class T2> std::istream& operator>>(std::istream& in, RectType<T>& r);
etc.
Run Code Online (Sandbox Code Playgroud)
向量的解析器(流提取器)调用解析器以获取模板类型.
使用这些可以解析整数矩形,双矩形以及字符串和整数对的向量的定义.
是否有可能使用Spirit编写模板解析器来调用模板类型的子解析器?
#include <iostream>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main ()
{
using qi::string;
std::string input("a");
std::string::iterator strbegin = input.begin();
std::string p;
bool ok = qi::phrase_parse(strbegin, input.end(),
((string("a") >> string("a")) | string("a")),
qi::space,
p);
if (ok && strbegin == input.end()) {
std::cout << p << std::endl;
std::cout << p.size() << std::endl;
} else {
std::cout << "fail" << std::endl;
std::cout << std::string(strbegin, input.end()) << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
该计划输出aa.这怎么可能?输入字符串是a.解析器应匹配aa或a.我写的string("a")只是测试运营商.
使用时char_ …
我的目的是将逗号分隔的值列表解析为嵌套向量.这个清单是二维的.基本问题是:
像"牵引"下的表格:
'
' RPM
0,5000,10000,15000,20000,25000
'
' Temp
'
-40.,0.,20.,40.
'
' Traction
200.,175.,170.,165.,160.,150.
200.,175.,170.,165.,160.,150.
165.,165.,160.,155.,145.,145.
160.,155.,150.,145.,145.,140.
'
Run Code Online (Sandbox Code Playgroud)
在接下来的步骤中,我想阅读4维数据,但是现在我正在努力解决第二个问题.数据结构如下:
struct table {
std::vector<double> index;
std::vector<double> index2;
std::vector<std::vector<double> > base;
};
Run Code Online (Sandbox Code Playgroud)
语法是恕我直言,非常简单如下:
comment %= qi::lexeme[ '\'' >> *(qi::standard::char_ - qi::eol)] >> qi::eol;
commentblock = comment >> *(comment);
doublevector = qi::double_ % ',' >> qi::eol ;
vectorblock = *doublevector;
start = commentblock >>
doublevector >>
commentblock >>
doublevector >>
commentblock >>
vectorblock >>
commentblock >>
qi::eoi
;
Run Code Online (Sandbox Code Playgroud)
到目前为止,我解析这两个向量 …
我正在尝试将LaTeX转义码(例如\alpha)解析为Unicode(数学)字符(即U+1D6FC).
现在这意味着我正在使用这个symbols解析器(规则):
struct greek_lower_case_letters_ : x3::symbols<char32_t>
{
greek_lower_case_letters_::greek_lower_case_letters_()
{
add("alpha", U'\u03B1');
}
} greek_lower_case_letter;
Run Code Online (Sandbox Code Playgroud)
这很好,但意味着我得到了std::u32string一个结果.我想要一种优雅的方法来保持代码中的Unicode代码点(可能是未来的自动化)和维护原因.有没有办法让这种解析器解析为UTF-8 std::string?
我想过将symbolsstruct解析为a std::string,但这样效率非常低(我知道,早期优化bla bla).
我希望有一些优雅的方式,而不是通过一堆箍来使这工作(symbols将结果附加到字符串).
我担心使用代码点值并想要UTF8会产生转换的运行时成本(或者是否有constexprUTF32-> UTF8转换?).
boost-spirit ×10
c++ ×10
boost ×5
parsing ×4
attributes ×1
c++14 ×1
eol ×1
stdvector ×1
synthesize ×1
templates ×1