Là phân tích cú pháp và lexing riêng biệt vượt qua thực hành tốt với các tổ hợp trình phân tích cú pháp?


18

Khi tôi bắt đầu sử dụng các trình kết hợp trình phân tích cú pháp, phản ứng đầu tiên của tôi là cảm giác giải phóng khỏi cảm giác giống như sự phân biệt giả tạo giữa phân tích cú pháp và từ vựng. Tất cả mọi thứ đột nhiên chỉ là phân tích cú pháp!

Tuy nhiên, gần đây tôi đã xem qua bài đăng này trên codereview.stackexchange minh họa cho ai đó phục hồi sự khác biệt này. Lúc đầu, tôi nghĩ rằng điều này rất ngớ ngẩn với họ, nhưng sau đó thực tế là các chức năng tồn tại trong Parsec để hỗ trợ hành vi này khiến tôi phải tự đặt câu hỏi.

Những lợi thế / bất lợi của việc phân tích cú pháp trên một luồng đã được lexed trong các trình kết hợp trình phân tích cú pháp là gì?


Xin vui lòng ai đó có thể thêm thẻ [trình phân tích cú pháp]?
Eli Frey

Câu trả lời:


15

Dưới phân tích cú pháp, chúng tôi hiểu hầu hết phân tích các ngôn ngữ tự do ngữ cảnh. Một ngôn ngữ tự do ngữ cảnh mạnh hơn ngôn ngữ thông thường, do đó trình phân tích cú pháp có thể (thường xuyên nhất) thực hiện công việc của bộ phân tích từ vựng ngay lập tức.

Nhưng, đây là một) khá không tự nhiên b) thường không hiệu quả.

Đối với a), nếu tôi nghĩ về việc ví dụ ifbiểu thức trông như thế nào , tôi nghĩ NẾU expr THEN expr ELSE expr chứ không phải 'i' 'f', có thể một số khoảng trắng, sau đó bất kỳ ký tự nào mà một biểu thức có thể bắt đầu, v.v. ý tưởng.

Đối với b) có các công cụ mạnh mẽ thực hiện công việc tuyệt vời để nhận ra các thực thể từ vựng, như định danh, nghĩa đen, dấu ngoặc, v.v. Chúng sẽ thực hiện công việc của chúng trong thực tế không có thời gian và cung cấp cho bạn một giao diện đẹp: danh sách các mã thông báo. Không phải lo lắng về việc bỏ qua khoảng trắng trong trình phân tích cú pháp nữa, trình phân tích cú pháp của bạn sẽ trừu tượng hơn nhiều khi nó xử lý các mã thông báo chứ không phải với các ký tự.

Rốt cuộc, nếu bạn nghĩ rằng một trình phân tích cú pháp nên bận rộn với các công cụ cấp thấp, tại sao sau đó xử lý các ký tự? Người ta có thể viết nó cũng trên cấp độ bit! Bạn thấy đấy, một trình phân tích cú pháp như vậy hoạt động ở cấp độ bit sẽ gần như không thể hiểu được. Nó giống với các ký tự và mã thông báo.

Chỉ 2 xu của tôi.


3
Chỉ vì mục đích chính xác: một trình phân tích cú pháp luôn có thể thực hiện công việc của một bộ phân tích từ vựng.
Giorgio

Ngoài ra, liên quan đến hiệu quả: Tôi không chắc chắn nếu trình phân tích cú pháp sẽ kém hiệu quả hơn (chậm hơn). Tôi hy vọng rằng ngữ pháp kết quả sẽ chứa một ngữ pháp phụ mô tả một ngôn ngữ thông thường và mã cho ngữ pháp phụ đó sẽ nhanh như một bộ phân tích từ vựng tương ứng. IMO quan điểm thực sự là (a): làm thế nào tự nhiên, trực quan để làm việc với một trình phân tích cú pháp đơn giản hơn, trừu tượng hơn.
Giorgio

