2011-01-06 39 views
6

Giống như nhiều câu hỏi khác, tôi đang cố gắng phân tích một ngữ pháp đơn giản thành một cây cấu trúc bằng cách sử dụng Boost.Spirit.Qi.Boost.Spirit.Qi: Lấy thuộc tính của quy tắc và đặt nó làm trường thuộc tính struct của quy tắc kèm theo?

Tôi sẽ cố gắng chưng cất những gì tôi đang cố gắng làm cho trường hợp đơn giản nhất có thể. Tôi có:

struct Integer { 
    int value; 
}; 
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value)) 

Sau đó, bên trong một cấu trúc ngữ pháp, tôi có biến thành viên sau đây:

qi::rule<Iterator, Integer> integer; 

mà tôi đang xác định với

integer = qi::int_; 

Khi tôi cố gắng thực sự phân tích một số nguyên, tuy nhiên, sử dụng

qi::phrase_parse(iter, end, g, space, myInteger); 

myInteger.value luôn được uninitialized sau khi phân tích thành công. Tương tự như vậy, tôi đã cố gắng định nghĩa sau đây (rõ ràng là những người mà không biên dịch là sai):

integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value 
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile 
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't 
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't 

Rõ ràng tôi đang hiểu lầm gì đó về Thánh Linh, Phoenix, hay cái gì khác. Sự hiểu biết của tôi là qi::_1 là thuộc tính đầu tiên của qi::int_, tại đây và phải đại diện cho số nguyên được phân tích cú pháp, khi phần trong dấu ngoặc vuông được thực hiện dưới dạng đối tượng hàm. Sau đó tôi giả định rằng đối tượng hàm sẽ lấy thuộc tính integer kèm theo qi::_val và thử và gán số nguyên được phân tách cho nó. Tôi đoán là vì cuộc gọi BOOST_FUSION_ADAPT_STRUCT của tôi, cả hai sẽ tương thích và chắc chắn có vẻ như là trường hợp từ góc độ phân tích tĩnh, nhưng dữ liệu không được bảo toàn.

Có một tham chiếu (&) chỉ định Tôi đang thiếu một nơi nào đó hoặc một cái gì đó?

+0

tôi chỉ tìm thấy một sự kết hợp đó biên dịch, mặc dù nó không dẫn đến dữ liệu khởi tạo: Tôi đã thêm một constructor cho 'Integer' mà phải mất một giá trị cho một' giá trị' , sau đó xác định phân tích cú pháp 'nguyên' của tôi là' integer = qi :: long_long [qi :: _ val = phx :: xây dựng (qi :: _ 1)]; ' – jtolds

+0

oops, ý tôi là' qi :: int_' – jtolds

+0

ghi chú. trong mã đầy đủ của tôi, tôi thực sự có 'qi :: rule integer;', có vẻ như nó bị hỏng nếu tôi thay thế 'Integer' bằng' Integer() ', và tất cả các ví dụ có dấu gạch chéo '()', mà tôi đã bỏ qua. Vì vậy, có lẽ các đối số mẫu cho 'quy tắc' đã bị vặn lên. Đào. – jtolds

Trả lời

13

Nếu Integer được coi là thuộc tính tiếp xúc bởi các quy tắc, bạn cần phải khai báo nó như:

qi::rule<Iterator, Integer()> integer; 

(lưu ý dấu ngoặc). Spirit yêu cầu sử dụng cú pháp khai báo hàm để mô tả 'giao diện' của quy tắc. Nó được sử dụng không chỉ trong Spirit mà còn bởi một số thư viện khác nữa (xem boost :: function chẳng hạn).

Lý do chính cho việc này là đó là cách súc tích để chỉ định giao diện chức năng. Nếu bạn nghĩ về quy tắc là gì, bạn nhanh chóng nhận ra rằng đó là một hàm: nó có thể trả về một giá trị (kết quả được phân tích cú pháp, tức là thuộc tính tổng hợp). Ngoài ra nó có thể mất một hoặc nhiều đối số (các thuộc tính kế thừa).

Lý do thứ hai, nhưng nhỏ là Spirit cần có khả năng phân biệt các tham số mẫu khác nhau của quy tắc. Các tham số mẫu có thể được xác định theo thứ tự bất kỳ (ngoại trừ trình lặp), vì vậy nó cần một số phương tiện để tìm ra những gì là gì. Cú pháp khai báo hàm hoàn toàn khác với trình thu thập thông tin hoặc mã hóa (hai tham số mẫu có thể khác) để cho phép nó được nhận dạng tại thời gian biên dịch.

Hãy xem xét các nỗ lực khác nhau của bạn:

Điều này có thể được thực hiện nếu bạn thay đổi định nghĩa quy tắc như được nêu ở trên.

integer = qi::int_[qi::_val = qi::_1]; 

Các _val đề cập đến Integer của bạn, trong khi _1 đề cập đến một int. Vì vậy, bạn cần phải xác định một toán tử gán từ int để làm cho công việc này:

struct Integer { 
    int value; 
    Integer& operator=(int) {...} 
};      

Bạn không cần phải thích ứng với kiểu của bạn như là một chuỗi Fusion trong trường hợp này.

Nhưng bạn có thể viết nó thậm chí còn dễ dàng hơn:

integer = qi::int_ >> qi::eps; 

mà là 100% tương đương (các eps là một thủ thuật dùng để chuyển đổi phía bên tay phải vào một chuỗi phân tích cú pháp, cho phép sử dụng được xây dựng trong tuyên truyền thuộc tính ánh xạ các phần tử của chuỗi Fusion đã được điều chỉnh của bạn đến các thuộc tính của các phần tử của chuỗi).

này:

integer = qi::int_[qi::_r1 = qi::_1]; 

sẽ không làm việc như _r1 đề cập đến thuộc tính thừa hưởng đầu tiên của một quy tắc. Tuy nhiên, quy tắc của bạn không có thuộc tính không được nhấn.

này sẽ làm việc:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; 

nhưng không đòi hỏi phải thích ứng loại của bạn như là một chuỗi Fusion.

Và như vậy sẽ này:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
+0

oh đẹp, cảm ơn bạn. do đó, có vẻ như tôi đã có một bản mẫu hoàn chỉnh. – jtolds

+2

'git commit -a -m 'Hartmut Kaiser là người đàn ông!'' – jtolds

Các vấn đề liên quan