Có trình biên dịch nào cố gắng tự sửa lỗi cú pháp không? [đóng cửa]


15

Tôi đã nghe một thời gian trước rằng đã từng có một trình biên dịch cố sửa các lỗi cú pháp bằng cách phân tích ngữ cảnh và suy ra những gì được dự định.

Liệu một trình biên dịch như vậy thực sự tồn tại? Rõ ràng nó có ít giá trị thực tế, nhưng sẽ rất thú vị để chơi và học hỏi.


3
IntelliSense có thuộc loại này không? Nhiều trình biên dịch có lỗi tương tự như [dấu chấm phẩy] dự kiến.
Robert Harvey

1
@Robert: Không, nhưng đó là một điểm tốt.
Nathan Osman

1
Một người bạn của tôi đã thực hiện khá nhiều hack trên bộ tiền xử lý C, ví dụ 'inlcude -> bao gồm', và một số công việc cố gắng tìm ra nơi đóng các điều kiện mở. Đó là luận án thạc sĩ của anh ấy, mà anh ấy đã nhanh chóng từ bỏ vì một điều gì đó dễ dàng hơn. Tuy nhiên, một câu hỏi khá thú vị!
Tim Post

3
Trình biên dịch AC # không thành công với các thông báo lỗi RẤT hữu ích. Điều đó kết hợp với tài liệu tốt có sẵn trực tuyến cho mọi mã lỗi hoạt động khá tốt. Đó là một ý tưởng tồi để tự động sửa cú pháp, mặc dù các trình thông dịch HTML (ví dụ: trình duyệt) thường làm điều đó.
Công việc

1
Trình biên dịch mà bạn đang đề cập đến là PL / I ban đầu. Nó giả định bất cứ điều gì lập trình viên viết phải có ý nghĩa gì đó, và cố gắng đoán xem đó có thể là gì. Theo kinh nghiệm của tôi, nó đã đoán rất tệ!
david.pfx

Câu trả lời:


28

Theo một nghĩa nào đó, hành động biên dịch suy ra cú pháp nào đó có nghĩa là gì, và do đó lỗi cú pháp là khi trình biên dịch không thể tìm ra nó. Bạn có thể thêm nhiều "đoán" để trình biên dịch suy ra những điều xa hơn và linh hoạt hơn với cú pháp, nhưng nó phải thực hiện điều này bằng cách suy ra một bộ quy tắc cụ thể. Và những quy tắc đó sau đó trở thành một phần của ngôn ngữ, và không còn là lỗi nữa.

Vì vậy, không, không có trình biên dịch như vậy, thực sự, bởi vì câu hỏi không có ý nghĩa. Đoán những lỗi cú pháp có nghĩa là phải làm theo một số bộ quy tắc chỉ trở thành một phần của cú pháp.

Theo nghĩa đó, có một ví dụ hay về trình biên dịch thực hiện điều này: Bất kỳ trình biên dịch C. Họ thường sẽ chỉ in ra một cảnh báo về một cái gì đó không giống như vậy, và sau đó giả sử bạn có nghĩa là X, và tiếp tục. Trên thực tế, đây là "đoán" mã không rõ ràng (mặc dù chủ yếu không phải là cú pháp mỗi lần), một cái gì đó cũng có thể đã ngừng biên dịch với một lỗi và do đó đủ điều kiện là một lỗi.


4
Đây là câu trả lời đúng. Khi trình biên dịch có thể khôi phục từ một lỗi, nó thực sự không còn là lỗi nữa. Perl nổi tiếng với hành vi "Làm những gì tôi muốn nói", chọn những gì lập trình viên rất có thể có nghĩa là được cung cấp nguồn mơ hồ.
Jon Purdy

Perl hy sinh tính dài dòng cho kích thước mã nguồn.
Nathan Osman

@George Edison: Đó là một tautology hoặc mâu thuẫn.
Jon Purdy

Hoặc một cái nhìn sâu sắc. :)
Lennart Regebro

23

Âm thanh thực sự nguy hiểm. Nếu trình biên dịch cố gắng suy luận ý định của bạn, hiểu sai, sửa mã và sau đó không cho bạn biết (hoặc nói với bạn trong một số cảnh báo rằng bạn, như mọi người, bỏ qua), thì bạn sắp chạy mã có thể nghiêm túc làm một số thiệt hại.

