Có những từ vựng thực sự sử dụng NFA trực tiếp thay vì trước tiên chuyển đổi chúng thành DFA không?


7

Tôi đang học lớp Coursera trên các trình biên dịch và trong bài học về từ vựng, có gợi ý rằng có một sự đánh đổi không gian thời gian giữa việc sử dụng máy tự động hữu hạn không xác định (NFA) và máy tự động hữu hạn xác định (DFA) để phân tích các biểu thức chính quy. Nếu tôi hiểu chính xác, sự đánh đổi là một NFA nhỏ hơn, nhưng tốn nhiều thời gian hơn để đi qua vì tất cả các trạng thái có thể phải được xem xét cùng một lúc và do đó, phần lớn thời gian được chuyển thành DFA. Có bất kỳ từ vựng nào sử dụng NFA thay vì DFA trong "đời thực" tức là một số trình biên dịch được sử dụng trong sản xuất và không chỉ là một bằng chứng về khái niệm?


Thay vì "... tất cả các trạng thái có thể phải được xem xét ...", đó là "... tất cả các chuyển đổi có thể phải được xem xét ...". Điều này khó hơn theo cấp số nhân và có thể nhanh chóng phát triển lớn hơn tổng số tiểu bang.
Paresh

Mặc dù tôi không tích cực về điều này, nhưng cách PRolog phân tích cú pháp sẽ không đáp ứng yêu cầu của bạn.
Guy Coder

Câu trả lời:


4

Tôi chỉ thấy hai ứng dụng sử dụng NFA (hay đúng hơn là tự động hóa năng lượng của nó mà không ghi nó xuống) thay vì DFA thu nhỏ:

  1. Ngôn ngữ đồng âm , nơi bạn có thể muốn sửa đổi từ vựng của mình thường xuyên
  2. Cú pháp kỳ lạ có thể làm nổ tung DFA của bạn như

    identifier := [a-z][a-z0-9_]*
    indices := [0-9_]{1,256} //up to 256 times
    var := identifier "_" indices | identifier
    

    Nếu bạn lấy quy tắc cuối cùng làm ưu tiên, thì từ vựng của bạn phải kiểm tra xem một mã định danh có chứa "_" trong 256 ký hiệu cuối cùng hay không và rút ngắn nó trong trường hợp này.


1
Nếu một số người tàn bạo cho tôi ngôn ngữ thứ hai, tôi sẽ xử lý nó ngoài FA nghiêm ngặt. Ví dụ, trình biên dịch C thường nhận ra việc /*bắt đầu nhận xét và bỏ qua phần khớp với */mã C. Bên cạnh đó, một ngôn ngữ có thể không thể đọc được cho con người.
vonbrand

Đây không phải là một ví dụ tự nhiên, mặt khác, nó không khó đọc nếu không bị lạm dụng nhiều và lạm dụng cú pháp nặng nề cũng có thể xảy ra trong C. Xử lý điều này giống như nhận xét trong C (chuyển đổi chế độ) không phải là quá dễ dàng, bởi vì nó phụ thuộc vào sự kết thúc của một định danh có thể. (+1 cho "kẻ tàn bạo").
từ

4

Các máy phân tích từ vựng được biên dịch biên dịch NFA thành DFA.

Mặt khác, các trình so khớp biểu thức chính được diễn giải tốt , sử dụng thuật toán của Thompson, mô phỏng NFA với khả năng ghi nhớ. Điều này tương đương với việc biên dịch NFA thành DFA, nhưng bạn chỉ tạo ra các trạng thái DFA theo yêu cầu, nếu cần. Ở mỗi bước, trạng thái xác định của bạn là một tập hợp các trạng thái NFA, sau đó đưa ra ký tự đầu vào tiếp theo mà bạn chuyển sang một bộ trạng thái NFA mới. Bạn lưu trữ các trạng thái đã thấy trước đó và các chuyển đổi đầu ra của chúng trong bảng băm. Bảng băm được tuôn ra nếu nó lấp đầy, nó không phát triển mà không bị ràng buộc.

Lý do bạn làm theo cách này là vì việc chuyển đổi NFA sang DFA có thể mất thời gian theo cấp số nhân theo kích thước của biểu thức chính quy. Đây chắc chắn không phải là điều bạn muốn làm nếu bạn chỉ đánh giá biểu thức thông thường một lần.

