your programing

더 많은 정신 광기-파서 유형 (규칙 대 int_parser <>) 및 메타 프로그래밍 기술

lovepro 2020. 10. 8. 08:24
반응형

더 많은 정신 광기-파서 유형 (규칙 대 int_parser <>) 및 메타 프로그래밍 기술


질문은 맨 아래에 굵게 표시되어 있으며 문제는 끝 부분의 증류 코드 조각으로 요약됩니다.

내 유형 시스템 (유형 시스템이 유형에서 문자열로, 유형에서 문자열로 수행)을 단일 구성 요소 (Lakos에서 정의한대로)로 통합하려고합니다. 내가 사용하고 boost::array, boost::variant하고, boost::mpl이를 달성하기 위해. 내 유형에 대한 파서 및 생성기 규칙을 변형으로 통합하고 싶습니다. 정의되지 않은 유형, int4 (아래 참조) 유형 및 int8 유형이 있습니다. 변형은 variant<undefined, int4,int8>.

int4 특성 :

struct rbl_int4_parser_rule_definition
{
  typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;

  boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;

  rule_type rule;

  rbl_int4_parser_rule_definition()
  {
    rule.name("rbl int4 rule");
    rule = parser_int32_t;  
  }
};

template<>
struct rbl_type_parser_rule<rbl_int4>
{
  typedef rbl_int4_parser_rule_definition string_parser;
};

위의 변형은 정의되지 않은 것으로 시작한 다음 규칙을 초기화합니다. 문제가 발생하여 50 페이지의 오류가 발생했고 마침내 추적 할 수있었습니다. Variant는 operator=할당 중에 사용 하고 a boost::spirit::qi::int_parser<>는 다른 사람에게 할당 할 수 없습니다 (operator =).

대조적으로, 정의되지 않은 유형에는 문제가 없습니다.

struct rbl_undefined_parser_rule_definition
{
  typedef boost::spirit::qi::rule<std::string::iterator, void()> rule_type;
  rule_type rule;

  rbl_undefined_parser_rule_definition()
  {
    rule.name("undefined parse rule");
    rule = boost::spirit::qi::eps;
  }
};

template<>
struct rbl_type_parser_rule<rbl_undefined>
{
  typedef rbl_undefined_parser_rule_definition string_parser;
};

문제의 증류 :

#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <boost/cstdint.hpp>

typedef boost::spirit::qi::rule<std::string::iterator,void()> r1;
typedef boost::spirit::qi::rule<std::string::iterator,int()> r2;

typedef boost::variant<r1,r2> v;

int main()
{
  /*
  problematic
  boost::spirit::qi::int_parser<int32_t> t2;
  boost::spirit::qi::int_parser<int32_t> t1;


  t1 = t2;
  */

  //unproblematic
  r1 r1_;
  r2 r2_;
  r1_ = r2_;

  v v_;
  // THIS is what I need to do.
  v_ = r2();
}

구체적인 파서와 규칙 사이에는 의미 론적 차이가 있습니다. 내 뇌는 지금 담배를 피우고 있으므로 실용주의에 대해 생각하지 않을 것입니다. 제 질문은이 문제를 어떻게 해결해야 하는가입니다. 문제를 해결하기 위해 세 가지 접근 방식을 생각할 수 있습니다.

1 : 정적 함수 멤버 :

struct rbl_int4_parser_rule_definition
{
  typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;

  //boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;

  rule_type rule;

  rbl_int4_parser_rule_definition()
  {
    static boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;

    rule.name("rbl int4 rule");
    rule = parser_int32_t;  
  }
};

접근 방식 1이 스레드 안전 코드를 방지한다고 생각합니까? ?

two: The integral parser is wrapped in a shared_ptr. There are two reasons I'm bothering with TMP for the typing system: 1 efficiency, 2 centralizing concerns into components. using pointers defeats the first reason.

three: operator= is defined as a no-op. variant guarantees that the lhs is default constructed before assignment.

Edit: I am thinking option 3 makes the most sense (operator= is a no-op). Once the rule container is created it will not change, and I am only assigning to force a type's rule trait into its offset.


I'm not so sure I get the full extent of the question, but here are a few hints

  • The line commented with // THIS is what I need to do. compiles fine with me (problem solved? I'm guessing you actually meant assigning a parser, not a rule?)

  • Initialization of function-local static has been defined to be thread safe in the latest standard (C++11). Check your compiler support for C++0x threading. (If the initializer throws, a pass of the initialization statement will try to initialize again, by the way).

  • rules alias()

    As described in http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases

    You can create 'logical copies' of rules without having to actually value-copy the proto expression. As the FAQ says, this is mainly to allow lazy-binding

  • The Nabialek Trick might be precisely what you need, basically it lazily selects a parser for subsequent parsing

    one = id;
    two = id >> ',' >> id;
    
    keyword.add
        ("one", &one)
        ("two", &two)
        ;
    
    start = *(keyword[_a = _1] >> lazy(*_a));
    

    In your context, I could see keyword defined as

    qi::symbols<char, qi::rule<Iterator>*> keyword;
    

    doing all the work with attributes from semantic actions. Alternatively,

    qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
    
  • Bring the rules under the same type (like shown in the previous line, basically)

    This is the part where I'm getting confused: You say you want to unify your type system. There might not be a need for strongtyped parsers (distinct attribute signatures).

    typedef boost::variant<std::string,int> unified_type;
    typedef qi::rule<std::string::iterator, unified_type() > unified_rule;
    
    unified_rule rstring = +(qi::char_ - '.');
    unified_rule rint    = qi::int_;
    
    unified_rule combine = rstring | rint;
    

참고URL : https://stackoverflow.com/questions/6060347/more-spirit-madness-parser-types-rules-vs-int-parser-and-meta-programming

반응형