Tôi đang nghiên cứu CoffeeScript trên trang web http://coffeescript.org/ và nó có văn bản
Trình biên dịch CoffeeScript được viết bằng CoffeeScript
Làm thế nào một trình biên dịch có thể tự biên dịch, hoặc câu lệnh này có ý nghĩa gì?
Tôi đang nghiên cứu CoffeeScript trên trang web http://coffeescript.org/ và nó có văn bản
Trình biên dịch CoffeeScript được viết bằng CoffeeScript
Làm thế nào một trình biên dịch có thể tự biên dịch, hoặc câu lệnh này có ý nghĩa gì?
Câu trả lời:
Phiên bản đầu tiên của trình biên dịch không thể được tạo bằng máy từ ngôn ngữ lập trình dành riêng cho nó; sự nhầm lẫn của bạn là dễ hiểu. Phiên bản mới hơn của trình biên dịch có nhiều tính năng ngôn ngữ hơn (với nguồn được viết lại trong phiên bản đầu tiên của ngôn ngữ mới) có thể được trình biên dịch đầu tiên xây dựng. Phiên bản đó sau đó có thể biên dịch trình biên dịch tiếp theo, v.v. Đây là một ví dụ:
Lưu ý: Tôi không chắc chắn chính xác cách các phiên bản CoffeeScript được đánh số, đó chỉ là một ví dụ.
Quá trình này thường được gọi là bootstrapping . Một ví dụ khác về trình biên dịch bootstrapping là rustc
trình biên dịch cho ngôn ngữ Rust .
Trong bài viết Refl Refl on Trusting Trust , Ken Thompson, một trong những người khởi tạo Unix, viết một cái nhìn tổng quan hấp dẫn (và dễ đọc) về cách trình biên dịch C tự biên dịch. Các khái niệm tương tự có thể được áp dụng cho CoffeeScript hoặc bất kỳ ngôn ngữ nào khác.
Ý tưởng về một trình biên dịch để biên dịch mã riêng của nó là mơ hồ tương tự như một Quine : Mã nguồn đó, khi thực hiện, sản xuất như đầu ra mã nguồn gốc. Đây là một ví dụ về một quine CoffeeScript. Thompson đã đưa ra ví dụ này về một câu hỏi C:
char s[] = {
'\t',
'0',
'\n',
'}',
';',
'\n',
'\n',
'/',
'*',
'\n',
… 213 lines omitted …
0
};
/*
* The string s is a representation of the body
* of this program from '0'
* to the end.
*/
main()
{
int i;
printf("char\ts[] = {\n");
for(i = 0; s[i]; i++)
printf("\t%d,\n", s[i]);
printf("%s", s);
}
Tiếp theo, bạn có thể tự hỏi làm thế nào trình biên dịch được dạy rằng một chuỗi thoát như '\n'
đại diện cho mã ASCII 10. Câu trả lời là ở đâu đó trong trình biên dịch C, có một thói quen diễn giải các ký tự, chứa một số điều kiện như thế này để nhận ra các chuỗi dấu gạch chéo ngược:
…
c = next();
if (c != '\\') return c; /* A normal character */
c = next();
if (c == '\\') return '\\'; /* Two backslashes in the code means one backslash */
if (c == 'r') return '\r'; /* '\r' is a carriage return */
…
Vì vậy, chúng ta có thể thêm một điều kiện vào đoạn mã trên
if (c == 'n') return 10; /* '\n' is a newline */
Để tạo ra một trình biên dịch '\n'
đại diện cho ASCII 10. Thật thú vị, trình biên dịch đó và tất cả các trình biên dịch tiếp theo được biên dịch bởi nó , "biết" ánh xạ đó, vì vậy trong thế hệ tiếp theo của mã nguồn, bạn có thể thay đổi dòng cuối cùng thành
if (c == 'n') return '\n';
Sôi và nó sẽ làm đúng! Xuất 10
phát từ trình biên dịch và không còn cần phải được xác định rõ ràng trong mã nguồn của trình biên dịch. 1
Đó là một ví dụ về tính năng ngôn ngữ C được triển khai trong mã C. Bây giờ, lặp lại quy trình đó cho mọi tính năng ngôn ngữ duy nhất và bạn có trình biên dịch "tự lưu trữ": trình biên dịch C được viết bằng C.
1 Vòng xoắn cốt truyện được mô tả trong bài báo là vì trình biên dịch có thể được "dạy" các sự kiện như thế này, nên cũng có thể bị dạy sai để tạo ra các thực thi trojan theo cách khó phát hiện và hành động phá hoại như vậy có thể tồn tại trong tất cả các trình biên dịch được tạo ra bởi trình biên dịch bị nhiễm độc.
Bạn đã nhận được một câu trả lời rất tốt, tuy nhiên tôi muốn cung cấp cho bạn một quan điểm khác, hy vọng sẽ được khai sáng cho bạn. Trước tiên chúng ta hãy thiết lập hai sự thật mà cả hai chúng ta có thể đồng ý:
Tôi chắc chắn rằng bạn có thể đồng ý rằng cả # 1 và # 2 đều đúng. Bây giờ, hãy nhìn vào hai tuyên bố. Bây giờ bạn có thấy trình biên dịch CoffeeScript hoàn toàn bình thường để có thể biên dịch trình biên dịch CoffeeScript không?
Trình biên dịch không quan tâm những gì nó biên dịch. Miễn là nó là một chương trình được viết bằng CoffeeScript, nó có thể biên dịch nó. Và trình biên dịch CoffeeScript chỉ là một chương trình như vậy. Trình biên dịch CoffeeScript không quan tâm rằng chính trình biên dịch CoffeeScript mà nó đang biên dịch. Tất cả những gì nó nhìn thấy là một số mã CoffeeScript. Giai đoạn = Stage.
Làm thế nào một trình biên dịch có thể tự biên dịch, hoặc câu lệnh này có ý nghĩa gì?
Vâng, đó chính xác là những gì câu nói đó có nghĩa, và tôi hy vọng bạn có thể thấy bây giờ câu nói đó đúng như thế nào.
Làm thế nào một trình biên dịch có thể tự biên dịch, hoặc câu lệnh này có ý nghĩa gì?
Nó có nghĩa chính xác đó. Trước hết, một số điều cần xem xét. Có bốn đối tượng chúng ta cần xem xét:
Bây giờ, rõ ràng là bạn có thể sử dụng tập hợp được tạo - tệp thực thi - của trình biên dịch CoffeScript để biên dịch bất kỳ chương trình CoffeScript tùy ý nào và tạo tập hợp cho chương trình đó.
Bây giờ, trình biên dịch CoffeScript tự nó chỉ là một chương trình CoffeScript tùy ý, và do đó, nó có thể được biên dịch bởi trình biên dịch CoffeScript.
Dường như sự nhầm lẫn của bạn bắt nguồn từ thực tế là khi bạn tạo ngôn ngữ mới của riêng mình, bạn chưa có trình biên dịch nhưng bạn có thể sử dụng để biên dịch trình biên dịch của mình. Điều này chắc chắn trông giống như một vấn đề trứng gà , phải không?
Giới thiệu quá trình gọi là bootstrapping .
Bây giờ bạn cần thêm các tính năng mới. Giả sử bạn chỉ thực hiện while
-loops, nhưng cũng muốn for
-loops. Đây không phải là một vấn đề, vì bạn có thể viết lại bất kỳ for
-loop theo cách mà nó là một while
-loop. Điều này có nghĩa là bạn chỉ có thể sử dụng while
-loop trong mã nguồn của trình biên dịch của mình, vì phần lắp ráp bạn có trong tay chỉ có thể biên dịch chúng. Nhưng bạn có thể tạo các hàm bên trong trình biên dịch có thể tạo và biên dịch for
-loop với nó. Sau đó, bạn sử dụng hội đồng bạn đã có và biên dịch phiên bản trình biên dịch mới. Và bây giờ bạn có một tập hợp của một trình biên dịch cũng có thể phân tích cú pháp và biên dịch for
-loops! Bây giờ bạn có thể quay lại tệp nguồn của trình biên dịch của mình và viết lại bất kỳ while
-loops nào bạn không muốn vào for
-loops.
Rửa sạch và lặp lại cho đến khi tất cả các tính năng ngôn ngữ mong muốn có thể được biên dịch bằng trình biên dịch.
while
và for
rõ ràng chỉ là ví dụ, nhưng điều này hoạt động cho bất kỳ tính năng ngôn ngữ mới nào bạn muốn. Và sau đó bạn đang ở trong tình huống CoffeScript hiện tại: Trình biên dịch tự biên dịch.
Có nhiều tài liệu ngoài kia. Phản ánh về niềm tin Tin tưởng là một tác phẩm kinh điển mà mọi người quan tâm đến chủ đề đó nên đọc ít nhất một lần.
Ở đây thuật ngữ trình biên dịch nhấn mạnh đến thực tế là có hai tệp liên quan. Một là một tệp thực thi, lấy các tệp đầu vào được viết bằng CoffeScript và tạo ra như tệp đầu ra của nó một tệp thực thi khác, tệp đối tượng có thể liên kết hoặc thư viện dùng chung. Cái còn lại là một tệp nguồn CoffeeScript chỉ xảy ra để mô tả quy trình biên dịch CoffeeScript.
Bạn áp dụng tệp thứ nhất cho tệp thứ hai, tạo tệp thứ ba có khả năng thực hiện cùng một hành động biên dịch như tệp thứ nhất (có thể nhiều hơn, nếu tệp thứ hai xác định các tính năng không được triển khai trước) và do đó có thể thay thế tệp đầu tiên nếu bạn mong muốn như vậy.
Do phiên bản Ruby của trình biên dịch CoffeeScript đã tồn tại, nên nó được sử dụng để tạo phiên bản CoffeeScript của trình biên dịch CoffeeScript.
Điều này được biết đến như là một trình biên dịch tự lưu trữ .
Nó cực kỳ phổ biến và thường xuất phát từ mong muốn của tác giả sử dụng ngôn ngữ của chính họ để duy trì sự phát triển của ngôn ngữ đó.
Đây không phải là vấn đề của trình biên dịch ở đây, mà là vấn đề về tính biểu cảm của ngôn ngữ, vì trình biên dịch chỉ là một chương trình được viết bằng một số ngôn ngữ.
Khi chúng tôi nói rằng "một ngôn ngữ được viết / triển khai", chúng tôi thực sự có nghĩa là trình biên dịch hoặc trình thông dịch cho ngôn ngữ đó được triển khai. Có các ngôn ngữ lập trình trong đó bạn có thể viết các chương trình thực hiện ngôn ngữ (là trình biên dịch / trình thông dịch cho cùng một ngôn ngữ). Những ngôn ngữ này được gọi là ngôn ngữ phổ quát .
Để có thể hiểu điều này, hãy nghĩ về một máy tiện kim loại. Nó là một công cụ được sử dụng để định hình kim loại. Có thể, chỉ sử dụng công cụ đó, để tạo một công cụ khác, giống hệt nhau, bằng cách tạo các phần của nó. Do đó, công cụ đó là một cỗ máy vạn năng. Tất nhiên, cái đầu tiên được tạo ra bằng các phương tiện khác (các công cụ khác) và có lẽ có chất lượng thấp hơn. Nhưng cái đầu tiên được sử dụng để chế tạo những cái mới với độ chính xác cao hơn.
Một máy in 3D gần như là một cỗ máy vạn năng. Bạn có thể in toàn bộ máy in 3D bằng máy in 3D (bạn không thể tạo mẹo làm nóng chảy nhựa).
Phiên bản thứ n + 1 của trình biên dịch được viết bằng X.
Do đó, nó có thể được biên dịch bởi phiên bản thứ n của trình biên dịch (cũng được viết bằng X).
Nhưng phiên bản đầu tiên của trình biên dịch được viết bằng X phải được biên dịch bởi trình biên dịch cho X được viết bằng ngôn ngữ khác X. Bước này được gọi là bootstrapping trình biên dịch.
Trình biên dịch lấy một đặc tả cấp cao và biến nó thành một triển khai cấp thấp, chẳng hạn như có thể được thực thi trên phần cứng. Do đó, không có mối quan hệ giữa định dạng của đặc tả và thực thi thực tế bên cạnh ngữ nghĩa của ngôn ngữ được nhắm mục tiêu.
Trình biên dịch chéo chuyển từ hệ thống này sang hệ thống khác, trình biên dịch ngôn ngữ chéo biên dịch một đặc tả ngôn ngữ thành một đặc tả ngôn ngữ khác.
Về cơ bản biên dịch là một bản dịch đơn thuần, và cấp độ thường là cấp độ ngôn ngữ cao hơn đến cấp độ ngôn ngữ thấp hơn, nhưng có nhiều biến thể.
Tất nhiên, trình biên dịch bootstrapping khó hiểu nhất vì chúng biên dịch ngôn ngữ mà chúng được viết. Đừng quên bước đầu tiên trong bootstrapping đòi hỏi ít nhất một phiên bản hiện có tối thiểu có thể thực thi được. Nhiều trình biên dịch bootstrapping hoạt động trên các tính năng tối thiểu của ngôn ngữ lập trình trước tiên và thêm các tính năng ngôn ngữ phức tạp bổ sung trong tương lai miễn là tính năng mới có thể được thể hiện bằng các tính năng trước đó. Nếu đó không phải là trường hợp, nó sẽ yêu cầu phải có một phần của "trình biên dịch" được phát triển bằng ngôn ngữ khác.
self-hosting
trình biên dịch. Xem lập trình