RE2 là một ví dụ về công cụ regex (về cơ bản) sử dụng thuật toán của Thompson. Tôi rất có thể giới thiệu các bài đăng trên blog tuyệt vời của tác giả của Russ2, Russ Cox nếu bạn muốn tìm hiểu thêm (bao gồm nhiều thông tin lịch sử và so sánh thử nghiệm của nhiều cách tiếp cận khác nhau để tìm kiếm regex.

Tôi cũng rất có thể khuyến nghị chuỗi email " tại sao GNU grep nhanh ". Bài học 1 là: trường hợp phổ biến cho tìm kiếm regex là tìm kiếm chuỗi đơn giản, vì vậy trường hợp đặc biệt là thuật toán của bạn.


3

Tôi sẽ ngạc nhiên nếu họ đã làm. Việc xây dựng lexer được thực hiện một lần (hy vọng), kết quả được sử dụng hàng triệu lần (chỉ cần nghĩ có bao nhiêu mã thông báo trong tệp nguồn cỡ trung bình của bạn). Vì vậy, trừ khi có những trường hợp rất bất thường, nó sẽ được đền đáp để làm cho lexer càng nhanh (và các tài nguyên khác tiết kiệm) càng tốt, tức là, hãy sử dụng DFA tối thiểu.


1
DFA tối thiểu rất có thể có kích thước theo cấp số nhân; nếu nó quá lớn, việc khám phá NFA có thể hợp lý hơn so với việc lưu trữ DFA. Điều đó nói rằng, tôi không biết rằng bất kỳ hệ thống nào cũng xem xét điều đó.
Raphael

0

Theo nghĩa chính thức nghiêm ngặt, không. Không xác định theo nghĩa lý thuyết / toán học cho phép một cỗ máy chọn một con đường tính toán dựa trên việc cuối cùng nó có dẫn đến trạng thái chấp nhận hay không mà không cần nhìn xa hơn về đầu vào . Vì vậy, theo nghĩa nghiêm ngặt này, đó là một tài sản chỉ phù hợp để kiểm tra lý thuyết và không có thứ gọi là máy không xác định thực sự, đặc biệt trong trường hợp này bạn không thể thực sự xây dựng NFA, trừ khi bạn có thể nhìn thấy trong tương lai, trong trường hợp xây dựng một trình biên dịch với tài năng này là một sự lãng phí! ;).

Tuy nhiên, chủ nghĩa không phá hủy và không phá hủy thường được sử dụng theo nghĩa yếu hơn, được xác định một cách nguy hiểm. Đôi khi nó có thể có nghĩa là ngẫu nhiên / xác suất - thuật toán lật một đồng xu, trong một thiết lập chính thức, điều này được nghiên cứu như các thuật toán xác suất / ngẫu nhiên, và không được gọi là thuyết không xác định. Một cách sử dụng khác là cho một thuật toán không nhất thiết tạo ra cùng một đầu ra với hai lần chạy trên cùng một đầu vào - nó có thể không ngẫu nhiên, nhưng một số hành vi của nó là không xác định, vì vậy có thể có một số đầu ra hợp lệ (cá nhân tôi nghĩ rằng định nghĩa xuất phát từ việc nhầm lẫn không xác định và không xác định .

Tuy nhiên, về nguyên tắc, bạn có thể xây dựng một từ vựng không đặc biệt ở một trong những giác quan yếu hơn, không chính thức này, tuy nhiên đó sẽ không phải là một NFA (đó là một mô hình máy chính thức nghiêm ngặt) và tôi không thể tưởng tượng được đó là một sự cố ý tưởng nóng hoặc - một lexer cần phải khá dễ đoán.

Tùy chọn cuối cùng là bạn có thể mô phỏng tính không xác định thông qua quay lui hoặc song song, nhưng trong trường hợp này, bạn mất đi hiệu quả rõ ràng của tính không xác định, vì bạn thực sự biến nó thành một tính toán xác định, vì vậy bạn không tốt hơn tắt hơn với một DFA.


Trong trường hợp cụ thể này, hoàn toàn có thể theo dõi tất cả các trạng thái có thể có mà NFA có thể có với chi phí không gian khiêm tốn, về cơ bản là thực hiện quét lần đầu tiên trên cây tính toán. Không cần quả cầu pha lê.
vonbrand

@vonbrand, đây là phiên bản hợp lý của bộ chuyển đổi NFA thành DFA, vì vậy chúng tôi trở lại DFA.
Luke Mathieson

OP là một câu hỏi thực hiện . Trong bối cảnh này, sự khác biệt giữa DFA và NFA là trong DFA, mỗi trạng thái có chính xác một chuyển đổi đầu ra cho mỗi ký hiệu đầu vào có thể. Một NFA, trong ngữ cảnh này, là một máy trạng thái trong đó mỗi trạng thái có thể có 0, 1 hoặc nhiều chuyển đổi đầu ra cho mỗi ký hiệu đầu vào và cũng cho phép chuyển đổi . OP đang hỏi liệu trên thực tế, chúng tôi (xác định) mô phỏng NFA (bằng cách giữ các bộ trạng thái) hay liệu chúng tôi biên dịch NFA thành DFA, sau đó chạy DFA. Cho dù có bất kỳ "không thực" nào là không liên quan. ϵ
Logic lang thang
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.