Làm thế nào chính xác một trình biên dịch phục hồi từ một lỗi loại?


10

Tôi đã đọc một số bài báo, bài báo và phần 4.1.4, chương 4 của Trình biên dịch: Nguyên tắc, Kỹ thuật và Công cụ (Ấn bản 2) (còn gọi là "Cuốn sách rồng"), tất cả đều thảo luận về chủ đề phục hồi lỗi trình biên dịch cú pháp. Tuy nhiên, sau khi thử nghiệm với một số trình biên dịch hiện đại, tôi đã thấy rằng chúng cũng phục hồi từ các lỗi ngữ nghĩa , cũng như các lỗi cú pháp.

Tôi hiểu khá rõ các thuật toán và kỹ thuật đằng sau trình biên dịch phục hồi từ các lỗi liên quan đến cú pháp, tuy nhiên tôi không hiểu chính xác làm thế nào trình biên dịch có thể phục hồi từ một lỗi ngữ nghĩa.

Tôi hiện đang sử dụng một biến thể nhỏ của mẫu khách truy cập để tạo mã từ cây cú pháp trừu tượng của mình. Hãy xem xét trình biên dịch của tôi biên dịch các biểu thức sau:

1 / (2 * (3 + "4"))

Trình biên dịch sẽ tạo cây cú pháp trừu tượng sau:

      op(/)
        |
     -------
    /       \ 
 int(1)    op(*)
             |
          -------
         /       \
       int(2)   op(+)
                  |
               -------
              /       \
           int(3)   str(4)

Giai đoạn tạo mã sau đó sẽ sử dụng mẫu khách truy cập để duyệt qua cây cú pháp trừu tượng và thực hiện kiểm tra kiểu. Cây cú pháp trừu tượng sẽ được duyệt qua cho đến khi trình biên dịch đến phần trong cùng của biểu thức; (3 + "4"). Trình biên dịch sau đó kiểm tra từng mặt của biểu thức và thấy rằng chúng không tương đương về mặt ngữ nghĩa. Trình biên dịch làm tăng một loại lỗi. Đây là vấn đề nằm ở đâu. Bây giờ trình biên dịch nên làm gì ?

Để trình biên dịch phục hồi từ lỗi này và tiếp tục gõ kiểm tra các phần bên ngoài của biểu thức, nó sẽ phải trả về một số loại ( inthoặc str) từ việc đánh giá phần trong cùng của biểu thức, đến phần trong cùng tiếp theo của biểu thức. Nhưng nó chỉ đơn giản là không có một loại để trở lại . Vì một lỗi loại xảy ra, không có loại nào được suy ra.

Một giải pháp khả thi mà tôi đã đưa ra, đó là nếu xảy ra lỗi loại, lỗi sẽ được đưa ra và một giá trị đặc biệt biểu thị rằng đã xảy ra lỗi loại, nên được trả về các lệnh gọi ngang qua cây cú pháp trừu tượng trước đó. Nếu các cuộc gọi truyền tải trước gặp phải giá trị này, họ biết rằng lỗi loại xảy ra sâu hơn trong cây cú pháp trừu tượng và nên tránh cố gắng suy ra một loại. Trong khi phương pháp này dường như không hoạt động, nó dường như rất không hiệu quả. Nếu phần trong cùng của một biểu thức nằm sâu trong cây cú pháp trừu tượng, thì trình biên dịch sẽ phải thực hiện nhiều lệnh gọi đệ quy để nhận ra rằng không có tác phẩm thực sự nào có thể được thực hiện và chỉ cần trả về từ mỗi một.

Là phương pháp tôi mô tả ở trên được sử dụng (tôi nghi ngờ nó). Nếu vậy, nó không hiệu quả? Nếu không, chính xác các phương thức được sử dụng khi trình biên dịch phục hồi từ các lỗi ngữ nghĩa là gì?


3
Khá chắc chắn đó là những gì được sử dụng, và tại sao bạn không nghĩ rằng nó đủ hiệu quả? Để làm được việc kiểm tra loại, trình biên dịch phải đi toàn bộ cây anyways . Một lỗi ngữ nghĩa sẽ hiệu quả hơn vì nó cho phép trình biên dịch loại bỏ một nhánh một khi lỗi được tìm thấy.
Telastyn

