我只使用Boost.Spirit(来自Boost 1.44)三天,试图通过RFC2822中的确切语法解析原始电子邮件.我以为我开始理解它并到达某个地方,但后来我遇到了一个问题:
#include <iostream>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using qi::omit;
using qi::repeat;
using std::cout;
using std::endl;
typedef qi::rule<std::string::const_iterator, std::string()> strrule_t;
void test(const std::string input, strrule_t rule) {
std::string target;
std::string::const_iterator i = input.begin(), ie = input.end();
if (qi::parse(i, ie, rule, target)) {
cout << "Success: '" << target << "'" << endl;
} else {
cout << "Failed to match." << endl;
}
}
int main() {
strrule_t obsolete_year = omit[-qi::char_(" \t")] >> repeat(2)[qi::digit] >>
omit[-qi::char_(" \t")];
strrule_t …Run Code Online (Sandbox Code Playgroud) 我有一个简单的配置文件解析器,由spirit :: lex和spirit :: qi构建.当词法分析器到达模式时,include "path"我希望包含文件的文本.您可能知道,spirit :: lexer :: begin()启动扫描过程:
// Read file contents into a std::string
...
// _first and _last are const char*
_first = _contents.c_str();
_last = &_first[_input.size()];
// _token is a lexer::iterator_type for the current token
_token = _lexer.begin(_first, _last);
Run Code Online (Sandbox Code Playgroud)
我的想法是有一个存储lexer状态的堆栈表示为结构:
struct LexerState
{
const char* first;
const char* last;
std::string contents;
};
Run Code Online (Sandbox Code Playgroud)
词法分析器将识别模式,include "path"并在语义动作中提取包含文件的路径.然后,将当前词法分析器状态推入堆栈,将文件的内容加载到字符串中,并使用lexer :: begin()按上述方式初始化新状态.
当词法分析器找到EOF字符时,弹出堆栈并使用先前的词法分析器状态变量调用lexer :: begin().
可以这样重复调用lexer :: begin()吗?如何让lex :: lexer识别include "path"模式和EOF字符而不将令牌返回到qi解析器?
最后,有没有其他或更好的方法来实现这一目标?
我尝试继续处理我之前的示例并扩展规则.我的问题是,使用ID_IDENTIFIER的规则不起作用 - 虽然我知道词法分析器正在工作(使用单元测试).
这是一个例子:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
enum LexerIDs { ID_IDENTIFIER, ID_WHITESPACE, ID_INTEGER, ID_FLOAT, ID_PUNCTUATOR };
template <typename Lexer>
struct custom_lexer : lex::lexer<Lexer>
{
custom_lexer()
: identifier ("[a-zA-Z_][a-zA-Z0-9_]*")
, white_space ("[ \\t\\n]+")
, integer_value ("[1-9][0-9]*")
, hex_value ("0[xX][0-9a-fA-F]+")
, float_value ("[0-9]*\\.[0-9]+([eE][+-]?[0-9]+)?")
, float_value2 ("[0-9]+\\.([eE][+-]?[0-9]+)?")
, punctuator ("\\[|\\]|\\(|\\)|\\.|&>|\\*\\*|\\*|\\+|-|~|!|\\/|%|<<|>>|<|>|<=|>=|==|!=|\\^|&|\\||\\^\\^|&&|\\|\\||\\?|:|,")// [ ] ( ) . &> ** * + - ~ ! / % << >> < > <= >= == != ^ & …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用boost精神框架来定义自己的语法,并且我正在定义这样的匹配规则:
value = (
char_('"') >>
(*qi::lexeme[
char_('\\') >> char_('\\') |
char_('\\') >> char_('"') |
graph - char_('"') |
char_(' ')
])[some_func] >>
char_('"')
);
Run Code Online (Sandbox Code Playgroud)
我想将一个动作 - some_func - 分配到它的一部分,并将整个匹配的字符串作为参数传递.但不幸的是,我会得到类似的东西vector<boost::variant<boost::fusion::vector2 ..a lot of stuff...)...>.我可以以某种方式将整个数据作为char*,std :: string甚至void*与大小?
假设我有一个我想用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属性的特定成员.
#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_ …
如何在使用有效关键字(符号)启动时阻止Boost Spirit符号解析器接受关键字(符号).我希望构造失败解析'ONEMORE'作为一个整体而不能成功解析'ONE',因为这是一个有效的关键字,然后在'MORE'失败.
以下是代码的实际输出:
Keyword as a number: 1
Keyword as a number: 2
Keyword as a number: 1
Invalid keyword: MORETHREE
Run Code Online (Sandbox Code Playgroud)
这就是我喜欢的:
Keyword as a number: 1
Keyword as a number: 2
Invalid keyword: ONEMORE
Keyword as a number: 3
Run Code Online (Sandbox Code Playgroud)
代码只是一个示例来获得重点.
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
using namespace std;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
void printNumber( unsigned u )
{
cout << "Keyword as a number: " << u << endl;
}
void printInvalidKeyword( …Run Code Online (Sandbox Code Playgroud) 我已经问过这个问题.但由于没有答案,我现在再次询问完整的可编辑源代码片段.
由于boost :: variant move semantic存在一些问题,因此应该使用no std = c ++ 11选项编译此代码段.只是'g ++ -Wall -pedantic'.
在此代码段中,您将找到"// Comment here"行.您可以在下面的句子中发表评论,直到"//这里-----".如果取消注释此块,则此程序的性能非常差.
所以只要我能看到瓶颈就是替代解析器.我需要的是一些关于改进/改变我的语法以提高解析性能的建议.谢谢.
码:
#include <string>
#include <vector>
#include <iostream>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#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_object.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/array.hpp>
#include <boost/variant/apply_visitor.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
namespace client {
typedef std::string::iterator input_iterator_type;
struct op_and {};
struct op_or …Run Code Online (Sandbox Code Playgroud) 我的目的是将逗号分隔的值列表解析为嵌套向量.这个清单是二维的.基本问题是:
像"牵引"下的表格:
'
' 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)
到目前为止,我解析这两个向量 …
你能帮助我理解Boost.Spirit中a % b解析器和它的扩展a >> *(b >> a)形式之间的区别吗?即使参考手册指出它们是等效的,
列表运算符
a % b是一个二元运算符,它匹配a由出现次数分隔的一个或多个重复的列表b.这相当于a >> *(b >> a).
以下程序根据使用的结果产生不同的结果:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
struct Record {
int id;
std::vector<int> values;
};
BOOST_FUSION_ADAPT_STRUCT(Record,
(int, id)
(std::vector<int>, values)
)
int main() {
namespace qi = boost::spirit::qi;
const auto str = std::string{"1: 2, 3, 4"};
const auto rule1 = qi::int_ >> ':' >> (qi::int_ % ',') >> …Run Code Online (Sandbox Code Playgroud) boost-spirit ×10
c++ ×10
boost ×9
attributes ×1
parsing ×1
stdvector ×1
symbols ×1
synthesize ×1