@Giorgio - Về nhận xét đầu tiên của bạn: Bạn đã đúng. Những gì tôi đã nghĩ ở đây là những trường hợp mà từ vựng thực tế thực hiện một số công việc giúp ngữ pháp dễ dàng hơn, để người ta có thể sử dụng LALR (1) thay vì LALR (2).
Ingo

2
Tôi đã loại bỏ sự chấp nhận câu trả lời của bạn sau khi thử nghiệm và suy ngẫm thêm. Nó nối liền hai bạn đến từ thế giới yon của Antlr et all. Xem xét bản chất lớp đầu tiên của trình kết hợp trình phân tích cú pháp, tôi thường chỉ đơn giản là kết thúc việc xác định trình phân tích cú pháp trình bao bọc cho trình phân tích mã thông báo của tôi để lại mỗi mã thông báo dưới dạng một tên trong lớp phân tích cú pháp. ví dụ nếu ví dụ của bạn sẽ trông như thế if = string "if" >> expr >> string "then" >> expr >> string "else" >> expr.
Eli Frey

1
Hiệu suất vẫn là một câu hỏi mở, tôi sẽ làm một số điểm chuẩn.
Eli Frey

8

Mọi người đều cho rằng tách biệt từ vựng và phân tích cú pháp là một "cách thực hành tốt" - tôi phải không đồng ý - trong nhiều trường hợp, việc thực hiện từ vựng và phân tích cú pháp trong một lần duy nhất mang lại nhiều sức mạnh hơn và ý nghĩa về hiệu suất không tệ như chúng được trình bày trong câu trả lời khác (xem Packrat ).

Cách tiếp cận này tỏa sáng khi người ta phải trộn một số ngôn ngữ khác nhau trong một luồng đầu vào. Điều này không chỉ cần thiết bởi các ngôn ngữ định hướng siêu lập trình kỳ lạ như Katahdintương tự , mà còn cho các ứng dụng chính thống hơn nhiều, như lập trình biết chữ (trộn latex và, nói, C ++), sử dụng HTML trong nhận xét, đưa Javascript vào HTML và Sớm.


Trong câu trả lời của tôi, tôi đã gợi ý rằng đó là một "thực hành tốt trong các bối cảnh nhất định" và không phải là "thực hành tốt hơn trong tất cả các bối cảnh".
Giorgio

5

Một bộ phân tích từ vựng nhận ra một ngôn ngữ thông thường và một trình phân tích cú pháp nhận ra một ngôn ngữ không ngữ cảnh. Vì mỗi ngôn ngữ thông thường cũng không có ngữ cảnh (có thể được xác định bởi cái gọi là ngữ pháp tuyến tính phải ), trình phân tích cú pháp cũng có thể nhận ra một ngôn ngữ thông thường và sự phân biệt giữa trình phân tích cú pháp và phân tích từ vựng dường như thêm một số phức tạp không cần thiết: một ngữ cảnh đơn lẻ ngữ pháp miễn phí (trình phân tích cú pháp) có thể thực hiện công việc của trình phân tích cú pháp và trình phân tích từ vựng.

Mặt khác, có thể hữu ích khi nắm bắt một số yếu tố của ngôn ngữ không ngữ cảnh thông qua ngôn ngữ thông thường (và do đó là máy phân tích từ vựng) bởi vì

  1. Thông thường các yếu tố này xuất hiện thường xuyên đến mức chúng có thể được xử lý theo cách tiêu chuẩn: nhận dạng số và chuỗi ký tự, từ khóa, mã định danh, bỏ qua khoảng trắng, v.v.
  2. Việc xác định ngôn ngữ thông thường của mã thông báo giúp việc ngữ pháp không ngữ cảnh trở nên đơn giản hơn, ví dụ: người ta có thể suy luận về mặt định danh, không phải về các ký tự riêng lẻ hoặc người ta có thể bỏ qua khoảng trắng hoàn toàn nếu nó không phù hợp với ngôn ngữ cụ thể đó.