Một trình biên dịch như thế này có lẽ là một cái gì đó rất cố ý KHÔNG được tạo ra.


5
Tôi biết điều đó. Một trình biên dịch như vậy sẽ không được sử dụng để biên dịch, nhưng khái niệm này khá thú vị và có tiềm năng học hỏi.
Nathan Osman

2
hầu như tất cả các IDE mới nhất cung cấp gợi ý cho cú pháp và nó thực sự hữu ích. và phần còn lại đồng ý với nganju
Jigar Joshi

Tôi sẽ không sử dụng một trình biên dịch như vậy. Nó xuất hiện dưới tiêu đề 'ma thuật đen'.
Michael K

Hmmm, bạn sẽ đánh giá suy luận kiểu của Scala ở đâu trong thang đo này? Đã thử nó, nó sẽ nói rằng đó là một đóng góp lớn cho mã ngắn gọn. Mặt khác, nó thỉnh thoảng bắn vào chân tôi (ví dụ vì tôi nghĩ rằng tôi đang xử lý các danh sách nhưng thực sự vẫn đang xử lý các bộ).
timday

Chúng tôi có những thứ như tự động trong OMP, vì vậy một chút trong số đó là có thể thực hiện được. Tất nhiên, mã tôi làm việc đã tắt tính năng tự động tắt vì chúng tôi không tin tưởng nó. Tôi có thể thấy có một trình biên dịch tương tác hỏi "ý bạn là XXX?". Đó là xa như tôi sẽ sẵn sàng để đi. Và thậm chí điều đó có lẽ quá nguy hiểm.
Omega Centauri

12

IDE cho ngôn ngữ lập trình thường ngày nay có trình biên dịch chạy nền, vì vậy nó có thể cung cấp các dịch vụ phân tích như tô màu cú pháp, IntelliSense, lỗi, v.v. Rõ ràng một trình biên dịch như vậy cần phải có khả năng hiểu được mã bị hỏng sâu; hầu hết thời gian khi chỉnh sửa, mã không chính xác. Nhưng chúng ta vẫn phải có ý nghĩa của nó.

Tuy nhiên, thông thường tính năng khôi phục lỗi chỉ được sử dụng trong quá trình chỉnh sửa; nó không có ý nghĩa gì khi cho phép biên dịch thực tế trong các tình huống "chính tuyến".

Thật thú vị, chúng tôi đã xây dựng tính năng đó vào trình biên dịch JScript.NET; về cơ bản có thể đưa trình biên dịch vào một chế độ trong đó chúng tôi cho phép trình biên dịch tiến hành ngay cả khi gặp lỗi, nếu IDE sẽ phục hồi từ nó. Bạn có thể nhập mã Visual Basic , chạy trình biên dịch JScript.NET trên đó và có cơ hội hợp lý để một chương trình làm việc xuất hiện ở đầu kia!

Đây là một bản demo thú vị, nhưng hóa ra nó không phải là một tính năng rất tốt cho các kịch bản "chính tuyến" vì nhiều lý do. Một lời giải thích đầy đủ sẽ khá dài; lời giải thích ngắn gọn là nó làm cho các chương trình hoạt động không thể đoán trướctình cờ , và làm cho nó khó chạy cùng một mã thông qua nhiều trình biên dịch hoặc nhiều phiên bản của cùng một trình biên dịch. Các chi phí lớn mà tính năng thêm vào không được chứng minh bằng các lợi ích nhỏ.

Peter Torr, người đã đưa tính năng này trở lại trong ngày, thảo luận ngắn gọn về nó trong bài đăng blog này từ năm 2003 .

Mặc dù chúng tôi phơi bày tính năng này thông qua các API lưu trữ tập lệnh của công cụ JScript .NET, tôi không biết bất kỳ khách hàng thực sự nào đã từng sử dụng nó.


