- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有没有一种好方法可以根据某些 boost phoenix 函数的结果来生成解析不同的语法非终结符?
在我的用例中,我有一个语法,其中包括 CPP 样式的#define 指令和#ifdef#else #endif 指令。 (它实际上不是 C 预处理器,尽管它只是其他人的一些粗略模仿。)当我在 qi 中解析它时,我将我的语法(在它的 ctor 中)传递给一个适用于 fusion 的“预处理器数据库”对象的引用结构,我已经修改了允许添加 PP 定义/检查 PP 定义的 phoenix 函数。我这样做是为了让 #define 指令具有注册新定义的语义操作。
当我尝试执行#ifdef#else 指令时,我不确定我应该做什么。我能想到的唯一方法是向我所有语法非终结符的所有属性类型添加一个 bool 标志,标记它是否在废弃的#ifdef 分支中,然后在我的 AST 被解析后爬行再次扔掉标记的家伙。但这很不雅观,必须有更好的方法,对吧?
如果可能的话,我希望能够跟踪原始行号(在解析 ifdef 之前)。
我希望问题很清楚,如果不是,我可以编写一个最小的示例来展示我正在尝试做的事情,但我的实际语法很大。
编辑:好的,我准备了一个 SSCCE:
这是一个解析非常简单的语法对的程序,它有一些最小的预处理器语言,包括 define 和 ifdef。我了解如何使用语义操作以便匹配事物导致 C++ 回调被触发,并且该部分似乎正在工作。但是我不明白的是如何使用回调将信息反馈到语法中,即“如果这个 phoenix 函数返回 false 则以不同的方式解析它”。我想知道怎么说“如果这个 phoenix 函数返回 boolean false 作为这个语义 Action 的一部分,那么任意声明非终结符不匹配和回溯”就足够了。实际上,现在我正在写所有这些,我想我知道“迷你 XML”示例必须以某种方式执行此操作,因为它使用局部变量来强制开始和结束标记必须匹配?所以我想我可以对它的工作原理进行逆向工程。但显然我还没有从阅读文档/研究示例中弄清楚。
请注意,我认为这与您的第一个建议不同,只是跳过语法。问题是我也不知道如何使跳过语法的行为取决于 boost phoenix 函数的输出,这又是同样的问题。我现在唯一知道如何在 qi 中使用 phoenix 的方法是,触发 void 回调,并制作分配给属性值的东西。
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_object.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/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <cassert>
#include <cmath>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef std::string pp_sym;
typedef std::set<pp_sym> pp_data;
void add(pp_data & defines, const pp_sym & s) { defines.insert(s); }
void remove(pp_data & defines, const pp_sym & s) { defines.erase(s); }
bool search(pp_data & defines, const pp_sym & s) { return defines.count(s); }
BOOST_PHOENIX_ADAPT_FUNCTION(void, pp_add_define_, add, 2);
BOOST_PHOENIX_ADAPT_FUNCTION(void, pp_remove_define_, remove, 2);
BOOST_PHOENIX_ADAPT_FUNCTION(bool, pp_search_define_, search, 2);
typedef std::string Str;
typedef std::pair<Str, Str> Pair;
typedef std::vector<Pair> PairVec;
/***
* Grammar definitions
*/
template <typename Iterator>
struct simple_grammar : qi::grammar<Iterator, PairVec()> {
qi::rule<Iterator, PairVec()> main;
qi::rule<Iterator, Pair()> pair;
qi::rule<Iterator, Str()> first;
qi::rule<Iterator, Str()> second;
qi::rule<Iterator, pp_sym()> pp_symbol;
qi::rule<Iterator> pp_directive;
qi::rule<Iterator, pp_sym()> define_directive;
qi::rule<Iterator, pp_sym()> undef_directive;
qi::rule<Iterator, pp_sym()> if_directive;
qi::rule<Iterator> else_directive;
qi::rule<Iterator> endif_directive;
qi::rule<Iterator> ws;
simple_grammar(pp_data & preprocessor_data)
: simple_grammar::base_type(main)
{
using qi::lit;
using qi::char_;
using namespace qi::labels;
ws = char_(" \t\r\n");
first = !lit('#') >> *(char_ - '=') >> lit('=');
second = *(char_ - '\n') >> lit('\n');
pair = first >> second;
pp_symbol = +char_("A-Za-z_");
pp_directive = &lit('#')
>> ((define_directive [ pp_add_define_(ref(preprocessor_data), _1) ] )
| (undef_directive [ pp_remove_define_(ref(preprocessor_data), _1) ] )
| if_directive // [ ??? ]
| else_directive
| endif_directive)
>> *(char_ - '\n') >> lit('\n');
main = (pp_directive >> -main) | (pair >> -main);
define_directive = lit("#define ") >> pp_symbol >> &ws;
undef_directive = lit("#undef ") >> pp_symbol >> &ws;
if_directive = lit("#ifdef ") >> pp_symbol >> &ws;
else_directive = lit("#else");
endif_directive = lit("#endif");
}
};
const char * example_1 = ""
"#define FOO\n"
"led_zeppelin=9\n"
"the_shins=9\n"
"dead_mau5=6\n"
"portishead=10\n"
"#ifdef FOO\n"
"foo_fighters=7\n"
"#else\n"
"the_who=6\n"
"#endif\n"
"kanye_west=4\n"
"#undef FOO\n"
"#define BAR\n";
int main() {
std::string temp{example_1};
typedef std::string::const_iterator str_it;
typedef simple_grammar<str_it> my_grammar;
pp_data defines;
my_grammar gram(defines); // Our grammar
PairVec ast; // Our tree
str_it it = temp.begin();
str_it end = temp.end();
bool b = qi::parse(it, end, gram, ast);
assert(b);
assert(defines.count("FOO") == 0);
assert(defines.count("BAR") == 1);
std::cout << "Parsed a list:\n\n";
for( const auto & p : ast) {
std::cout << p.first << "\n\t\t\t=\t" << p.second << std::endl;
}
return 0;
}
对我来说,上面的输出是(如预期的那样):
$ ./main
Parsed a list:
led_zeppelin
= 9
the_shins
= 9
dead_mau5
= 6
portishead
= 10
foo_fighters
= 7
the_who
= 6
kanye_west
= 4
但是我想做的是让 ifdef 部分执行您自然期望的操作,并允许嵌套的 ifdef 子句。
最佳答案
针对添加到问题中的“SSCCE”代码:
正确处理嵌套定义的唯一方法(包括条件 block 包含 #define
/#undef
指令的情况!)是使用表示树的 AST block 的数量¹:
namespace Common {
typedef std::string pp_sym;
}
namespace Ast {
using Common::pp_sym;
typedef std::string Str;
typedef std::pair<Str, Str> Pair;
typedef std::vector<Pair> Pairs;
struct ConditionalBlock;
namespace tag {
struct define;
struct undefine;
}
template <typename Tag> struct Directive {
pp_sym name;
};
typedef Directive<tag::define> Define;
typedef Directive<tag::undefine> Undef;
typedef boost::make_recursive_variant<
Pairs,
boost::recursive_wrapper<ConditionalBlock>,
Define,
Undef
>::type Block;
typedef std::vector<Block> Blocks;
struct ConditionalBlock {
pp_sym required;
Blocks if_, else_;
};
}
为了在不使用语义操作的情况下 boost 解析这些:
BOOST_FUSION_ADAPT_TPL_STRUCT((Tag), (Ast::Directive)(Tag), name)
BOOST_FUSION_ADAPT_STRUCT(Ast::ConditionalBlock, required, if_, else_)
完成。
由于上述工作,我们现在可以完全按照我们的意愿定义解析器!
注意事项:
seek[eol]
忽略直到一行结束distinct
解析标识符(参见 boost::spirit::qi keywords and identifiers )#else
的外观可选(参见 -else
)启用调试信息,无需任何更多工作
start = skip(blank) [ blocks ];
blocks = *block;
block = define | undef | conditional_block | +pair;
pair = !char_("#") >> +~char_("=\r\n") >> '=' >> *(char_ - eol) >> *eol;
pp_symbol = qr::distinct(char_("A-Za-z_")) [ +char_("A-Za-z_") ];
define = '#' >> distinct(alnum | '_') [ "define" ] >> pp_symbol >> seek[*eol];
undef = '#' >> distinct(alnum | '_') [ "undef" ] >> pp_symbol >> seek[*eol];
else_ = '#' >> distinct(alnum | '_') [ "else" ] >> seek[*eol];
endif = '#' >> distinct(alnum | '_') [ "endif" ] >> seek[*eol];
conditional_block =
('#' >> distinct(alnum | '_') [ "ifdef" ] >> pp_symbol >> seek[*eol])
>> *(!(else_|endif) >> block)
>> -else_
>> *(!endif >> block)
>> endif
;
BOOST_SPIRIT_DEBUG_NODES((start)(blocks)(block)(pair)(pp_symbol)(define)(undef)(else_)(endif)(conditional_block))
我会说这非常清晰,它会导致 ast 包含您以后可能想要使用的所有信息
现在我们已经将处理与解析分开,处理是树的单次访问。我们使用一个函数对象 Logic::Preprocessor
兼作变体访问者:
Logic::Preprocess pp({{"EXTERNAL"}} , " ");
pp(ast);
在此示例中,我们从定义的预处理器符号 EXTERNAL
开始(就好像它是在“外部”定义的,就像在命令行上一样)。
访问者的实现非常简单,但让我展示一下操作位,即采用条件和忽略分支的位置。为了让事情变得非常完整,我什至遍历了不满足的分支,只是为了表明完整的 AST 在那里,但是函数对象的 en isolated
实例所以有没有效果:
void operator()(Ast::ConditionalBlock const& cb) const {
bool const satisfied = ctx.defined.count(cb.required);
auto old_indent = indent;
indent += "\t";
std::cout << old_indent << "#ifdef " << cb.required << " // " << std::boolalpha << satisfied << "\n";
Preprocess isolated{ctx, indent+"// "}; // prevent changes to ctx to affect us for the non-matching branch
(satisfied? *this : isolated)(cb.if_);
std::cout << old_indent << "#else " << " // ifdef " << cb.required << "\n";
(satisfied? isolated : *this)(cb.else_);
std::cout << old_indent << "#endif " << " // ifdef " << cb.required << "\n";
indent.resize(indent.size()-1);
}
void operator()(Ast::Define const& directive) const {
ctx.defined.insert(directive.name);
std::cout << indent << "#define\t" << directive.name;
report();
}
void operator()(Ast::Undef const& directive) const {
ctx.defined.erase(directive.name);
std::cout << indent << "#undef\t" << directive.name;
report();
}
观察这个文档是如何被正确解释的,它甚至嵌套了条件 block 并定义了条件分支中的符号(因此,有条件地):
#define FOO
led_zeppelin=9
the_shins=9
dead_mau5=6
portishead=10
#ifdef FOO
foo_fighters=7
#define ZOO
#else
the_who=6
#define QUX
#endif
#ifdef EXTERNAL
#ifdef ZOO
zoowasdefined=yes
#else
zoowasdefined=no
#endif
#ifdef QUX
quxwasdefined=yes
#else
quxwasdefined=no
#endif
#endif
kanye_west=4
#undef FOO
#define BAR
我们的演示程序打印: Live On Coliru
Preprocess results:
#define FOO // effective: EXTERNAL FOO
led_zeppelin=9
the_shins=9
dead_mau5=6
portishead=10
#ifdef FOO // true
foo_fighters=7
#define ZOO // effective: EXTERNAL FOO ZOO
#else // ifdef FOO
// the_who=6
// #define QUX // effective: EXTERNAL FOO QUX
#endif // ifdef FOO
#ifdef EXTERNAL // true
#ifdef ZOO // true
zoowasdefined=yes
#else // ifdef ZOO
// zoowasdefined=no
#endif // ifdef ZOO
#ifdef QUX // false
// quxwasdefined=yes
#else // ifdef QUX
quxwasdefined=no
#endif // ifdef QUX
#else // ifdef EXTERNAL
#endif // ifdef EXTERNAL
kanye_west=4
#undef FOO // effective: EXTERNAL ZOO
#define BAR // effective: BAR EXTERNAL ZOO
Defines still in effect: BAR EXTERNAL ZOO
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
#include <boost/spirit/repository/include/qi_seek.hpp>
#include <boost/variant.hpp>
#include <cassert>
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace qr = boost::spirit::repository::qi;
namespace Common {
typedef std::string pp_sym;
}
namespace Ast {
using Common::pp_sym;
typedef std::string Str;
typedef std::pair<Str, Str> Pair;
typedef std::vector<Pair> Pairs;
struct ConditionalBlock;
namespace tag {
struct define;
struct undefine;
}
template <typename Tag> struct Directive {
pp_sym name;
};
typedef Directive<tag::define> Define;
typedef Directive<tag::undefine> Undef;
typedef boost::make_recursive_variant<
Pairs,
boost::recursive_wrapper<ConditionalBlock>,
Define,
Undef
>::type Block;
typedef std::vector<Block> Blocks;
struct ConditionalBlock {
pp_sym required;
Blocks if_, else_;
};
}
BOOST_FUSION_ADAPT_TPL_STRUCT((Tag), (Ast::Directive)(Tag), name)
BOOST_FUSION_ADAPT_STRUCT(Ast::ConditionalBlock, required, if_, else_)
/***
* Grammar definitions
*/
template <typename Iterator>
struct simple_grammar : qi::grammar<Iterator, Ast::Blocks()> {
simple_grammar() : simple_grammar::base_type(start)
{
using namespace qi;
using qr::distinct;
using qr::seek;
start = skip(blank) [ blocks ];
blocks = *block;
block = define | undef | conditional_block | +pair;
pair = +~char_("=\r\n") >> '=' >> *(char_ - eol) >> *eol;
pp_symbol = qr::distinct(char_("A-Za-z_")) [ +char_("A-Za-z_") ];
define = '#' >> distinct(alnum | '_') [ "define" ] >> pp_symbol >> seek[*eol];
undef = '#' >> distinct(alnum | '_') [ "undef" ] >> pp_symbol >> seek[*eol];
else_ = '#' >> distinct(alnum | '_') [ "else" ] >> seek[*eol];
endif = '#' >> distinct(alnum | '_') [ "endif" ] >> seek[*eol];
conditional_block =
('#' >> distinct(alnum | '_') [ "ifdef" ] >> pp_symbol >> seek[*eol])
>> *(!(else_|endif) >> block)
>> -else_
>> *(!endif >> block)
>> endif
;
BOOST_SPIRIT_DEBUG_NODES((start)(blocks)(block)(pair)(pp_symbol)(define)(undef)(else_)(endif)(conditional_block))
}
private:
using Skipper = qi::blank_type;
qi::rule<Iterator, Ast::Blocks()> start;
qi::rule<Iterator, Ast::Blocks(), Skipper> blocks;
qi::rule<Iterator, Ast::Block(), Skipper> block;
// directive
qi::rule<Iterator, Ast::ConditionalBlock(), Skipper> conditional_block;
qi::rule<Iterator, Ast::Define(), Skipper> define;
qi::rule<Iterator, Ast::Undef(), Skipper> undef;
// empty directives
qi::rule<Iterator, Skipper> else_, endif;
// lexeme
qi::rule<Iterator, Ast::Pair()> pair;
qi::rule<Iterator, Ast::pp_sym()> pp_symbol;
};
namespace Logic {
using Common::pp_sym;
typedef std::set<pp_sym> pp_syms;
struct context {
pp_syms defined;
};
struct Preprocess : boost::static_visitor<void> {
context ctx;
std::string indent;
Preprocess(context ctx = {}, std::string indent = "")
: ctx(std::move(ctx)), indent(std::move(indent))
{ }
void operator()(Ast::Blocks const& blocks) {
for (auto& b : blocks)
boost::apply_visitor(*this, b);
}
void operator()(Ast::Block const& block) {
boost::apply_visitor(*this, block);
}
void operator()(Ast::Pairs const& pairs) {
for (auto& p : pairs)
std::cout << indent << p.first << "=" << p.second << "\n";
}
void operator()(Ast::ConditionalBlock const& cb) {
bool const satisfied = ctx.defined.count(cb.required);
auto old_indent = indent;
indent += "\t";
std::cout << old_indent << "#ifdef " << cb.required << " // " << std::boolalpha << satisfied << "\n";
Preprocess isolated{ctx, indent+"// "}; // prevent changes to ctx to affect us for the non-matching branch
(satisfied? *this : isolated)(cb.if_);
std::cout << old_indent << "#else " << " // ifdef " << cb.required << "\n";
(satisfied? isolated : *this)(cb.else_);
std::cout << old_indent << "#endif " << " // ifdef " << cb.required << "\n";
indent.resize(indent.size()-1);
}
void operator()(Ast::Define const& directive) {
ctx.defined.insert(directive.name);
std::cout << indent << "#define\t" << directive.name;
report();
}
void operator()(Ast::Undef const& directive) {
ctx.defined.erase(directive.name);
std::cout << indent << "#undef\t" << directive.name;
report();
}
private:
void report() const {
std::cout << "\t// effective: ";
for (auto& sym : ctx.defined) std::cout << sym << " ";
std::cout << "\n";
}
};
}
int main() {
typedef boost::spirit::istream_iterator It;
typedef simple_grammar<It> my_grammar;
my_grammar gram; // Our grammar
Ast::Blocks ast; // Our tree
It it(std::cin >> std::noskipws), end;
bool b = qi::parse(it, end, gram, ast);
if (it != end)
std::cout << "Remaining input: '" << std::string(it, end) << "'\n";
assert(b);
std::cout << "Preprocess results:\n\n";
Logic::Preprocess pp({{"EXTERNAL"}} , " ");
pp(ast);
std::cout << "\n\nDefines still in effect: ";
for (auto& sym : pp.ctx.defined) std::cout << sym << " ";
}
除了上述输出之外,启用调试信息还会产生以下详细的跟踪信息:
<start>
<try>#define FOO\nled_zepp</try>
<blocks>
<try>#define FOO\nled_zepp</try>
<block>
<try>#define FOO\nled_zepp</try>
<define>
<try>#define FOO\nled_zepp</try>
<pp_symbol>
<try>FOO\nled_zeppelin=9\nt</try>
<success>\nled_zeppelin=9\nthe_</success>
<attributes>[[F, O, O]]</attributes>
</pp_symbol>
<success>led_zeppelin=9\nthe_s</success>
<attributes>[[[F, O, O]]]</attributes>
</define>
<success>led_zeppelin=9\nthe_s</success>
<attributes>[[[F, O, O]]]</attributes>
</block>
<block>
<try>led_zeppelin=9\nthe_s</try>
<define>
<try>led_zeppelin=9\nthe_s</try>
<fail/>
</define>
<undef>
<try>led_zeppelin=9\nthe_s</try>
<fail/>
</undef>
<conditional_block>
<try>led_zeppelin=9\nthe_s</try>
<fail/>
</conditional_block>
<pair>
<try>led_zeppelin=9\nthe_s</try>
<success>the_shins=9\ndead_mau</success>
<attributes>[[[l, e, d, _, z, e, p, p, e, l, i, n], [9]]]</attributes>
</pair>
<pair>
<try>the_shins=9\ndead_mau</try>
<success>dead_mau5=6\nportishe</success>
<attributes>[[[t, h, e, _, s, h, i, n, s], [9]]]</attributes>
</pair>
<pair>
<try>dead_mau5=6\nportishe</try>
<success>portishead=10\n#ifdef</success>
<attributes>[[[d, e, a, d, _, m, a, u, 5], [6]]]</attributes>
</pair>
<pair>
<try>portishead=10\n#ifdef</try>
<success>#ifdef FOO\nfoo_fight</success>
<attributes>[[[p, o, r, t, i, s, h, e, a, d], [1, 0]]]</attributes>
</pair>
<pair>
<try>#ifdef FOO\nfoo_fight</try>
<fail/>
</pair>
<success>#ifdef FOO\nfoo_fight</success>
<attributes>[[[[l, e, d, _, z, e, p, p, e, l, i, n], [9]], [[t, h, e, _, s, h, i, n, s], [9]], [[d, e, a, d, _, m, a, u, 5], [6]], [[p, o, r, t, i, s, h, e, a, d], [1, 0]]]]</attributes>
</block>
<block>
<try>#ifdef FOO\nfoo_fight</try>
<define>
<try>#ifdef FOO\nfoo_fight</try>
<fail/>
</define>
<undef>
<try>#ifdef FOO\nfoo_fight</try>
<fail/>
</undef>
<conditional_block>
<try>#ifdef FOO\nfoo_fight</try>
<pp_symbol>
<try>FOO\nfoo_fighters=7\n#</try>
<success>\nfoo_fighters=7\n#def</success>
<attributes>[[F, O, O]]</attributes>
</pp_symbol>
<else_>
<try>foo_fighters=7\n#defi</try>
<fail/>
</else_>
<endif>
<try>foo_fighters=7\n#defi</try>
<fail/>
</endif>
<block>
<try>foo_fighters=7\n#defi</try>
<define>
<try>foo_fighters=7\n#defi</try>
<fail/>
</define>
<undef>
<try>foo_fighters=7\n#defi</try>
<fail/>
</undef>
<conditional_block>
<try>foo_fighters=7\n#defi</try>
<fail/>
</conditional_block>
<pair>
<try>foo_fighters=7\n#defi</try>
<success>#define ZOO\n#else\nth</success>
<attributes>[[[f, o, o, _, f, i, g, h, t, e, r, s], [7]]]</attributes>
</pair>
<pair>
<try>#define ZOO\n#else\nth</try>
<fail/>
</pair>
<success>#define ZOO\n#else\nth</success>
<attributes>[[[[f, o, o, _, f, i, g, h, t, e, r, s], [7]]]]</attributes>
</block>
<else_>
<try>#define ZOO\n#else\nth</try>
<fail/>
</else_>
<endif>
<try>#define ZOO\n#else\nth</try>
<fail/>
</endif>
<block>
<try>#define ZOO\n#else\nth</try>
<define>
<try>#define ZOO\n#else\nth</try>
<pp_symbol>
<try>ZOO\n#else\nthe_who=6\n</try>
<success>\n#else\nthe_who=6\n#de</success>
<attributes>[[Z, O, O]]</attributes>
</pp_symbol>
<success>#else\nthe_who=6\n#def</success>
<attributes>[[[Z, O, O]]]</attributes>
</define>
<success>#else\nthe_who=6\n#def</success>
<attributes>[[[Z, O, O]]]</attributes>
</block>
<else_>
<try>#else\nthe_who=6\n#def</try>
<success>the_who=6\n#define QU</success>
<attributes>[]</attributes>
</else_>
<else_>
<try>#else\nthe_who=6\n#def</try>
<success>the_who=6\n#define QU</success>
<attributes>[]</attributes>
</else_>
<endif>
<try>the_who=6\n#define QU</try>
<fail/>
</endif>
<block>
<try>the_who=6\n#define QU</try>
<define>
<try>the_who=6\n#define QU</try>
<fail/>
</define>
<undef>
<try>the_who=6\n#define QU</try>
<fail/>
</undef>
<conditional_block>
<try>the_who=6\n#define QU</try>
<fail/>
</conditional_block>
<pair>
<try>the_who=6\n#define QU</try>
<success>#define QUX\n#endif\n\n</success>
<attributes>[[[t, h, e, _, w, h, o], [6]]]</attributes>
</pair>
<pair>
<try>#define QUX\n#endif\n\n</try>
<fail/>
</pair>
<success>#define QUX\n#endif\n\n</success>
<attributes>[[[[t, h, e, _, w, h, o], [6]]]]</attributes>
</block>
<endif>
<try>#define QUX\n#endif\n\n</try>
<fail/>
</endif>
<block>
<try>#define QUX\n#endif\n\n</try>
<define>
<try>#define QUX\n#endif\n\n</try>
<pp_symbol>
<try>QUX\n#endif\n\n#ifdef E</try>
<success>\n#endif\n\n#ifdef EXTE</success>
<attributes>[[Q, U, X]]</attributes>
</pp_symbol>
<success>#endif\n\n#ifdef EXTER</success>
<attributes>[[[Q, U, X]]]</attributes>
</define>
<success>#endif\n\n#ifdef EXTER</success>
<attributes>[[[Q, U, X]]]</attributes>
</block>
<endif>
<try>#endif\n\n#ifdef EXTER</try>
<success>#ifdef EXTERNAL\n\n#if</success>
<attributes>[]</attributes>
</endif>
<endif>
<try>#endif\n\n#ifdef EXTER</try>
<success>#ifdef EXTERNAL\n\n#if</success>
<attributes>[]</attributes>
</endif>
<success>#ifdef EXTERNAL\n\n#if</success>
<attributes>[[[F, O, O], [[[[f, o, o, _, f, i, g, h, t, e, r, s], [7]]], [[Z, O, O]]], [[[[t, h, e, _, w, h, o], [6]]], [[Q, U, X]]]]]</attributes>
</conditional_block>
<success>#ifdef EXTERNAL\n\n#if</success>
<attributes>[[[F, O, O], [[[[f, o, o, _, f, i, g, h, t, e, r, s], [7]]], [[Z, O, O]]], [[[[t, h, e, _, w, h, o], [6]]], [[Q, U, X]]]]]</attributes>
</block>
<block>
<try>#ifdef EXTERNAL\n\n#if</try>
<define>
<try>#ifdef EXTERNAL\n\n#if</try>
<fail/>
</define>
<undef>
<try>#ifdef EXTERNAL\n\n#if</try>
<fail/>
</undef>
<conditional_block>
<try>#ifdef EXTERNAL\n\n#if</try>
<pp_symbol>
<try>EXTERNAL\n\n#ifdef ZOO</try>
<success>\n\n#ifdef ZOO\nzoowasd</success>
<attributes>[[E, X, T, E, R, N, A, L]]</attributes>
</pp_symbol>
<else_>
<try>#ifdef ZOO\nzoowasdef</try>
<fail/>
</else_>
<endif>
<try>#ifdef ZOO\nzoowasdef</try>
<fail/>
</endif>
<block>
<try>#ifdef ZOO\nzoowasdef</try>
<define>
<try>#ifdef ZOO\nzoowasdef</try>
<fail/>
</define>
<undef>
<try>#ifdef ZOO\nzoowasdef</try>
<fail/>
</undef>
<conditional_block>
<try>#ifdef ZOO\nzoowasdef</try>
<pp_symbol>
<try>ZOO\nzoowasdefined=ye</try>
<success>\nzoowasdefined=yes\n#</success>
<attributes>[[Z, O, O]]</attributes>
</pp_symbol>
<else_>
<try>zoowasdefined=yes\n#e</try>
<fail/>
</else_>
<endif>
<try>zoowasdefined=yes\n#e</try>
<fail/>
</endif>
<block>
<try>zoowasdefined=yes\n#e</try>
<define>
<try>zoowasdefined=yes\n#e</try>
<fail/>
</define>
<undef>
<try>zoowasdefined=yes\n#e</try>
<fail/>
</undef>
<conditional_block>
<try>zoowasdefined=yes\n#e</try>
<fail/>
</conditional_block>
<pair>
<try>zoowasdefined=yes\n#e</try>
<success>#else\nzoowasdefined=</success>
<attributes>[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [y, e, s]]]</attributes>
</pair>
<pair>
<try>#else\nzoowasdefined=</try>
<fail/>
</pair>
<success>#else\nzoowasdefined=</success>
<attributes>[[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [y, e, s]]]]</attributes>
</block>
<else_>
<try>#else\nzoowasdefined=</try>
<success>zoowasdefined=no\n#en</success>
<attributes>[]</attributes>
</else_>
<else_>
<try>#else\nzoowasdefined=</try>
<success>zoowasdefined=no\n#en</success>
<attributes>[]</attributes>
</else_>
<endif>
<try>zoowasdefined=no\n#en</try>
<fail/>
</endif>
<block>
<try>zoowasdefined=no\n#en</try>
<define>
<try>zoowasdefined=no\n#en</try>
<fail/>
</define>
<undef>
<try>zoowasdefined=no\n#en</try>
<fail/>
</undef>
<conditional_block>
<try>zoowasdefined=no\n#en</try>
<fail/>
</conditional_block>
<pair>
<try>zoowasdefined=no\n#en</try>
<success>#endif\n\n#ifdef QUX\nq</success>
<attributes>[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [n, o]]]</attributes>
</pair>
<pair>
<try>#endif\n\n#ifdef QUX\nq</try>
<fail/>
</pair>
<success>#endif\n\n#ifdef QUX\nq</success>
<attributes>[[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [n, o]]]]</attributes>
</block>
<endif>
<try>#endif\n\n#ifdef QUX\nq</try>
<success>#ifdef QUX\nquxwasdef</success>
<attributes>[]</attributes>
</endif>
<endif>
<try>#endif\n\n#ifdef QUX\nq</try>
<success>#ifdef QUX\nquxwasdef</success>
<attributes>[]</attributes>
</endif>
<success>#ifdef QUX\nquxwasdef</success>
<attributes>[[[Z, O, O], [[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [y, e, s]]]], [[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [n, o]]]]]]</attributes>
</conditional_block>
<success>#ifdef QUX\nquxwasdef</success>
<attributes>[[[Z, O, O], [[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [y, e, s]]]], [[[[z, o, o, w, a, s, d, e, f, i, n, e, d], [n, o]]]]]]</attributes>
</block>
....
</start>
¹ 或者你应该有一个相当复杂的树来在解析时匹配。每当有疑问时,将解析与处理分开。这与 Boost Spirit: "Semantic actions are evil"? 密切相关
关于c++ - 如何在 boost::spirit::qi 语法中实现#ifdef?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32145352/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!