Vì vậy, phân tách phân tích cú pháp khỏi phân tích từ vựng có lợi thế là bạn có thể làm việc với một ngữ pháp không ngữ cảnh đơn giản hơn và gói gọn một số tác vụ cơ bản (thường là thường lệ) trong máy phân tích từ vựng (chia et đế chế).

CHỈNH SỬA

Tôi không quen thuộc với các trình kết hợp trình phân tích cú pháp vì vậy tôi không chắc các cân nhắc trên áp dụng như thế nào trong bối cảnh đó. Ấn tượng của tôi là ngay cả khi với các trình kết hợp trình phân tích cú pháp, người ta chỉ có một ngữ pháp không ngữ cảnh, việc phân biệt giữa hai cấp độ (phân tích từ vựng / phân tích cú pháp) có thể giúp làm cho ngữ pháp này trở nên mô đun hơn. Như đã nói, lớp phân tích từ vựng thấp hơn có thể chứa các trình phân tích cú pháp có thể tái sử dụng cơ bản cho các định danh, nghĩa đen, v.v.


2
Từ vựng rơi vào ngữ pháp thông thường không phải tự nhiên, mà theo quy ước, vì tất cả các từ vựng được xây dựng trên các công cụ biểu thức chính quy. Nó đang giới hạn sức mạnh biểu cảm của các ngôn ngữ bạn có thể thiết kế.
SK-logic

1
Bạn có thể đưa ra một ví dụ về một ngôn ngữ mà nó sẽ phù hợp để xác định các từ vựng không thể được mô tả như một ngôn ngữ thông thường không?
Giorgio

1
ví dụ: trong một vài ngôn ngữ cụ thể của miền mà tôi đã tạo, số nhận dạng có thể là biểu thức TeX, đơn giản hóa việc in mã, ví dụ: một biểu thức như \alpha'_1 (K_0, \vec{T}), trong đó \ alpha'_1, K_0 và \ vec {T} là định danh.
SK-logic

1
Đưa ra một ngữ pháp không ngữ cảnh, bạn luôn có thể lấy N không phải đầu cuối và coi các từ mà nó có thể rút ra là các đơn vị có ý nghĩa hữu ích trong chính chúng (ví dụ: một biểu thức, một thuật ngữ, một số, một câu lệnh). Điều này có thể được thực hiện bất kể bạn phân tích đơn vị đó như thế nào (trình phân tích cú pháp, trình phân tích cú pháp + lexer, v.v.). IMO sự lựa chọn của một trình phân tích cú pháp + lexer là một kỹ thuật (cách thực hiện phân tích cú pháp) hơn là một ngữ nghĩa (ý nghĩa của các khối mã nguồn mà bạn phân tích) là gì. Có thể tôi đang nhìn một cái gì đó nhưng hai khía cạnh trông trực giao với tôi.
Giorgio

3
Vì vậy, tôi đồng ý với bạn: nếu bạn xác định một số khối xây dựng cơ bản tùy ý ( lexemes ) và muốn sử dụng một máy phân tích từ vựng để nhận ra chúng, điều này không phải lúc nào cũng tốt. Tôi chỉ tự hỏi nếu đây là mục tiêu của một lexer. Theo tôi hiểu, mục tiêu của một bộ phân tích từ vựng là một mục tiêu kỹ thuật: lấy đi một số chi tiết triển khai cấp thấp, tẻ nhạt từ trình phân tích cú pháp.
Giorgio

3

Đơn giản, nên tách biệt và phân tích cú pháp vì chúng phức tạp khác nhau. Lexing là một DFA (automaton hữu hạn xác định) và trình phân tích cú pháp là một PDA (tự động đẩy xuống). Điều này có nghĩa là phân tích cú pháp vốn đã tiêu tốn nhiều tài nguyên hơn so với từ vựng và có các kỹ thuật tối ưu hóa cụ thể chỉ dành cho DFA. Ngoài ra, việc viết một máy trạng thái hữu hạn sẽ ít phức tạp hơn và dễ dàng tự động hóa hơn.

