Spirit 2.X 부스트 : 키워드 및 식별자를 처리하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1630709

  •  06-07-2019
  •  | 
  •  

문제

좋은 하루에요.

나는 과거에 Boost Spirit Classic을 사용해 왔으며 지금은 새로운 것, Boost Spirit 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_;

ID 규칙은 다음과 같이 선언했습니다.

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"등이 키워드라고 말하면서 올바르게 작성하는 방법은 무엇입니까? 미리 감사드립니다.

도움이 되었습니까?

해결책

흠 단지 규칙을 다음과 같이 선언합니다.

//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에서 사용 된 버전을 사용했으며 연산자 %=를 사용할 때 버그가있는 것 같습니다. 전:

ident_decl %= ident;

대신 이것을하십시오

ident_decl %= ident > eps;

동등해야합니다.

이것이 도움이 되었기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top