C++ 增强精神动力->;qi:获得;“无文件记录”;论高校工作的成功机制
编辑:我已经删除了lexer,因为它没有与Qi完全集成,只是混淆了语法(请参阅)C++ 增强精神动力->;qi:获得;“无文件记录”;论高校工作的成功机制,c++,parsing,boost-spirit,lexer,C++,Parsing,Boost Spirit,Lexer,编辑:我已经删除了lexer,因为它没有与Qi完全集成,只是混淆了语法(请参阅) on_success没有很好的文档记录,我正在尝试将它连接到我的解析器。关于on_success的示例处理的是基于qi构建的解析器,即nolex 以下是我试图介绍该结构的方式: using namespace qi::labels; qi::on_success(event_entry_,std::cout << _val << _1); 查看头文件,我认为占位符的含义是: _1 = I
on_success
没有很好的文档记录,我正在尝试将它连接到我的解析器。关于on_success
的示例处理的是基于qi
构建的解析器,即nolex
以下是我试图介绍该结构的方式:
using namespace qi::labels;
qi::on_success(event_entry_,std::cout << _val << _1);
查看头文件,我认为占位符的含义是:
_1 = Iterator position when the rule was tried.
_2 = Iterator to the end of the input.
_3 = Iterator position right after the rule has been successfully matched.
(因为我不确定上面的行是否可以理解,这里有一个小例子,说明您的输入) 正如GManNickG在评论中提到的,这些是lexer迭代器,您无法使用它们轻松访问原始字符串。组合使用lexer和
on\u error
/on\u success
。为了实现这一点,它使用了一种特殊的令牌,position\u-token
。此令牌始终可以访问与其关联的原始字符串的迭代器对(当您使用lex::omit
时,普通令牌会丢失此信息)position\u token
有几个有趣的方法matched()
返回一个iterator\u范围
,begin()
和end()
返回相应的迭代器
在下面的代码中,我选择创建一个phoenix::function
,它接受两个lexer迭代器(用_1和_3调用),并返回一个覆盖它们之间距离的字符串(使用std::string(begin\u iter->begin(),end\u iter->begin())
)
我发现的一个问题是,空白处于不同状态的事实导致position\u标记
返回的迭代器无效。我解决这个问题的方法是将所有内容都放在相同的状态,然后简单地使用带有空格的lex::\u pass=lex::pass\u flags::pass\u ignore
最后一个(次要)问题是,如果您想使用
std::cout,我可以提供部分答案\u1
、\u2
和\u3
是迭代器(\u1
是规则的开始位置,\u3
是结束位置,我从来没有确定\u2
是什么。)对于我来说,我没有lexer,而是在一个普通的\std::string
上迭代,因此迭代器很容易检查和使用。我不知道lex迭代器是如何工作的。显然,\u val
是刚刚解析的值,您也可以修改它。(我的所有AST节点都派生自包含源信息的基类,因此我的on_success
函数只是将\u 1
和\u 3
的位置复制到\u val
以进行错误报告。)您的错误可能是因为您试图将迭代器插入到一个ostream中,这可能不起作用。如果需要,我可以将这些注释与将被调用的常规success\u handler
函数一起移动到一个答案,但正如前面提到的,您需要自己从词法分析器中找出迭代器。:)据我的测试显示,on_error/on_success不想与您的样本一起工作。。。嗯,谢谢你如此深思熟虑和解释的答案。它还处理了我以前的一个小麻烦,我不得不使用“qi::in_state”作为队长。我确实想切换到上面的样式来跳过空白。我想我现在终于可以开始愤怒地写我的DSL了。唯一缺少的是将我在上面的“事件\限定符”、“原子\类型”和“事件\类型”规则中的“qi::grammar”中所做的token->integer\ id映射移动到lex中。这是最棒的东西。我在那里的“一切”都是一样的,只是我丢失了链接position\u token
+1(@HassanSyed我重新排序声明以匹配初始化顺序。-Wextra
是您的朋友)当我在lexer中的选项
标记上注释语义操作时,会出现奇怪的错误。与分配内存有关。显示在clang++和gcc中。如果我取消对可选和必需的注释,并将输入更改为同时具有这两个必需项,则不会显示:D@HassanSyed似乎是与在lex语义操作中使用\u val
相关的问题。如果在optional
中删除\u val
的打印(我认为这没有意义,因为它的属性是lex::omit),程序在g++4.8.1中不会崩溃。但是序数
和标识符
仍然存在问题,qi似乎无法“看到”它们的属性。我会继续寻找解决方案。@cv_and_he yes打印\u val
没有意义,但奇怪的是\u val
被设置为匹配的字符串,即使省略了。我之所以尝试它,是因为我怀疑我的未分配令牌仍在qi
中暴露一个属性(它们不是:D)。打印令牌只是为了调试,而我正在拼接组件。
_1 = Iterator position when the rule was tried.
_2 = Iterator to the end of the input.
_3 = Iterator position right after the rule has been successfully matched.
rule being tried
_________________________________
´ `
[EVENT][1][:][sihan][{][OPTIONAL][123][:][hassan][int4][;][OPTIONAL][321][:][hassan2][int4][;][}]
_1 _3 _2
#define BOOST_SPIRIT_USE_PHOENIX_V3
// #define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_bind.hpp> //CHANGED
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/lex_lexertl_position_token.hpp> //ADDED
#include <boost/none.hpp>
#include <boost/cstdint.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <exception>
#include <vector>
namespace lex = boost::spirit::lex;
namespace px = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Lexer>
struct tokens : lex::lexer<Lexer>
{
tokens()
: left_curly("\"{\""),
right_curly("\"}\""),
left_paren("\"(\""),
right_paren("\")\""),
colon(":"),
scolon(";"),
namespace_("(?i:namespace)"),
event("(?i:event)"),
optional("(?i:optional)"),
required("(?i:required)"),
repeated("(?i:repeated)"),
t_int_4("(?i:int4)"),
t_int_8("(?i:int8)"),
t_string("(?i:string)"),
ordinal("\\d+"),
identifier("\\w+")
{
using boost::spirit::lex::_val;
this->self
=
left_curly //[ std::cout << px::val("lpar") << std::endl]
| right_curly //[ std::cout << px::val("rpar") << std::endl]
| left_paren
| right_paren
| colon //[ std::cout << px::val("colon") << std::endl]
| scolon
| namespace_ // [ std::cout << px::val("kw namesapce") << std::endl]
| event // [ std::cout << px::val("kw event") << std::endl]
| optional //[ std::cout << px::val("optional ") << "-->" << _val << "<--" << std::endl]
| required //[ std::cout << px::val("required") << std::endl]
| repeated
| t_int_4
| t_int_8
| t_string
| ordinal //[ std::cout << px::val("val ordinal (") << _val << ")" << std::endl]
| identifier //[std::cout << px::val("val identifier(") << _val << ")" << std::endl]
| lex::token_def<>("[ \\t\\n]+") [lex::_pass = lex::pass_flags::pass_ignore] //CHANGED
;
}
lex::token_def<lex::omit> left_curly, right_curly, left_paren, right_paren, colon, scolon;
lex::token_def<lex::omit> namespace_, event, optional, required, repeated, t_int_4, t_int_8, t_string;
lex::token_def<boost::uint32_t> ordinal;
lex::token_def<> identifier;
};
enum event_entry_qualifier
{
ENTRY_OPTIONAL,
ENTRY_REQUIRED,
ENTRY_REPEATED
};
enum entry_type
{
RBL_INT4,
RBL_INT8,
RBL_STRING,
RBL_EVENT
};
struct oid
{
boost::uint32_t ordinal;
std::string name;
};
BOOST_FUSION_ADAPT_STRUCT
(
oid,
(boost::uint32_t, ordinal)
(std::string, name)
)
std::ostream& operator<<(std::ostream& os, const oid& val) //ADDED
{
return os << val.ordinal << "-" << val.name;
}
struct type_descriptor
{
entry_type type_id;
std::string referenced_event;
};
BOOST_FUSION_ADAPT_STRUCT
(
type_descriptor,
(entry_type, type_id)
(std::string, referenced_event)
)
std::ostream& operator<<(std::ostream& os, const type_descriptor& val) //ADDED
{
return os << val.type_id << "-" << val.referenced_event;
}
struct event_entry
{
event_entry_qualifier qualifier;
oid identifier;
type_descriptor descriptor;
};
BOOST_FUSION_ADAPT_STRUCT
(
event_entry,
(event_entry_qualifier, qualifier)
(oid, identifier)
(type_descriptor, descriptor)
)
std::ostream& operator<<(std::ostream& os, const event_entry& val) //ADDED
{
return os << val.qualifier << "-" << val.identifier << "-" << val.descriptor;
}
struct event_descriptor
{
oid identifier;
std::vector<event_entry> event_entries;
};
BOOST_FUSION_ADAPT_STRUCT
(
event_descriptor,
(oid, identifier)
(std::vector<event_entry>, event_entries)
)
std::ostream& operator<<(std::ostream& os, const event_descriptor& val) //ADDED
{
os << val.identifier << "[";
for(const auto& entry: val.event_entries) //C++11
os << entry;
os << "]";
return os;
}
struct build_string_impl //ADDED
{
template <typename Sig>
struct result;
template <typename This, typename Iter1, typename Iter2>
struct result<This(Iter1,Iter2)>
{
typedef std::string type;
};
template <typename Iter1, typename Iter2>
std::string operator()(Iter1 begin, Iter2 end) const
{
return std::string(begin->begin(),end->begin());
}
};
px::function<build_string_impl> build_string;
template <typename Iterator, typename Lexer>
struct grammar : qi::grammar<Iterator,event_descriptor() >
{
template <typename TokenDef>
grammar(TokenDef const& tok)
: grammar::base_type(event_descriptor_)
{
using qi::_val;
//start = event;
event_descriptor_ = tok.event >> oid_ >> tok.left_curly >> *(event_entry_) >> tok.right_curly;
event_entry_ = event_qualifier >> oid_ >> type_descriptor_ >> tok.scolon;
event_qualifier = tok.optional [ _val = ENTRY_OPTIONAL]
| tok.required [ _val = ENTRY_REQUIRED]
| tok.repeated [ _val = ENTRY_REPEATED];
oid_ = tok.ordinal
>> tok.colon
>> tok.identifier;
type_descriptor_
= (( atomic_type >> qi::attr(""))
| ( event_type >> tok.left_paren >> tok.identifier >> tok.right_paren));
atomic_type = tok.t_int_4 [ _val = RBL_INT4]
| tok.t_int_8 [ _val = RBL_INT8]
| tok.t_string [ _val = RBL_STRING];
event_type = tok.event [_val = RBL_EVENT];
using namespace qi::labels;
qi::on_success(event_entry_,std::cout << _val << " " << build_string(_1,_3) << std::endl); //CHANGED
// BOOST_SPIRIT_DEBUG_NODES( (event_descriptor_)(event_entry_)(event_qualifier)(oid_)(type_descriptor_)(atomic_type)(event_type) );
}
qi::rule<Iterator> start;
qi::rule<Iterator, event_descriptor()> event_descriptor_;
qi::rule<Iterator, event_entry()> event_entry_;
qi::rule<Iterator, event_entry_qualifier()> event_qualifier;
qi::rule<Iterator, entry_type()> atomic_type;
qi::rule<Iterator, entry_type()> event_type;
qi::rule<Iterator, type_descriptor()> type_descriptor_;
qi::rule<Iterator, oid()> oid_;
};
std::string test = " EVENT 1:sihan { OPTIONAL 123:hassan int4; OPTIONAL 321:hassan2 int4; } ";
int main()
{
typedef lex::lexertl::position_token<std::string::iterator, boost::mpl::vector<boost::uint32_t, std::string> > token_type; //CHANGED
typedef lex::lexertl::actor_lexer<token_type> lexer_type;
typedef tokens<lexer_type>::iterator_type iterator_type;
tokens<lexer_type> token_lexer;
grammar<iterator_type,tokens<lexer_type>::lexer_def> grammar(token_lexer);
std::string::iterator it = test.begin();
iterator_type first = token_lexer.begin(it, test.end());
iterator_type last = token_lexer.end();
bool r;
r = qi::parse(first, last, grammar); //CHANGED
if(r)
;
else
{
std::cout << "parsing failed" << std::endl;
}
}