Các đối số chống phân tích cú pháp Cthulhu là gì?


24

Tôi đã được giao nhiệm vụ triển khai Ngôn ngữ cụ thể miền cho một công cụ có thể trở nên khá quan trọng đối với công ty. Ngôn ngữ đơn giản nhưng không tầm thường, nó đã cho phép các vòng lặp lồng nhau, nối chuỗi, v.v. và thực tế chắc chắn rằng các cấu trúc khác sẽ được thêm vào khi dự án tiến triển.

Tôi biết bằng kinh nghiệm rằng việc viết một lexer / trình phân tích cú pháp bằng tay - không cần ngữ pháp là tầm thường - là một quá trình dễ bị mất thời gian và dễ bị lỗi. Vì vậy, tôi còn lại hai tùy chọn: trình tạo trình phân tích cú pháp à la yacc hoặc thư viện kết hợp như Parsec. Cái trước cũng tốt nhưng tôi chọn cái sau vì nhiều lý do, và thực hiện giải pháp bằng ngôn ngữ chức năng.

Kết quả là khá ngoạn mục đối với mắt tôi, mã rất súc tích, thanh lịch và dễ đọc / trôi chảy. Tôi thừa nhận nó có thể trông hơi kỳ lạ nếu bạn chưa bao giờ lập trình ở bất cứ thứ gì ngoài java / c #, nhưng sau đó điều này sẽ đúng với bất cứ điều gì không được viết bằng java / c #.

Tuy nhiên, tại một số điểm, tôi đã bị đồng nghiệp tấn công theo nghĩa đen. Sau khi liếc nhanh vào màn hình của tôi, anh ta tuyên bố rằng mã này không thể hiểu được và tôi không nên phát minh lại phân tích cú pháp mà chỉ sử dụng một ngăn xếp và String.Split như mọi người. Anh ta gây ồn ào, và tôi không thể thuyết phục anh ta, một phần vì tôi đã bị bất ngờ và không có lời giải thích rõ ràng, một phần vì ý kiến ​​của anh ta là bất biến (không có ý định chơi chữ). Tôi thậm chí đề nghị giải thích cho anh ta ngôn ngữ, nhưng vô ích.

Tôi khẳng định cuộc thảo luận sẽ xuất hiện trở lại trước ban lãnh đạo, vì vậy tôi đang chuẩn bị một số lập luận chắc chắn.