Tôi ước gì chủ nhân của tôi có tài nguyên để thử nghiệm như thế; chúng tôi thậm chí không chạy thử nghiệm đơn vị vào ban đêm vì có rất nhiều tính năng cần thêm và các lỗi cần khắc phục :(
Công việc

1
Đây là loại câu trả lời tôi đã hy vọng ... như tôi đã đề cập trước đây - rõ ràng một tính năng như vậy có ít sử dụng thực tế, nhưng sẽ cung cấp một cách tuyệt vời để tìm hiểu một số kỹ thuật có thể áp dụng cho những thứ khác. (Phân tích ngôn ngữ, v.v.)
Nathan Osman

1
@Job: Sự khôn ngoan chung là nếu bạn không thường xuyên chạy các bài kiểm tra đơn vị, bạn sẽ có nhiều lỗi hơn để khắc phục .
Eric Lippert

Tôi đã biết những gì tôi cần làm về công việc của mình thay vì than vãn ở đây. Tại một số công ty phần mềm, những người đứng đầu không thực sự hiểu sự khác biệt giữa nguyên mẫu và thành phẩm. Rốt cuộc, pixel-khôn thường không có nhiều sự khác biệt. Thật không khôn ngoan khi không bắt đầu với một nguyên mẫu, vì vậy thời gian không bị lãng phí. Nhưng phản ứng khủng khiếp "có vẻ tốt, bao nhiêu ngày để chuyển sản phẩm này vào sản xuất?". Đó là những người sẽ nghi ngờ nếu các kỹ sư nói với họ rằng họ cần dành thời gian cho cơ sở hạ tầng hoặc tái cấu trúc. Tôi thậm chí còn nghe thấy Spolsky không thích nó.
Công việc

10

Điều đầu tiên tôi nghĩ đến là việc chèn dấu chấm phẩy tự động của Javascript . Một tính năng khủng khiếp, khủng khiếp không bao giờ nên đi vào ngôn ngữ.

Điều đó không có nghĩa là nó không thể làm tốt hơn. Nếu nó nhìn về phía trước dòng sau, thì nó có thể đoán đúng hơn về ý định của lập trình viên, nhưng vào cuối ngày, nếu có nhiều cách hợp lệ thì cú pháp có thể đi, nhưng thực sự không có gì thay thế được cho các lập trình viên rõ ràng.


1
Tôi thực sự đồng ý với tính năng chèn dấu hai chấm JavaScript - hoàn toàn vô dụng.
Nathan Osman

7

Tôi nghe có vẻ như nếu một trình biên dịch có thể sửa lỗi cú pháp không chính xác, thì cú pháp đó sẽ được ghi lại bằng ngôn ngữ.

Lý do cho lỗi cú pháp là vì trình phân tích cú pháp không thể tạo cây cú pháp trừu tượng ra khỏi chương trình. Điều này xảy ra khi một mã thông báo không đúng chỗ. Để đoán mã thông báo đó sẽ ở đâu, nếu cần xóa hoặc nếu cần thêm một số mã thông báo khác để sửa lỗi, bạn sẽ cần một số loại máy tính có thể đoán được ý định của lập trình viên. Làm thế nào một máy có thể đoán rằng:

int x = 5 6;

Được cho là:

int x = 5 + 6;

Nó có thể chỉ là một cách dễ dàng được bất kỳ những điều sau đây: 56, 5 - 6, 5 & 6. Không có cách nào để một trình biên dịch biết.

Công nghệ đó chưa tồn tại.


1
Công nghệ như vậy không thể tồn tại. Tâm trí không được phép đọc; tất cả các hướng dẫn phải rõ ràng đến từ mã.
Công việc

Đúng, nhưng điều tôi thực sự muốn nói là "Có trình biên dịch nào cố sửa lỗi cú pháp không hợp lệ bằng cách đoán dựa trên ngữ cảnh không." Thực tế là trình biên dịch sửa cú pháp không hợp lệ không làm cho cú pháp hợp lệ. Ngoài ra, tôi nhận ra rằng một công cụ như vậy sẽ vô dụng để phát triển mã.
Nathan Osman

6

Mặc dù không hoàn toàn giống như vậy, đây là lý do tại sao HTML biến thành thảm họa. Các trình duyệt chấp nhận đánh dấu xấu và điều tiếp theo bạn biết, trình duyệt A không thể hiển thị giống như Trình duyệt B đã làm (vâng, có một số lý do khác, nhưng đây là một trong những lý do hàng đầu, khoảng 10 năm trước khi một số quy tắc nới lỏng trở thành quy ước ).

Khi Eric Lippert xâm nhập, nhiều thứ trong số này được IDE xử lý tốt nhất chứ không phải trình biên dịch. Điều đó cho phép bạn xem những gì các bit tự động đang cố gắng làm hỏng cho bạn.

Chiến lược tôi nghĩ hiện đang chiếm ưu thế là tinh chỉnh ngôn ngữ liên tục thay vì nới lỏng trình biên dịch: Nếu đó thực sự là thứ mà trình biên dịch có thể tự động tìm ra, thì hãy giới thiệu một cấu trúc ngôn ngữ được xác định rõ xung quanh nó.

Ví dụ ngay lập tức xuất hiện là các thuộc tính tự động trong C # (không phải ngôn ngữ duy nhất có thứ gì đó tương tự): Cho rằng phần lớn các getters / setters trong bất kỳ ứng dụng nào thực sự chỉ là các hàm bao quanh một trường, chỉ cho phép nhà phát triển chỉ ra ý định và để cho trình biên dịch tiêm phần còn lại.

Điều đó sau đó khiến tôi suy nghĩ: Hầu hết các ngôn ngữ kiểu C đã làm điều này ở một mức độ nào đó. Đối với những thứ có thể được tìm ra tự động, chỉ cần tinh chỉnh cú pháp:

 if (true == x)
 {
    dothis();
 }
 else
 {
    dothat();
 }

Có thể rút gọn thành:

if (true == x)
    dothis();
else
    dothat();

Cuối cùng, tôi nghĩ rằng điều này dẫn đến điều này: Xu hướng là bạn không làm cho trình biên dịch "thông minh hơn" hoặc "lỏng hơn". Đó là ngôn ngữ được làm cho thông minh hơn hoặc lỏng hơn.

Bên cạnh đó, quá nhiều "trợ giúp" có thể nguy hiểm, chẳng hạn như lỗi "nếu" cổ điển:

if (true == x)
    if (true == y)
       dothis();
else
    dothat();

Cần lưu ý rằng XHTML đã cung cấp giải pháp cho mớ hỗn độn mà các thông số kỹ thuật kém của HTML đã tạo.
Nathan Osman

2
if (x && y) dothis(); else dothat();sẽ nhìn tốt hơn một chút.
Công việc

1
Một con mèo chết mỗi khi ai đó so sánh với truehoặc false.
JensG

2

Khi tôi mã hóa FORTRAN và PL / I vào cuối những năm 80 và đầu thập niên 90 trên các hệ thống máy tính và máy tính lớn của DEC và IBM, tôi dường như nhớ các trình biên dịch sẽ thường xuyên đăng xuất các thông báo như "lỗi blah blah, giả sử blah blah và tiếp tục .. . ". Trước đó, đây là một di sản của những ngày (thậm chí trước đó, trước thời gian của tôi) xử lý hàng loạt và thẻ đục lỗ khi có khả năng rất lớn giữa việc gửi mã của bạn để chạy và lấy lại kết quả. Vì vậy, nó rất có ý nghĩa đối với các trình biên dịch để cố gắng đoán thứ hai lập trình viên và tiếp tục thay vì hủy bỏ sai lầm đầu tiên gặp phải. Nhắc bạn, tôi không nhớ "chỉnh sửa" là đặc biệt tinh vi. Cuối cùng khi tôi chuyển sang các máy trạm Unix tương tác (Sun, SGI, v.v.),


2
Những trình biên dịch đó sẽ tiếp tục, nhưng chúng sẽ tiếp tục CHỈ với mục đích cố gắng tìm thêm lỗi, vì vậy bạn có thể (có khả năng) sửa một số thứ trước khi gửi lại. Các PC hiện đại đủ nhanh để trình biên dịch "tương tác" dừng lại ở lỗi cú pháp đầu tiên và đưa bạn vào trình chỉnh sửa. (Và trên thực tế, Turbo Pascal ban đầu, vào đầu những năm 1980, hoạt động chính xác theo cách đó. Thật tuyệt.)
John R. Strohm

1
Có, tôi nhớ trình biên dịch tối ưu hóa PL / I của IBM đôi khi sẽ cung cấp các câu lệnh BEGIN và END bị thiếu, ISTR nó cũng sẽ cung cấp các dấu chấm phẩy bị thiếu.
TMN

1

Mục tiêu của trình biên dịch là tạo ra các tệp thực thi hoạt động như mong muốn. Nếu một lập trình viên viết một cái gì đó không hợp lệ, ngay cả khi trình biên dịch có thể xác suất 90% đoán được ý định, thì tốt hơn là yêu cầu lập trình viên sửa chương trình để làm rõ ý định, hơn là trình biên dịch đi trước và tạo ra một thực thi trong đó sẽ có một cơ hội đáng kể để che giấu một lỗi.

Tất nhiên, các ngôn ngữ nói chung nên được thiết kế sao cho mã thể hiện rõ ràng ý định sẽ hợp pháp và mã không thể hiện rõ ràng ý định nên bị cấm, nhưng điều đó không có nghĩa là chúng có nghĩa. Hãy xem xét đoạn mã sau [Java hoặc C #]

const double oneTenth = 0.1;
const float  oneTenthF = 0.1f;
...
float f1 = oneTenth;
double d1 = oneTenthF;

Có một trình biên dịch thêm một kiểu chữ ngầm cho phép gán f1sẽ hữu ích, vì chỉ có một điều logic mà lập trình viên có thể muốn f1chứa ( floatgiá trị gần nhất với 1/10). Tuy nhiên, thay vì khuyến khích các trình biên dịch chấp nhận các chương trình không phù hợp, sẽ tốt hơn cho thông số kỹ thuật cho phép chuyển đổi hai lần ẩn thành ẩn trong một số ngữ cảnh. Mặt khác, việc gán cho d1có thể hoặc không phải là những gì lập trình viên thực sự có ý định, nhưng không có quy tắc ngôn ngữ nào cấm nó.

Các loại quy tắc ngôn ngữ tồi tệ nhất là những quy tắc mà trình biên dịch sẽ suy luận trong trường hợp thứ gì đó không thể biên dịch hợp pháp theo cách khác, nhưng khi một chương trình có thể "vô tình" có hiệu lực trong trường hợp có ý định suy luận. Nhiều tình huống liên quan đến kết thúc ngầm định thuộc loại này. Nếu một lập trình viên có ý định viết hai câu lệnh riêng biệt bỏ qua dấu kết thúc câu lệnh, trình biên dịch thường có thể quản lý để suy ra ranh giới câu lệnh, nhưng đôi khi có thể coi đó là một câu lệnh được coi là hai câu lệnh.


0

Lỗi cú pháp đặc biệt khó sửa. Lấy trường hợp của một quyền bị thiếu ): Chúng tôi biết chúng tôi có thể sửa mã bằng cách chèn một mã, nhưng thường có nhiều nơi chúng tôi có thể chèn một mã và có được một chương trình đúng về mặt cú pháp.

Một điểm dễ dàng hơn nhiều là các định danh sai chính tả (nhưng lưu ý đây không phải là lỗi cú pháp). Người ta có thể tính khoảng cách chỉnh sửa giữa số nhận dạng không thể giải quyết và tất cả các số nhận dạng trong phạm vi, và bằng cách thay thế từ không thể giải quyết bằng từ mà người dùng có thể có nghĩa là, người ta sẽ đưa ra một chương trình chính xác trong nhiều trường hợp. Tuy nhiên, hóa ra vẫn tốt hơn là gắn cờ lỗi và để IDE đề xuất thay thế hợp lệ.


-1

Một trình biên dịch như vậy đơn giản sẽ là một triển khai thoải mái, không chuẩn của bất kỳ ngôn ngữ nào mà nó biên dịch.


-2

Nó đã được thử nhiều lần, nhưng thường thì nó không đạt được hiệu quả mong muốn: nghĩ HAL 9000 hoặc GlaDOS.


-3

Trong C, bạn không thể truyền mảng theo giá trị, tuy nhiên trình biên dịch cho phép bạn viết:

void foo(int array[10]);

mà sau đó âm thầm viết lại như sau:

void foo(int* array);

Thật là ngu ngốc? Tôi thích một lỗi cứng ở đây thay vì viết lại một cách im lặng, bởi vì quy tắc đặc biệt này đã khiến nhiều lập trình viên tin rằng các mảng và con trỏ về cơ bản là giống nhau. Họ không phải.

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.