如何在带有Boost Spirit的AST中使用仅具有一个属性的类? [英] How do I use a class with only one attribute in a AST with Boost Spirit?
问题描述
我想使用Boost Spirit将文件解析为AST.
I want to parse a file into an AST using Boost Spirit.
我的AST的根是只有一个属性的类:
The root of my AST is a class with only one attribute :
typedef boost::variant<FunctionDeclaration, GlobalVariableDeclaration> FirstLevelBlock;
struct Program {
std::vector<FirstLevelBlock> blocks;
};
BOOST_FUSION_ADAPT_STRUCT(
::Program,
(std::vector<eddic::FirstLevelBlock>, blocks)
)
如果我使用单个规则进行解析:
If I parse using a single rule :
program %= *(function | globalDeclaration);
它不会编译,但是如果我在Program中添加一个字符串名,它会很好地工作.我可以将向量用作根,但是我想使用该类,因为我想向Program类添加一些方法.
it doesn't compiles, but if I add a single string name to Program, it works well. I could use the vector as the root, but I want to use the class, because I want to add some methods to the Program class.
如果我用括号括住程序,它会很好地工作:
If I surround my program with braces, it works well :
program %= lexer.left_brace >> *(function | globalDeclaration) >> lexer.right_brace;
可以编译并正常工作,但是:
compiles and works fine, but :
program %= *(function | globalDeclaration);
无法编译...
Boost Spirit中是否有某些东西阻止使用如此简单的规则?
Is there something in Boost Spirit that prevent using such simple rules ?
推荐答案
已编辑的问题版本2
如果我用括号括住程序,它可以很好地工作,但是
program %= *(function | globalDeclaration);
无法编译...
If I surround my program with braces, it works well [...], but
program %= *(function | globalDeclaration);
does not compile...
Boost Spirit中是否有某些东西阻止使用如此简单的规则?
首先,如果没有对function
和globalDeclaration
的定义,我们就无法真正知道.
Firstly, we can't really tell without the defintion for function
and globalDeclaration
.
第二次,我尝试将PoC行更改为
Secondly I tried, changing my PoC lines to
static const qi::rule<It, Program(), space_type> program = *(function | global);
Program d = test("void test(); int abc; int xyz; void last();" , program);
瞧瞧,我得到了您的编译器错误!现在,我当然同意这看起来非常像属性转换错误.另外,这是一个初步的解决方法:
Lo and behold, I get your compiler error! Now I would certainly agree that this looks very much like an attribute conversion bug. Also, Here is a preliminary workaround:
program %= eps >> *(function | global);
如您所见,qi::eps
进行救援
As you can see, qi::eps
to the rescue
嗯.我认为您需要发布最少的工作示例.这是从您的问题开始的概念证明,并且一切都很好.
Mmm. I think you need to post a minimal working sample. Here is a proof of concept starting from your question, and it all works rather nicely.
请注意,为了获得test
函数的默认Attr
参数参数,我使用g++ -std=c++0x
进行了编译.
Note that I compiled with g++ -std=c++0x
in order to get the default Attr
parameter argument on the test
function.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/strong_typedef.hpp>
// added missing bits
namespace eddic
{
typedef std::string FunctionDeclaration;
typedef std::string GlobalVariableDeclaration;
typedef boost::variant<FunctionDeclaration, GlobalVariableDeclaration> FirstLevelBlock;
}
using namespace eddic;
// end missing bits
struct Program {
std::vector<FirstLevelBlock> blocks;
};
BOOST_FUSION_ADAPT_STRUCT(
::Program,
(std::vector<eddic::FirstLevelBlock>, blocks)
)
namespace /*anon*/
{
using namespace boost::spirit::karma;
struct dumpvariant : boost::static_visitor<std::ostream&>
{
dumpvariant(std::ostream& os) : _os(os) {}
template <typename T> std::ostream& operator ()(const T& t) const
{ return _os << format(stream, t); }
private: std::ostream& _os;
};
std::ostream& operator<<(std::ostream& os, const FirstLevelBlock& block)
{
os << "variant[" << block.which() << ", ";
boost::apply_visitor(dumpvariant(os), block);
return os << "]";
}
std::ostream& operator<<(std::ostream& os, const std::vector<FirstLevelBlock>& blocks)
{ return os << format(-(stream % eol), blocks); }
std::ostream& operator<<(std::ostream& os, const Program& program)
{ return os << "BEGIN\n" << program.blocks << "\nEND"; }
}
namespace qi = boost::spirit::qi;
template <typename Rule, typename Attr = typename Rule::attr_type>
Attr test(const std::string& input, const Rule& rule)
{
typedef std::string::const_iterator It;
It f(input.begin()), l(input.end());
Attr result;
try
{
bool ok = qi::phrase_parse(f, l, rule, qi::space, result);
if (!ok)
std::cerr << " -- ERR: parse failed" << std::endl;
} catch(qi::expectation_failure<It>& e)
{
std::cerr << " -- ERR: expectation failure at '" << std::string(e.first, e.last) << "'" << std::endl;
}
if (f!=l)
std::cerr << " -- WARN: remaing input '" << std::string(f,l) << "'" << std::endl;
return result;
}
int main()
{
typedef std::string::const_iterator It;
static const qi::rule<It, FunctionDeclaration(), space_type> function = "void " > +~qi::char_("()") > "();";
static const qi::rule<It, GlobalVariableDeclaration(), space_type> global = "int " > +~qi::char_(";") > ";";
static const qi::rule<It, FirstLevelBlock(), space_type> block = function | global;
static const qi::rule<It, Program(), space_type> program = '{' >> *(function | global) >> '}';
FunctionDeclaration a = test("void test();", function);
std::cout << "FunctionDeclaration a : " << a << std::endl;
GlobalVariableDeclaration b = test("int abc;", global);
std::cout << "GlobalVariableDeclaration b : " << b << std::endl;
FirstLevelBlock c = test("void more();", block);
std::cout << "FirstLevelBlock c : " << c << std::endl;
/*FirstLevelBlock*/ c = test("int bcd;", block);
std::cout << "FirstLevelBlock c : " << c << std::endl;
Program d = test("{"
"void test();"
"int abc"
";"
"int xyz; void last();"
"}", program);
std::cout << "Program d : " << d << std::endl;
}
输出:
FunctionDeclaration a : test
GlobalVariableDeclaration b : abc
FirstLevelBlock c : variant[1, more]
FirstLevelBlock c : variant[1, bcd]
Program d : BEGIN
test
abc
xyz
last
END
这篇关于如何在带有Boost Spirit的AST中使用仅具有一个属性的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!