Đây là một vài lý do đầu tiên xuất hiện trong đầu tôi để tránh giải pháp dựa trên String.Split:

  • bạn cần rất nhiều ifs để xử lý các trường hợp đặc biệt và mọi thứ nhanh chóng vượt khỏi tầm kiểm soát
  • rất nhiều chỉ số mảng mã hóa cứng làm cho bảo trì đau đớn
  • cực kỳ khó xử lý những thứ như hàm gọi như một đối số phương thức (ví dụ: add ((thêm a, b), c)
  • rất khó để cung cấp các thông báo lỗi có ý nghĩa trong trường hợp lỗi cú pháp (rất có thể xảy ra)
  • Tôi hoàn toàn đơn giản, rõ ràng và tránh những thứ khó hiểu thông minh không cần thiết, nhưng tôi cũng tin rằng đó là một sai lầm khi làm câm lặng mọi phần của cơ sở mã để ngay cả một người bán bánh mì kẹp thịt cũng có thể hiểu được. Đó là cùng một lập luận mà tôi nghe thấy về việc không sử dụng giao diện, không chấp nhận phân tách mối quan tâm, sao chép mã dán xung quanh, v.v ... Rốt cuộc, tối thiểu phải có năng lực kỹ thuật và sẵn sàng học hỏi để làm việc trên một dự án phần mềm. (Tôi sẽ không sử dụng lập luận này vì nó có thể sẽ gây khó chịu và bắt đầu một cuộc chiến sẽ không giúp được ai)

Đối số yêu thích của bạn chống lại phân tích cú pháp theo cách của Cthulhu là gì? *

* tất nhiên nếu bạn có thể thuyết phục tôi thì anh ấy cũng sẽ hoàn toàn hạnh phúc


9
Âm thanh với tôi như đồng nghiệp của bạn đang tình nguyện làm dự án DSL cho bạn!
GrandmasterB

23
"Tôi không nên phát minh lại phân tích cú pháp mà chỉ sử dụng một ngăn xếp và String.Split như mọi người vẫn làm" - chết tiệt, anh chàng đó nên vui mừng vì sự thiếu hiểu biết không làm tổn thương ...
Michael Borgwardt

4
Khuyên đồng nghiệp của bạn không quay lại cuộc thảo luận này trừ khi anh ta đọc toàn bộ Sách Rồng và vượt qua bài kiểm tra. Nếu không, anh ta không có quyền thảo luận bất cứ điều gì liên quan đến phân tích cú pháp.
SK-logic

4
xin lỗi, ai đã phát minh lại phân tích cú pháp?
rwong

2
Tôi nghĩ đầu tôi sẽ nổ tung theo nghĩa đen vào lần tới khi tôi thấy ai đó sử dụng từ "nghĩa đen" theo nghĩa bóng.

Câu trả lời:


33

Sự khác biệt quan trọng giữa hai cách tiếp cận là, cách mà anh ta coi là cách duy nhất đúng là bắt buộc và của bạn là khai báo.

  • Cách tiếp cận của bạn tuyên bố rõ ràng các quy tắc, tức là các quy tắc ngữ pháp (hầu như) được mã hóa trực tiếp trong mã của bạn và thư viện trình phân tích cú pháp sẽ tự động chuyển đổi đầu vào thô thành đầu ra được phân tích cú pháp, trong khi quan tâm đến trạng thái và những thứ khác khó xử lý. Mã của bạn được viết trong một lớp trừu tượng duy nhất trùng với miền vấn đề: phân tích cú pháp. Thật hợp lý khi giả định tính chính xác của Parsec, điều đó có nghĩa là chỗ duy nhất có lỗi ở đây là định nghĩa ngữ pháp của bạn sai. Nhưng sau đó, một lần nữa bạn có các đối tượng quy tắc đủ điều kiện và chúng dễ dàng được kiểm tra một cách cô lập. Ngoài ra, có thể đáng chú ý, các thư viện trình phân tích cú pháp trưởng thành có một tính năng quan trọng: báo cáo lỗi. Phục hồi lỗi không đúng khi phân tích cú pháp bị lỗi không phải là chuyện nhỏ. Để chứng minh, tôi gọi PHP parse error, unexpected T_PAAMAYIM_NEKUDOTAYIM: D

  • Cách tiếp cận của anh ta thao túng các chuỗi, duy trì rõ ràng trạng thái và nâng đầu vào thô bằng tay thành đầu vào được phân tích cú pháp. Bạn phải tự viết mọi thứ, kể cả báo cáo lỗi. Và khi có sự cố xảy ra, bạn hoàn toàn lạc lối.

Điều trớ trêu bao gồm ở chỗ tính chính xác của trình phân tích cú pháp được viết theo cách tiếp cận của bạn tương đối dễ dàng được chứng minh. Trong trường hợp của anh, nó gần như không thể.

Có hai cách để xây dựng một thiết kế phần mềm: Một cách là làm cho nó đơn giản đến mức rõ ràng là không có thiếu sót, và cách khác là làm cho nó phức tạp đến mức không có thiếu sót rõ ràng. Phương pháp đầu tiên là khó khăn hơn nhiều.

Ô tô

Cách tiếp cận của bạn đơn giản hơn. Tất cả những gì ngăn cản là để anh ta mở rộng chân trời của mình một chút. Kết quả của cách tiếp cận của anh ta sẽ luôn luôn bị chia rẽ, cho dù chân trời của bạn rộng đến đâu.
Thành thật mà nói, với tôi, anh chàng đó chỉ là một kẻ ngu dốt, người mắc hội chứng blub , đủ kiêu ngạo để cho rằng bạn sai và la mắng bạn, nếu anh ta không hiểu bạn.

Tuy nhiên, cuối cùng, câu hỏi là: ai sẽ phải duy trì nó? Nếu đó là bạn, thì đó là cuộc gọi của bạn, bất kể ai nói gì. Nếu đó là anh ta, thì chỉ có hai khả năng: Tìm cách khiến anh ta hiểu thư viện trình phân tích cú pháp hoặc viết một trình phân tích cú pháp bắt buộc cho anh ta. Tôi đề nghị bạn tạo nó từ cấu trúc trình phân tích cú pháp của bạn: D


Giải thích tuyệt vời về sự khác biệt giữa hai phương pháp.
smarmy53

6
Bạn dường như đã liên kết với TVTropes cho lập trình viên. Chiều Tạm biệt ...
Izkata

10

Một ngữ pháp biểu thức phân tích cú pháp (như cách tiếp cận trình phân tích cú pháp Packrat) hoặc trình kết hợp trình phân tích cú pháp không phát minh lại phân tích cú pháp. Đây là những kỹ thuật được thiết lập tốt trong thế giới lập trình chức năng và, trong tay phải, nó có thể dễ đọc hơn các lựa chọn thay thế. Tôi đã thấy một minh chứng khá thuyết phục về PEG trong C # một vài năm trước đây thực sự sẽ biến nó thành công cụ đầu tiên của tôi cho các ngữ pháp tương đối đơn giản.

Nếu bạn có một giải pháp tao nhã bằng cách sử dụng bộ kết hợp trình phân tích cú pháp hoặc PEG, thì đó là một cách bán tương đối dễ dàng: nó khá dễ mở rộng, thường tương đối dễ đọc một khi bạn vượt qua nỗi sợ lập trình chức năng và đôi khi dễ đọc hơn trình tạo trình phân tích cú pháp thông thường công cụ cung cấp, mặc dù điều đó phụ thuộc rất nhiều vào ngữ pháp và mức độ kinh nghiệm bạn có với một trong hai bộ công cụ. Nó cũng khá dễ dàng để viết bài kiểm tra cho. Tất nhiên, có một số sự mơ hồ về ngữ pháp có thể dẫn đến hiệu suất phân tích cú pháp khá khủng khiếp trong các trường hợp xấu nhất (hoặc tiêu thụ nhiều bộ nhớ với Packrat), nhưng trường hợp trung bình khá tốt và thực tế một số sự mơ hồ về ngữ pháp được xử lý tốt hơn với PEG so với LALR, như Tôi gọi lại.

Sử dụng Split và ngăn xếp hoạt động với một số ngữ pháp đơn giản hơn PEG hoặc có thể hỗ trợ, nhưng rất có thể theo thời gian, bạn sẽ phát minh lại hậu duệ xấu, hoặc bạn sẽ có một loạt các hành vi dễ xảy ra mà bạn sẽ mắc phải viện trợ nộp với chi phí mã vô cùng phi cấu trúc. Nếu bạn chỉ có các quy tắc mã thông báo đơn giản thì có lẽ nó không tệ lắm, nhưng khi bạn thêm độ phức tạp, nó có thể sẽ là giải pháp ít bảo trì nhất. Thay vào đó tôi sẽ tiếp cận với một trình tạo phân tích cú pháp.

Cá nhân, thiên hướng đầu tiên của tôi khi tôi cần xây dựng DSL sẽ là sử dụng một cái gì đó như Boo (.Net) hoặc Groovy (JVM), vì tôi có được tất cả sức mạnh của ngôn ngữ lập trình hiện có và khả năng tùy biến đáng kinh ngạc bằng cách xây dựng các macro và điều chỉnh đơn giản với đường ống biên dịch, mà không phải thực hiện những thứ tẻ nhạt mà tôi sẽ làm nếu tôi bắt đầu từ số không (vòng lặp, biến, mô hình đối tượng, v.v.). Nếu tôi ở trong một cửa hàng đang phát triển Ruby hoặc Lisp, tôi sẽ chỉ sử dụng các thành ngữ có ý nghĩa ở đó (siêu lập trình, v.v.)

Nhưng tôi nghi ngờ vấn đề thực sự của bạn là về văn hóa hoặc bản ngã. Bạn có chắc rằng đồng nghiệp của bạn sẽ không hoảng sợ như nhau nếu bạn đã sử dụng Antlr hoặc Flex / Bison? Tôi nghi ngờ rằng "tranh luận" cho giải pháp của bạn có thể là một trận thua; bạn có thể cần dành nhiều thời gian hơn để thực hiện một cách tiếp cận nhẹ nhàng hơn, sử dụng các kỹ thuật xây dựng sự đồng thuận thay vì lôi cuốn cơ quan quản lý địa phương của bạn. Lập trình cặp và chứng minh bạn có thể nhanh chóng điều chỉnh ngữ pháp như thế nào mà không phải hy sinh khả năng duy trì và thực hiện một túi màu nâu để giải thích kỹ thuật, lịch sử của nó, v.v., có thể đi xa hơn 10 điểm gạch đầu dòng và một số câu hỏi "thô lỗ" cuộc gặp gỡ đối đầu.


9

Tôi không rành về thuật toán phân tích cú pháp và những thứ tương tự, nhưng tôi nghĩ bằng chứng của bánh pudding là trong việc ăn uống. Vì vậy, nếu thất bại, bạn có thể đề nghị anh ta thực hiện trình phân tích cú pháp theo cách của mình. Sau đó

  • so sánh thời gian đầu tư vào một trong hai giải pháp,
  • chạy cả hai giải pháp thông qua thử nghiệm chấp nhận toàn diện để xem cái nào có ít lỗi hơn và
  • có một thẩm phán độc lập so sánh mã kết quả về kích thước và độ rõ ràng với mã của bạn.

Để thử nghiệm thực sự công bằng, bạn có thể muốn cả hai giải pháp triển khai cùng một API và sử dụng một thử nghiệm chung (hoặc khung thử nghiệm đơn vị được cả hai bạn biết). Cả hai bạn có thể viết bất kỳ số lượng và loại trường hợp kiểm tra chức năng nào và đảm bảo rằng giải pháp của riêng anh ấy vượt qua tất cả chúng. Và tất nhiên, lý tưởng nhất là cả hai bạn không nên có quyền truy cập vào việc thực hiện của người khác trước thời hạn. Thử nghiệm quyết định sau đó sẽ là thử nghiệm chéo cả hai giải pháp bằng cách sử dụng bộ thử nghiệm được phát triển bởi nhà phát triển khác .


đây là một ý tưởng hay! Nó cũng sẽ dễ dàng sử dụng một khung kiểm tra đơn vị commont.
smarmy53

1
+1 vì đã để đồng nghiệp thực hiện phiên bản phân tách ... OP là người được giao nhiệm vụ tạo ra nó, vì vậy anh ta là người có khả năng sẽ phải hỗ trợ nó - không phải là đồng nghiệp. Chỉ cần gợi ý cho anh ấy trên đầu công việc khác của anh ấy là đủ để anh ấy rời khỏi lưng bạn.
Izkata

7

Bạn đã hỏi điều này như thể bạn có một câu hỏi kỹ thuật, nhưng như bạn có thể đã biết, không có câu hỏi kỹ thuật nào ở đây. Cách tiếp cận của bạn vượt trội hơn rất nhiều so với việc hack thứ gì đó ở cấp độ nhân vật.

Vấn đề thực sự là đồng nghiệp của bạn (có lẽ có nhiều kinh nghiệm hơn) không an toàn và cảm thấy bị đe dọa bởi kiến ​​thức của bạn. Bạn sẽ không thuyết phục anh ta bằng các lý lẽ kỹ thuật ; Điều đó sẽ chỉ khiến anh ta phòng thủ hơn. Thay vào đó, bạn sẽ phải tìm cách giảm bớt nỗi sợ hãi của anh ấy. Tôi không thể đưa ra nhiều gợi ý, nhưng bạn có thể thử thể hiện sự quan tâm cao đối với kiến ​​thức của anh ấy về mã kế thừa.

Cuối cùng, nếu người quản lý của bạn đồng ý với các lập luận kỹ thuật chuyên sâu của anh ấy và loại bỏ giải pháp của bạn, thì tôi nghĩ bạn sẽ phải tìm một vị trí khác. Rõ ràng bạn sẽ có giá trị hơn, và được đánh giá cao hơn, trong một tổ chức tinh vi hơn.


Bạn nói đúng Tôi đã biết rằng cách tiếp cận của tôi là vượt trội, tuy nhiên tôi đã không đưa ra được một lời giải thích hay, thuyết phục - đó là thông tin kỹ thuật mà tôi đang tìm kiếm. Đồng ý khía cạnh "tương tác của con người" của vấn đề cũng quan trọng như vấn đề kỹ thuật (nếu không muốn nói là nhiều hơn).
smarmy53

4

Tôi sẽ nói ngắn gọn:

Phân tích cách Cthulhu là khó. Đó là lý lẽ đơn giản và thuyết phục nhất chống lại nó.

Nó có thể thực hiện các mẹo cho các ngôn ngữ đơn giản; nói, ngôn ngữ thông thường. Nó có lẽ sẽ không dễ dàng hơn một biểu thức thông thường, mặc dù.

Nó cũng có thể thực hiện các mẹo cho các ngôn ngữ phức tạp hơn một chút.

Tuy nhiên, tôi muốn thấy một trình phân tích cú pháp Cthulhu cho bất kỳ ngôn ngữ nào có lồng nhau hoặc chỉ "trạng thái đáng kể" - các biểu thức toán học hoặc ví dụ của bạn (các hàm gọi lồng nhau).

Hãy tưởng tượng điều gì sẽ xảy ra nếu ai đó cố gắng cthulhu một trình phân tích cú pháp cho ngôn ngữ (không ngữ cảnh không tầm thường) như vậy. Miễn là anh ta đủ thông minh để viết một trình phân tích cú pháp chính xác, tôi cá rằng trong quá trình mã hóa, anh ta sẽ "khám phá" tokenizaton đầu tiên, và sau đó phân tích cú pháp gốc đệ quy - dưới một hình thức nào đó.

Sau đó, điều đơn giản: "Này này, bạn đã viết một thứ gọi là trình phân tích cú pháp gốc đệ quy! Bạn có biết rằng nó có thể được tạo tự động từ một mô tả ngữ pháp đơn giản, giống như các biểu thức thông thường không?


Câu chuyện dài ngắn:
Điều duy nhất có thể ngăn ai đó sử dụng cách tiếp cận văn minh là sự thiếu hiểu biết của họ về nó.


1

Có lẽ làm việc trên một ngữ nghĩa DSL tốt cũng rất quan trọng (cú pháp quan trọng, nhưng cũng là ngữ nghĩa). Nếu bạn không quen thuộc với những vấn đề này, tôi khuyên bạn nên đọc một số cuốn sách, như Lập trình ngôn ngữ lập trình (của M.Scott) và Christian Queinnec. Lisp trong miếng nhỏ . Nhà xuất bản Đại học Cambridge, 1996.

Đọc các bài báo gần đây trong các hội nghị DSL, ví dụ DSL2011 cũng sẽ giúp ích.

Thiết kế và triển khai một ngôn ngữ cụ thể miền là khó khăn (và hầu hết khó khăn không phải là phân tích cú pháp!).

Tôi thực sự không hiểu ý của bạn là gì khi phân tích cú pháp theo cách của Cthulhu ; Tôi đoán bạn chỉ có nghĩa là phân tích theo một cách kỳ lạ nào đó.


Liên kết tốt. Đối với Cthulhu, xin lỗi, tôi quên liên kết. Đây là một tài liệu tham khảo cho một bài viết về kinh dị mã hóa cổ điển: mã hóa kinh dị.com / blog / 2009/11 / parsing-html-the-cthulhu-way.html . Tôi đã cập nhật bài viết gốc.
smarmy53
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.