2010-08-12 33 views
10

Tôi đang cố viết một trình phân tích ngôn ngữ trình bao trong Boost.Spirit. Tuy nhiên, tôi không rõ ràng về một số vấn đề cơ bản liên quan đến ngữ nghĩa của rule s.Sao chép hoặc tham chiếu ngữ nghĩa của boost :: quy tắc của tinh thần <>?

Nhìn vào tài liệu, có các thành viên r.alias()r.copy() trong số rule. IIUC, các thành viên này nên trả về một tham chiếu đến quy tắc và một bản sao nội dung của quy tắc, tương ứng. Tuy nhiên, nó không được xác định rõ ràng những gì sẽ xảy ra khi tôi chỉ sử dụng quy tắc trong định nghĩa của một quy tắc khác. Từ các thử nghiệm của tôi, tôi đã tìm thấy các quy tắc đệ quy hai bên có thể được xác định bởi:

rule<Iter> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

cho biết các quy tắc được thực hiện bằng tham chiếu bên trong biểu thức phân tích cú pháp. Vấn đề là, nó làm gì khi biến đi ra khỏi phạm vi, ví dụ:

rule<Iter> r1; 
{ 
    rule<Iter> r2; 
    r1 = ... >> r2 >> ...; 
    r2 = ... >> r1 >> ...; 
} 
... // use r1 

Cùng lưu ý, sẽ gán cho một quy tắc từ một biểu thức phân tích có chứa một rvalue công việc loại quy tắc (r.copy() sẽ một rvalue loại rule quá, phải không?) ví dụ.

rule<Iter> f() { return char_('a') << char_('b'); } 
rule<Iter> r1 = ... << f(); 

Ai có thể soi sáng cho tôi về ngữ nghĩa chi tiết của bản và tài liệu tham khảo rule 's, và có thể sửa bất kỳ quan niệm sai lầm trong bài viết này?

Trả lời

13

Câu trả lời tùy thuộc vào phiên bản Spirit bạn đang đề cập đến.


Spirit.Classic (trước đây là Spirit V1.x) thực hiện ngữ nghĩa đặc biệt cho các quy tắc. Các tài liệu cho biết:

Khi một quy tắc được tham chiếu bất cứ nơi nào trong phía bên tay phải của một biểu thức EBNF , các quy tắc được tổ chức bởi sự biểu hiện bằng cách tham khảo. Trách nhiệm của của khách hàng là đảm bảo rằng quy tắc được tham chiếu nằm trong phạm vi và không bị hủy trong khi đang được tham chiếu.

Toán tử gán về cơ bản cũng tham chiếu đến quy tắc rh mà không cần tạo bản sao sâu. Điều này được thực hiện để cho phép:

rule<> r1, r2; 
r1 = ...; 
r2 = r1; 

Nhưng điều này hóa ra là rất nhầm lẫn vì nó ngăn cản xử lý các quy tắc giống như đối tượng 'bình thường'.

Vì lý do đó có chức năng thành viên rule::copy(), cho phép tạo các bản sao sâu sắc rõ ràng của quy tắc (ví dụ để lưu trữ chúng trong một vùng chứa STL).

Cùng thời gian này:

r2 = r1.copy(); 

là sai đơn giản. r2 sẽ đề cập đến bản sao tạm thời (bị hủy) của r1 được trả lại từ hàm copy().


Trong Spirit.Qi (tức là Spirit V2.x) hành vi này bị thay đổi một phần.các quy tắc hiện đang hoạt động như mong đợi khi được xử lý bên ngoài trình phân tích cú pháp. Bạn có thể lưu trữ chúng bình thường trong các thùng chứa (toán tử gán cho thấy hành vi mong đợi). Nhưng hãy cẩn thận, mà bên trong một phân tích cú pháp quy định biểu hiện vẫn đang nắm giữ tài liệu tham khảo, mà vẫn cho phép để đề cập đến một nguyên tắc theo cùng một cách như trước:

rule<> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

Đôi khi nó là cần thiết để tạo một bản sao sâu của một quy tắc, do đó vẫn là thành viên functon copy.

Ngữ nghĩa bản sao đã thay đổi có tác dụng phụ khác. Cấu trúc thích:

r1 = r2; 

đang tạo một (sâu) bản sao của r2, mà có thể không được những gì bạn mong đợi, đặc biệt là nếu r2 sẽ nhận được RHS của nó được gán chỉ sau khi bị 'giao' để r1. Vì lý do đó có chức năng thành viên mới alias phép ngữ nghĩa tham khảo cho các trường hợp góc này:

r1 = r2.alias(); 

Trong mọi trường hợp, ở cả hai phiên bản của Thần Khí bạn sẽ kết thúc với sự tham khảo tòn ten nếu một phần của các quy tắc tham chiếu từ một phân tích cú pháp biểu thức nằm ngoài phạm vi.

BTW, không phiên bản Spirit nào thực hiện chức năng rule::ref().

+0

Cảm ơn câu trả lời này. Tôi chỉ có một câu hỏi tiếp theo: Có cách nào có thể sử dụng các giá trị (tạm thời) của các biểu thức phân tích cú pháp của một số loại trong biểu thức phân tích cú pháp để cho phép các câu lệnh như 'r1 = r1 | string ("abc") 'hoặc tạo các quy tắc trong một hàm? – jpalecek

+0

Trong khi biểu thức 'r1 = r1 | chuỗi ("abc") 'về mặt lý thuyết có thể là một đệ quy trái, điều này sẽ dẫn đến một đệ quy vô hạn vì Spirit tạo ra các trình phân tích cú pháp gốc đệ quy. Nhưng biểu thức 'r1 = string ("abc") | r1 'sẽ hoạt động như mong đợi. Bạn có thể tạo một quy tắc trong một hàm nếu bạn đảm bảo rằng nó không tham chiếu đến bất kỳ quy tắc nào khác, mà đã vượt quá phạm vi. Ngoài ra, trong Spirit.Classic bạn cần trả về r.copy() từ hàm. – hkaiser

+0

'r1 = chuỗi ("abc") | r1 'là trái đệ quy quá :) Nhưng những gì tôi muốn làm, là làm cho r1 phù hợp với những gì r1 phù hợp trước đó và "abc". BTW làm thế nào tôi có thể tạo ra một quy tắc trong một chức năng? Điều này không hiệu quả đối với tôi: http://pastebin.org/482764 – jpalecek

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