Câu trả lời:


8

Ý tưởng đề xuất của bạn về cơ bản là chính xác.

Điều quan trọng là loại nút AST chỉ được tính một lần và sau đó được lưu trữ. Bất cứ khi nào loại cần thiết một lần nữa, nó chỉ cần lấy loại được lưu trữ. Nếu độ phân giải kết thúc bằng một lỗi, một loại lỗi được lưu trữ thay thế.


3

Một cách tiếp cận thú vị là có một loại đặc biệt cho lỗi. Khi gặp lỗi như vậy lần đầu tiên, chẩn đoán được ghi lại và loại lỗi được trả về là loại biểu thức. Loại lỗi này có một số thuộc tính thú vị:

  • Bất kỳ thao tác nào được thực hiện trên nó đều thành công (để ngăn chặn một loạt các thông báo lỗi gây ra bởi cùng một lỗi ban đầu)
  • Kết quả của bất kỳ hoạt động nào được thực hiện trên một đối tượng có loại lỗi cũng có loại lỗi
  • Nếu một loại lỗi xảy ra khi tạo mã, trình tạo mã sẽ phát hiện việc sử dụng và tạo mã không thành công (ví dụ: ném ngoại lệ, hủy bỏ hoặc bất cứ điều gì phù hợp với ngôn ngữ của bạn)

Với sự kết hợp này, bạn thực sự có thể biên dịch thành công mã có chứa lỗi loại và miễn là mã đó không thực sự được sử dụng, sẽ không xảy ra lỗi thời gian chạy. Điều này có thể hữu ích, ví dụ, để cho phép bạn chạy thử nghiệm đơn vị cho các phần của mã không bị ảnh hưởng.


Cảm ơn câu trả lời Jules. Hài hước lắm, đây là phương pháp chính xác mà tôi đã sử dụng. Những bộ óc vĩ đại nghĩ giống nhau, nhỉ? ;-)
Christian Dean

2

Nếu có lỗi ngữ nghĩa, một thông báo lỗi biên dịch cho biết như vậy sẽ được cấp cho người dùng.

Khi đã xong, bạn có thể hủy bỏ việc biên dịch vì chương trình đầu vào bị lỗi - đó không phải là chương trình hợp pháp trong ngôn ngữ, vì vậy đơn giản là nó có thể bị từ chối.

Tuy nhiên, điều đó khá khắc nghiệt, vì vậy có những lựa chọn thay thế nhẹ nhàng hơn. Hủy bỏ bất kỳ việc tạo mã và tạo tệp đầu ra, nhưng vẫn tiếp tục một cái gì đó để tìm thêm lỗi.

Ví dụ, nó có thể đơn giản hủy bỏ mọi phân tích kiểu tiếp theo cho cây biểu thức hiện tại và tiếp tục xử lý các biểu thức từ các câu lệnh tiếp theo.


2

Giả sử ngôn ngữ của bạn cho phép thêm số nguyên và cho phép nối chuỗi với +toán tử.

int + stringkhông được phép, việc đánh giá +sẽ dẫn đến một lỗi được báo cáo. Trình biên dịch chỉ có thể trả về errornhư kiểu. Hoặc nó có thể thông minh hơn, vì int + int -> intstring + string -> stringđược cho phép, nó có thể trả về "lỗi, có thể là int hoặc chuỗi".

Sau đó, đến *nhà điều hành, và chúng tôi sẽ giả sử chỉ int + intđược phép. Trình biên dịch sau đó có thể quyết định rằng cái +thực sự được cho là trả về int, và kiểu được trả về *sau đó sẽ intkhông có bất kỳ thông báo lỗi nào.


Tôi nghĩ rằng tôi theo dõi bạn, @gnasher, nhưng chính xác thì ý của nhà điều hành "" là gì? Đó có phải là lỗi đánh máy không?
Christian Dean

@ChristianDean có dấu hoa thị trong dấu ngoặc kép đang được hiểu là đánh dấu Markdown thay vì được hiển thị.
JakeRobb

Tôi đã gửi một bản chỉnh sửa cho câu trả lời sẽ giải quyết vấn đề ngay khi bản chỉnh sửa của tôi được xem xét ngang hàng.
JakeRobb
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.