2014-10-01 29 views
5

Trong một PEG bình thường (phân tích biểu ngữ pháp) này là một ngữ pháp hợp lệ:Tạo một LPeg mẫu đệ quy

values <- number (comma values)* 
number <- [0-9]+ 
comma <- ',' 

Tuy nhiên, nếu tôi cố gắng viết này sử dụng LPeg bản chất đệ quy của quy tắc mà vẫn thất bại:

local lpeg = require'lpeg' 

local comma = lpeg.P(',') 
local number = lpeg.R('09')^1 
local values = number * (comma * values)^-1 
--> bad argument #2 to '?' (lpeg-pattern expected, got nil) 

Mặc dù trong ví dụ đơn giản này tôi có thể viết lại quy tắc để không sử dụng đệ quy, tôi có một số ngữ pháp hiện có mà tôi không muốn viết lại.

Tôi làm cách nào để viết quy tắc tự tham chiếu trong LPeg?

Trả lời

5

Sử dụng grammar.

Với việc sử dụng biến Lua, có thể xác định mẫu theo từng bước, với mỗi mẫu mới sử dụng mẫu được xác định trước đó. Tuy nhiên, kỹ thuật này không cho phép định nghĩa các mẫu đệ quy. Đối với các mẫu đệ quy, chúng ta cần các ngữ pháp thực.

LPeg đại diện cho các ngữ pháp có bảng, trong đó mỗi mục nhập là một quy tắc.

Cuộc gọi lpeg.V (v) tạo ra một mẫu đại diện cho nonterminal (hoặc biến) với chỉ số v trong một ngữ pháp. Bởi vì ngữ pháp vẫn không tồn tại khi hàm này được đánh giá, kết quả là một tham chiếu mở với quy tắc tương ứng.

Một bảng được cố định khi nó được chuyển đổi thành một mẫu (hoặc bằng cách gọi lpeg.P hoặc bằng cách sử dụng nó trong đó một mẫu được mong đợi). Sau đó, mọi tham chiếu mở được tạo bởi lpeg.V (v) được sửa lại để tham chiếu đến quy tắc được chỉ mục bởi v trong bảng.

Khi bàn được cố định, kết quả là mẫu phù hợp với quy tắc ban đầu của nó. Mục nhập với chỉ mục 1 trong bảng xác định quy tắc ban đầu của nó. Nếu mục nhập đó là một chuỗi, nó được giả định là tên của quy tắc ban đầu. Nếu không, LPeg giả định rằng chính mục 1 là quy tắc ban đầu.

Như một ví dụ, ngữ pháp sau đây phù hợp với chuỗi của một và b của có cùng số một và b của:

equalcount = lpeg.P{ 
    "S"; -- initial rule name 
    S = "a" * lpeg.V"B" + "b" * lpeg.V"A" + "", 
    A = "a" * lpeg.V"S" + "b" * lpeg.V"A" * lpeg.V"A", 
    B = "b" * lpeg.V"S" + "a" * lpeg.V"B" * lpeg.V"B", 
} * -1 

Nó tương đương với văn phạm sau đây trong ký hiệu PEG tiêu chuẩn:

S <- 'a' B/'b' A/'' 
    A <- 'a' S/'b' A A 
    B <- 'b' S/'a' B B 
+1

Chắc chắn là câu trả lời đúng; nhưng tôi có thể thực sự chấp nhận câu trả lời là bản sao/dán từ hướng dẫn sử dụng, mà không cần cố gắng định dạng? : p – Phrogz

+0

@Phrogz Nếu bạn thực sự đã đặt câu hỏi trực tiếp được giải quyết bằng hướng dẫn đó?=) Và đó là "định dạng", hãy thử dán trích dẫn đó từ hướng dẫn trực tiếp vào câu trả lời và sau đó chỉ chặn trích dẫn tất cả những gì bạn không nhận được ở trên. =) –

+0

Tôi không nên có, nhưng tôi đã không nhận ra phần này của hướng dẫn sử dụng như áp dụng lúc đầu tiên. My ': p' phải là một':) '. Bạn đã làm tốt, cảm ơn bạn. – Phrogz

0

tôi biết đây là một câu trả lời cuối nhưng đây là một ý tưởng làm thế nào để back-tham khảo một quy tắc

local comma = lpeg.P(',') 
local number = lpeg.R('09')^1 
local values = lpeg.P{ lpeg.C(number) * (comma * lpeg.V(1))^-1 } 

local t = { values:match('1,10,20,301') } 

Về cơ bản ngữ pháp nguyên thủy được chuyển đến lpeg.P (ngữ pháp chỉ là một bảng được tôn vinh) tham chiếu đến quy tắc đầu tiên theo số thay vì tên tức là lpeg.V(1).

Mẫu chỉ thêm một lần chụp lpeg.C đơn giản trên number thiết bị đầu cuối và thu thập tất cả các kết quả này trong bảng cục bộ t để sử dụng thêm. (Lưu ý rằng không có lpeg.Ct được sử dụng mà không phải là một việc lớn nhưng vẫn ... một phần của mẫu tôi đoán.)

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