Bạn đang lãng phí bằng cách sử dụng thuật toán phân tích cú pháp để lex.


Nếu bạn sử dụng trình phân tích cú pháp để phân tích từ vựng, thì PDA sẽ không bao giờ sử dụng ngăn xếp, về cơ bản nó sẽ hoạt động như một DFA: chỉ tiêu thụ đầu vào và nhảy giữa các trạng thái. Tôi không chắc chắn 100%, nhưng tôi nghĩ rằng các kỹ thuật tối ưu hóa (giảm số lượng trạng thái) có thể được áp dụng cho DFA cũng có thể được áp dụng cho một thiết bị PDA. Nhưng có: viết trình phân tích từ vựng dễ dàng hơn như vậy mà không cần sử dụng một công cụ mạnh hơn, và sau đó viết một trình phân tích cú pháp đơn giản hơn trên đầu trang.
Giorgio

Ngoài ra, nó làm cho toàn bộ điều linh hoạt hơn và bảo trì. Chẳng hạn, giả sử chúng ta có một trình phân tích cú pháp cho ngôn ngữ Haskell mà không có quy tắc bố cục (nghĩa là với dấu chấm phẩy và dấu ngoặc nhọn). Nếu chúng ta có một từ vựng riêng biệt, bây giờ chúng ta có thể thêm các quy tắc bố cục bằng cách thực hiện một lần chuyển qua mã thông báo khác, thêm dấu ngoặc nhọn và dấu chấm phẩy khi cần. Hoặc, cho một ví dụ dễ dàng hơn: giả sử chúng tôi bắt đầu với một ngôn ngữ chỉ hỗ trợ các ký tự ASCII trong mã định danh và bây giờ chúng tôi muốn hỗ trợ các chữ cái unicode trong mã định danh.
Ingo

1
@Ingo, và tại sao bạn cần phải làm điều đó trong một từ vựng riêng biệt? Chỉ cần yếu tố ra các thiết bị đầu cuối.
SK-logic

1
@ SK-logic: Tôi không chắc tôi hiểu câu hỏi của bạn. Tại sao một lexer riêng biệt có thể là một lựa chọn tốt mà tôi đã cố gắng chứng minh trong bài viết của mình.
Ingo

Giorgio, không. Ngăn xếp là một thành phần quan trọng của trình phân tích cú pháp kiểu LALR bình thường. Làm lexing với một trình phân tích cú pháp là một sự lãng phí bộ nhớ (cả lưu trữ tĩnh và phân bổ động) và sẽ chậm hơn nhiều. Mô hình Lexer / Parser hiệu quả - sử dụng nó :)
riwalk

1

Một trong những lợi thế chính của phân tích cú pháp / lex riêng biệt là biểu diễn trung gian - luồng mã thông báo. Điều này có thể được xử lý theo nhiều cách khác nhau mà không thể thực hiện được với một lex / parse kết hợp.

Điều đó nói rằng, tôi đã thấy rằng 'ol đệ quy tốt có thể ít phức tạp hơn và dễ dàng hơn để làm việc với việc học một số trình tạo trình phân tích cú pháp và phải tìm ra cách diễn đạt điểm yếu của ngữ pháp trong các quy tắc của trình tạo trình phân tích cú pháp.


Bạn có thể giải thích thêm về các ngữ pháp được thể hiện dễ dàng hơn trên luồng được tạo sẵn sau đó được thực hiện tại thời điểm phân tích không? Tôi chỉ có kinh nghiệm triển khai các ngôn ngữ đồ chơi và một vài định dạng dữ liệu ít ỏi, vì vậy có lẽ tôi đã bỏ lỡ điều gì đó. Bạn có nhận thấy bất kỳ đặc điểm hiệu suất nào giữa các bộ phân tích cú pháp / lex RD cuộn tay của bạn và các trình tạo BNF được cho ăn không (tôi giả sử)?
Eli Frey
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.