2012-02-22 15 views
5

Hãy xem xét ví dụ về phân tích cú pháp như thế này:Trình kết hợp phân tích cú pháp: Tính năng repsep có cho phép theo dõi lại không?

object TestParser extends RegexParsers { 
    override protected val whiteSpace = """[ \t]*""".r 

    def eol = """(\r?\n)+""".r 
    def item = "[a-zA-Z][a-zA-Z0-9-]*".r 
    def list = "items:" ~> rep1sep(item,",") 
    def constraints = "exclude:" ~> item 

    def itemsDefinition = (rep1sep(list, eol) ~ repsep(constraints,eol)) 
} 

Nếu tôi cố gắng phân tích đầu vào này (mà không hai dòng chứa loại trừ công trình OK):

items: item1, item2, item3, item3, item4 
items: item2, item3, item3, item5, item4  
items: item4, item5, item6, item10  
items: item1, item2, item3 
exclude: item1 
exclude: item2 

tôi nhận được lỗi sau:

[5.5] failure: `items:' expected but `e' found 

     exclude: item1 

    ^

Vấn đề hiển nhiên là dòng này:

def itemsDefinition = (rep1sep(list, eol) ~ repsep(constraints,eol)) 

Lý do không hoạt động. Nó có liên quan đến việc quay ngược lại không? Tôi phải làm gì để làm cho nó hoạt động?

+0

Nếu có ai đề xuất tiêu đề câu hỏi hay hơn, vui lòng cho tôi biết. Không chắc chắn nếu nó thậm chí có ý nghĩa .. – PrimosK

Trả lời

5

Bạn sẽ cần một eol giữa danh sách của bạn và những hạn chế của bạn

(rep1sep(list, eol) <~ eol) ~ repsep(constraint,eol) 

Hoàn thành câu trả lời:

ngữ pháp của bạn chỉ định eol dấu phân tách giữa danh sách, không phải là một terminator. Nó sẽ chấp nhận một đầu vào trong đó exclude đầu tiên xuất hiện ngay sau item3 cuối cùng (với khoảng trắng, nhưng không phải là dòng mới).

Sau khi trình phân tích cú pháp của bạn đạt đến số không mong muốn eol, tìm kiếm items và tìm số excludes thay thế. Cung cấp thông báo lỗi được hiển thị. Sau đó, trình phân tích cú pháp thực sự quay trở lại, đến dòng mới trước đó. Nó xem xét khả năng phần danh sách dừng ở đó và tìm kiếm loại trừ. Nhưng nếu tìm thấy một eol thay thế. Vì vậy, một thông báo lỗi khác có thể là "excludes expected, eol found", trong trường hợp này sẽ hữu ích hơn

Khi có sự lựa chọn ngữ pháp và không có chi nhánh nào thành công, trình phân tích cú pháp sẽ trả về lỗi ở vị trí xa hơn, thường là chiến lược đúng. Giả sử ngữ pháp của bạn cho phép "if" hoặc "for" và đầu vào là "if !!!". Trên chi nhánh if, lỗi sẽ là một cái gì đó như "(" expected, "!" found. Trên chi nhánh for, thông báo sẽ là "for expected, if found". Rõ ràng, thông báo từ chi nhánh if, xuất hiện trên mã thông báo thứ hai, tốt hơn thông điệp từ chi nhánh for, trên mã thông báo đầu tiên và không liên quan chút nào.

Về vấn đề tách/terminator, bạn có thể xem xét:

  • separator (; trong Pascal): repsep(item, separator)
  • terminator (; trong C): rep(item <~ terminator)
  • linh hoạt: repsep(item, separator) <~ separator?

điều cuối cùng sẽ cho phép một dấu tách đơn lẻ sau khi không có mục nào cả. Nếu điều này là không mong muốn, có thể (rep1sep(item, separator) <~ separator?)?.

+0

Wow .. Tuyệt vời! Nhưng lý do nó hoạt động theo cách này là gì? – PrimosK

+0

Tôi cho rằng vì "sep" nằm giữa "danh sách" và không phải sau mỗi lần lặp lại. Vì vậy, trình phân tích cú pháp không thể "rời" 'rep1sep' đầu tiên và nó mong đợi một" danh sách "sau mỗi" eol ". – paradigmatic

+0

Câu trả lời tuyệt vời !! TY – PrimosK

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