điên cuồng hơn về tinh thần - kiểu phân tích cú pháp (quy tắc so với int_parser <>) và kỹ thuật lập trình siêu


80

Câu hỏi được in đậm ở phía dưới, vấn đề cũng được tóm tắt bằng đoạn mã chưng cất về cuối.

Tôi đang cố gắng thống nhất hệ thống kiểu của mình (hệ thống kiểu thực hiện và chuyển từ kiểu sang chuỗi) thành một thành phần duy nhất (theo định nghĩa của Lakos). Tôi đang sử dụng boost::array, boost::variantboost::mpl, để đạt được điều này. Tôi muốn thống nhất các quy tắc phân tích cú pháp và trình tạo cho các loại của mình trong một biến thể. có một loại không xác định, một loại int4 (xem bên dưới) và một loại int8. Biến thể đọc là variant<undefined, int4,int8>.

đặc điểm 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;
};

biến thể ở trên bắt đầu là không xác định và sau đó tôi khởi tạo các quy tắc. Tôi đã gặp sự cố, gây ra lỗi 50 trang và cuối cùng tôi đã tìm ra được nó, Biến thể sử dụng operator=trong quá trình gán và boost::spirit::qi::int_parser<>không thể gán một biến thể cho người khác (toán tử =).

Ngược lại, tôi không gặp vấn đề với loại không xác định của mình:

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;
};

Chưng cất vấn đề:

#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();
}

Có một khoảng cách ngữ nghĩa giữa các trình phân tích cú pháp cụ thể và các quy tắc. Bộ não của tôi lúc này đang hút thuốc vì vậy tôi sẽ không nghĩ về bệnh liệt dương, Câu hỏi của tôi là, làm cách nào để giải quyết vấn đề này? Tôi có thể nghĩ ra ba cách tiếp cận để giải quyết vấn đề.

một: Các thành viên hàm tĩnh:

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;  
  }
};

Tôi đoán cách tiếp cận một ngăn chặn mã an toàn luồng? ?

hai: Trình phân tích cú pháp tích phân được bao bọc trong shared_ptr. Có hai lý do khiến tôi bận tâm với TMP cho hệ thống đánh máy: 1 hiệu quả, 2 là tập trung mối quan tâm vào các thành phần. sử dụng con trỏ đánh bại lý do đầu tiên.

ba: operator = được định nghĩa là không chọn. biến thể đảm bảo rằng cái lhsđược tạo mặc định trước khi gán.

Chỉnh sửa: Tôi đang nghĩ lựa chọn 3 hợp lý nhất (toán tử = là không chọn). Khi vùng chứa quy tắc được tạo, nó sẽ không thay đổi và tôi chỉ chỉ định để buộc đặc điểm quy tắc của một loại vào phần bù của nó.


1
tùy chọn 1 chỉ không an toàn cho luồng nếu: parser_int32_tcó trạng thái tham chiếu được sử dụng. Nếu không có trạng thái hoặc một bản sao được tạo ra, thì nó là an toàn. Từ ngữ nghĩa, tôi sẽ nói một bản sao được tạo ra.
Matthieu M.

Đó là một mối quan tâm khá khó hiểu, tôi không thể chắc chắn rằng đối tượng phân tích cú pháp không có trạng thái. Ngoài ra, có các ngữ nghĩa tham chiếu và cụ thể với cơ học quy tắc -ie, một quy tắc có thể chứa các tham chiếu đến các quy tắc khác, nhưng bản thân chúng cũng có thể là bộ phân tích cú pháp cụ thể (tôi nghĩ vậy) và tôi không biết những ngữ nghĩa này áp dụng cho bộ phân tích cú pháp cụ thể như thế nào .
Hassan Syed

@MatthieuM: Đúng vậy, một bản sao được tạo ra trừ khi .alias()được sử dụng.
ildjarn

@ildjarn nhưng quy tắc không phải là trình phân tích cú pháp cụ thể: D nội dung của quy tắc là một biểu thức, tương đương với một cây phân tích cú pháp.
Hassan Syed

1
Tôi không thể đánh giá liệu số 1 có an toàn hay không, nhưng tôi có thể đưa ra một vài lời khuyên rất dễ quên. Một phép gán tĩnh chỉ được trình biên dịch đánh giá một lần. Hãy tưởng tượng một chút kiểm tra trong mã (if (! Eval_yet) eval () else noop ()). lần đầu tiên bất kỳ đối tượng thành viên có liên quan nào của rbl_int4_parser_rule_definition được gọi ở bất kỳ đâu, nó sẽ được xây dựng tại thời điểm đó. nó gần như hoàn toàn tương đương với việc sử dụng một singleton toàn cục. bạn có thể sử dụng một singleton toàn cục thuộc loại đó để giải quyết vấn đề tương tự không? (bỏ qua inti. order, v.v.) nếu vậy, điều này phải an toàn cho luồng.
std''OrgnlDave

Câu trả lời:


11

Tôi không chắc mình hiểu được toàn bộ câu hỏi, nhưng đây là một vài gợi ý

  • Dòng nhận xét với các // THIS is what I need to do.biên dịch tốt với tôi (vấn đề đã được giải quyết? Tôi đoán bạn thực sự muốn chỉ định một trình phân tích cú pháp chứ không phải một quy tắc?)

  • Việc khởi tạo hàm-cục bộ staticđã được xác định là an toàn cho luồng trong tiêu chuẩn mới nhất (C ++ 11). Kiểm tra hỗ trợ trình biên dịch của bạn để phân luồng C ++ 0x. (Nhân tiện, nếu trình khởi tạo ném, một đoạn lệnh khởi tạo sẽ cố gắng khởi tạo lại).

  • quy tắc alias()

    Như được mô tả trong http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases

    Bạn có thể tạo 'bản sao hợp lý' của các quy tắc mà không cần phải thực sự sao chép giá trị của biểu thức proto. Như Câu hỏi thường gặp đã nói, điều này chủ yếu là để cho phép liên kết lười biếng

  • Các Nabialek Lừa có thể là chính xác những gì bạn cần, về cơ bản nó uể oải chọn một phân tích cú pháp cho phân tích tiếp theo

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

    Trong ngữ cảnh của bạn, tôi có thể thấy keywordđược định nghĩa là

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

    thực hiện tất cả các công việc với các thuộc tính từ các hành động ngữ nghĩa. Ngoài ra,

    qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
    
  • Đưa các quy tắc vào cùng một loại (về cơ bản như được hiển thị trong dòng trước)

    Đây là phần mà tôi đang bối rối: Bạn nói rằng bạn muốn thống nhất hệ thống loại của mình. Có thể không cần trình phân tích cú pháp kiểu mạnh (chữ ký thuộc tính riêng biệt).

    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;
    
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.