美好的一天。
我过去一直在使用提升精神经典,现在我正在努力坚持更新的一个,提升精神2.x.有人可以如此友善地指出我如何处理关键字?比如,我想区分“foo”和“int”,其中“foo”是标识符,“int”只是一个关键字。我想保护我的语法不被错误的解析,比如“intfoo”。
好的,我有
struct my_keywords : boost::spirit::qi::symbols<char, std::string> {
my_keywords() {
add
("void")
("string")
("float")
("int")
("bool")
//TODO: add others
;
}
} keywords_table_;
并将ident规则声明为:
boost::spirit::qi::rule<Iterator, std::string(), ascii::space_type> ident;
ident = raw[lexeme[((alpha | char_('_')) >> *(alnum | char_('_'))) - keywords_table_]];
,比方说,有些规则:
boost::spirit::qi::rule<Iterator, ident_decl_node(), ascii::space_type> ident_decl;
ident_decl = ("void" | "float" | "string" | "bool") >> ident;
如何正确编写,说“void”,“float”等是关键字? 提前谢谢。
答案 0 :(得分:6)
嗯,只是声明你的规则是:
//the > operator say that your keyword MUST be followed by an ident
//instead of just may (if I understood spirit right the >> operator will
//make the parser consider other rules if it fail which might or not be
//what you want.
ident_decl = keyword_table_ > ident;
根据你的例子,你应该在最后得到这样的东西:
struct my_keywords : boost::spirit::qi::symbols<char, int> {
my_keywords() {
add
("void", TYPE_VOID)
("string", TYPE_STRING)
("float", TYPE_FLOAT)
("int", TYPE_INT)
("bool", TYPE_BOOL)
//TODO: add others
;
}
} keywords_table_;
// ...
class ident_decl_node
{
//this will enable fusion_adapt_struct to access your private members
template < typename, int>
friend struct boost::fusion::extension::struct_member;
//new version of spirit use:
//friend struct boost::fusion::extension::access::struct_member;
int type;
std::string ident;
};
BOOST_FUSION_ADAPT_STRUCT(
ident_decl_node,
(int, type)
(std::string, ident)
)
// ...
struct MyErrorHandler
{
template <typename, typename, typename, typename>
struct result { typedef void type; };
template <typename Iterator>
void operator()(Iterator first, Iterator last, Iterator error_pos, std::string const& what) const
{
using boost::phoenix::construct;
std::string error_msg = "Error! Expecting ";
error_msg += what; // what failed?
error_msg += " here: \"";
error_msg += std::string(error_pos, last); // iterators to error-pos, end
error_msg += "\"";
//put a breakpoint here if you don't have std::cout for the console or change
//this line for something else.
std::cout << error_msg;
}
};
// ...
using boost::spirit::qi::grammar;
using boost::spirit::ascii::space_type;
typedef std::vector<boost::variant<ident_decl_node, some_other_node> ScriptNodes;
template <typename Iterator>
struct NodeGrammar: public grammar<Iterator, ScriptNodes(), space_type>
{
using boost::spirit::arg_names; //edit1
NodeGrammar: NodeGrammar::base_type(start)
{
//I had problem if I didn't add the eps rule (which do nothing) so you might
//want to leave it
start %= ident_decl | some_other_node_decl >> eps;
ident_decl %= keyword_table > ident;
//I'm not sure if the %= operator will work correctly on this, you might have to do
//the push_back manually but I think it should work
ident %= raw[lexeme[((alpha | char_('_')) >> *(alnum | char_('_'))) - keywords_table_]];
on_error<fail>(start, error_handler(_1, _2, _3, _4)); //edit1
}
my_keywords keyword_table_;
boost::spirit::qi::rule<Iterator, ScriptNodes(), ascii::space_type> start;
boost::spirit::qi::rule<Iterator, ident_decl_node(), ascii::space_type> ident_decl;
boost::spirit::qi::rule<Iterator, some_other_node(), ascii::space_type> ident_decl;
boost::spirit::qi::rule<Iterator, std::string(), ascii::space_type> ident;
boost::phoenix::function<MyErrorHandler> error_handler; //edit1
};
另外我不知道你使用的是哪个版本,但是我使用了boost 1.40中的那个版本,似乎有一个bug 当使用运算符%=后跟只有一个参数时(解析器不会正确解析此规则)。例如:
ident_decl %= ident;
改为执行此操作
ident_decl %= ident > eps;
应该是等价的。
希望这会有所帮助。