Bootstrapping vẫn yêu cầu hỗ trợ bên ngoài


96

Tôi đã nghe về ý tưởng khởi động một ngôn ngữ, nghĩa là viết một trình biên dịch / thông dịch cho ngôn ngữ đó. Tôi đã tự hỏi làm thế nào điều này có thể được thực hiện và nhìn xung quanh một chút, và thấy ai đó nói rằng chỉ có thể làm được

  • viết một trình biên dịch ban đầu bằng một ngôn ngữ khác.
  • viết tay mã hóa trình biên dịch ban đầu trong Assembly, đây có vẻ như là một trường hợp đặc biệt của trình biên dịch đầu tiên

Đối với tôi, cả hai đều không có vẻ thực sự là khởi động một ngôn ngữ theo nghĩa là cả hai đều yêu cầu hỗ trợ từ bên ngoài. Có cách nào để thực sự viết một trình biên dịch bằng ngôn ngữ riêng của nó không?


Tôi không có nhiều kinh nghiệm với những thứ như vậy, nhưng tôi sẽ giả định rằng trình biên dịch ban đầu sẽ phải được viết bằng ngôn ngữ khác. Tôi khá chắc chắn rằng "bootstrapping", ám chỉ đến các trình biên dịch, chỉ cần đề cập đến cách viết một trình biên dịch cho một ngôn ngữ trong ngôn ngữ nó có nghĩa là để biên dịch, không viết là người đầu tiên trình biên dịch cho các ngôn ngữ trong ngôn ngữ nó có nghĩa là để biên dịch.
jdd 17/08/2016

1
Cảm ơn vì thông tin, tất cả mọi người. Khi được giải thích với ý tưởng ban đầu là viết một trình biên dịch giới hạn, sau đó xây dựng trên đó, thì ý tưởng về bootstrapping sẽ có ý nghĩa hơn. Tôi đang tham gia một lớp Biên dịch trong học kỳ này, một quyết định phần lớn bị ảnh hưởng bởi bài đăng của Steve Yegge về tầm quan trọng của một lớp trong Trình biên dịch và tôi vừa mua một bản sao của cuốn sách Dragon từ liên kết Amazon đã bị hạ cấp trên SO trước đó.
pbh101

Câu trả lời:


107

Có cách nào để thực sự viết một trình biên dịch bằng ngôn ngữ riêng của nó không?

Bạn phải có một số ngôn ngữ hiện có để viết trình biên dịch mới của mình. Nếu bạn đang viết một trình biên dịch C ++ mới, bạn chỉ cần viết nó bằng C ++ và biên dịch nó bằng một trình biên dịch hiện có trước. Mặt khác, nếu bạn đang tạo một trình biên dịch cho một ngôn ngữ mới, hãy gọi nó là Yazzleof, trước tiên bạn cần viết trình biên dịch mới bằng một ngôn ngữ khác. Nói chung, đây sẽ là một ngôn ngữ lập trình khác, nhưng nó không nhất thiết phải như vậy. Nó có thể là lắp ráp, hoặc nếu cần, mã máy.

Nếu bạn đang đi để bootstrap một trình biên dịch cho Yazzleof, bạn thường sẽ không viết một trình biên dịch cho toàn bộ ngôn ngữ ban đầu. Thay vào đó, bạn sẽ viết một trình biên dịch cho Yazzle-lite, tập hợp con nhỏ nhất có thể có của Yazzleof (tốt, ít nhất là một tập hợp con khá nhỏ ). Sau đó, trong Yazzle-lite, bạn sẽ viết một trình biên dịch cho ngôn ngữ đầy đủ. (Rõ ràng là điều này có thể xảy ra lặp đi lặp lại thay vì chỉ trong một lần nhảy.) Bởi vì Yazzle-lite là một tập hợp con thích hợp của Yazzleof, bây giờ bạn có một trình biên dịch có thể tự biên dịch.

Có một bài viết thực sự tốt về việc khởi động một trình biên dịch từ mức thấp nhất có thể (mà trên một máy hiện đại về cơ bản là một trình soạn thảo hex), có tiêu đề Bootstrapping một trình biên dịch đơn giản từ hư vô . Nó có thể được tìm thấy tại https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html .


19

Lời giải thích bạn đã đọc là đúng. Có một cuộc thảo luận về vấn đề này trong Trình biên dịch: Nguyên tắc, Kỹ thuật và Công cụ (Sách Rồng):

  • Viết trình biên dịch C1 cho ngôn ngữ X bằng ngôn ngữ Y
  • Sử dụng trình biên dịch C1 để viết trình biên dịch C2 cho ngôn ngữ X bằng ngôn ngữ X
  • Bây giờ C2 là một môi trường tự lưu trữ hoàn toàn.

7

Một cuộc thảo luận siêu thú vị về vấn đề này là trong bài giảng về Giải thưởng Turing của đồng sáng tạo Unix, Ken Thompson .

Anh ấy bắt đầu với:

Những gì tôi sắp mô tả là một trong nhiều vấn đề "con gà và quả trứng" nảy sinh khi các trình biên dịch được viết bằng ngôn ngữ của chúng. Để dễ dàng hơn, tôi sẽ sử dụng một ví dụ cụ thể từ trình biên dịch C.

và tiếp tục cho thấy cách anh ta đã viết một phiên bản của trình biên dịch Unix C luôn cho phép anh ta đăng nhập mà không cần mật khẩu, vì trình biên dịch C sẽ nhận ra chương trình đăng nhập và thêm vào mã đặc biệt.

Mẫu thứ hai nhắm vào trình biên dịch C. Mã thay thế là một chương trình tự tái tạo Giai đoạn I chèn cả hai con ngựa Trojan vào trình biên dịch. Điều này đòi hỏi một giai đoạn học tập như trong ví dụ Giai đoạn II. Đầu tiên, chúng tôi biên dịch mã nguồn đã sửa đổi với trình biên dịch C bình thường để tạo ra một tệp nhị phân bị lỗi. Chúng tôi cài đặt tệp nhị phân này làm tệp C. Bây giờ chúng tôi có thể xóa các lỗi khỏi nguồn của trình biên dịch và tệp nhị phân mới sẽ chèn lại các lỗi bất cứ khi nào nó được biên dịch. Tất nhiên, lệnh đăng nhập sẽ vẫn bị ghi âm mà không có dấu vết nguồn ở bất kỳ đâu.


9
Điều này là lạc đề .. Thú vị, nhưng khó hiểu và không phải là câu trả lời cho câu hỏi.
blueshift

5

Cách tôi đã nghe nói là viết một trình biên dịch cực kỳ hạn chế bằng một ngôn ngữ khác, sau đó sử dụng nó để biên dịch một phiên bản phức tạp hơn, được viết bằng ngôn ngữ mới. Phiên bản thứ hai này sau đó có thể được sử dụng để tự biên dịch và phiên bản tiếp theo. Mỗi khi nó được biên dịch, phiên bản cuối cùng được sử dụng.

Đây là định nghĩa của bootstrapping:

quá trình của một hệ thống đơn giản kích hoạt một hệ thống phức tạp hơn phục vụ cùng một mục đích.

CHỈNH SỬA: Bài viết trên Wikipedia về khởi động trình biên dịch bao hàm khái niệm tốt hơn tôi.



4

Donald E. Knuth thực sự đã xây dựng WEB bằng cách viết trình biên dịch vào đó, sau đó biên dịch thủ công nó thành assembly hoặc mã máy.


3

Theo tôi hiểu, trình thông dịch Lisp đầu tiên được khởi động bằng cách biên dịch thủ công các hàm khởi tạo và trình đọc mã thông báo. Phần còn lại của trình thông dịch sau đó được đọc từ nguồn.

Bạn có thể tự kiểm tra bằng cách đọc các giấy McCarthy gốc, hàm đệ quy của biểu thức tượng trưng và tính toán của họ bằng máy, Phần I .


Điều gì đã xảy ra với phần 2 và 3? ... Làm thế nào mà tôi không nhận thấy rằng @Wing đã đăng điều tương tự trước tôi 3 năm? Tôi là một thằng ngu. Ít nhất tôi đã liên kết bài báo (với sự trợ giúp).
luser droog

2

Một giải pháp thay thế khác là tạo một máy bytecode cho ngôn ngữ của bạn (hoặc sử dụng một máy hiện có nếu các tính năng của nó không quá bất thường) và viết một trình biên dịch sang bytecode, trong bytecode hoặc bằng ngôn ngữ mong muốn của bạn bằng cách sử dụng phương tiện trung gian khác - chẳng hạn như bộ công cụ phân tích cú pháp xuất ra AST dưới dạng XML, sau đó biên dịch XML thành mã bytecode bằng XSLT (hoặc một ngôn ngữ đối sánh mẫu khác và biểu diễn dựa trên cây). Nó không loại bỏ sự phụ thuộc vào một ngôn ngữ khác, nhưng có thể có nghĩa là nhiều công việc khởi động hơn kết thúc trong hệ thống cuối cùng.


2

Đó là phiên bản khoa học máy tính của nghịch lý con gà và quả trứng. Tôi không thể nghĩ ra cách nào để không viết trình biên dịch ban đầu bằng trình hợp dịch hoặc một số ngôn ngữ khác. Nếu nó có thể được thực hiện, tôi nên Lisp đã có thể làm điều đó.

Trên thực tế, tôi nghĩ Lisp gần như đủ điều kiện. Kiểm tra mục nhập Wikipedia của nó . Theo bài báo, hàm eval Lisp có thể được triển khai trên mã máy IBM 704 , với một trình biên dịch hoàn chỉnh (được viết bằng chính Lisp) ra đời vào năm 1962 tại MIT .


2

Mọi ví dụ về khởi động ngôn ngữ mà tôi có thể nghĩ đến ( C , PyPy ) đã được thực hiện sau khi có một trình biên dịch hoạt động. Bạn phải bắt đầu từ đâu đó và việc hoàn thiện lại một ngôn ngữ của chính nó yêu cầu viết một trình biên dịch bằng ngôn ngữ khác trước.

Nó sẽ hoạt động như thế nào khác? Tôi không nghĩ rằng nó thậm chí có thể làm khác về mặt khái niệm.


4
Trình biên dịch Lisp đầu tiên, ít nhất, đã được khởi động bằng cách sử dụng trình thông dịch Lisp hiện có . Vì vậy, không phải ngôn ngữ khác về mặt ngữ nghĩa, mà là cách triển khai ngôn ngữ khác.
Ken

0

Một số trình biên dịch hoặc hệ thống bootstrapped giữ cả biểu mẫu nguồn và biểu mẫu đối tượng trong kho lưu trữ của chúng:

  • ocaml là một ngôn ngữ có cả trình thông dịch bytecode (tức là trình biên dịch sang Ocaml bytecode) và trình biên dịch gốc (sang x86-64 hoặc ARM, v.v.). Kho lưu trữ svn của nó chứa cả mã nguồn (tệp */*.{ml,mli}) và dạng bytecode (tệp boot/ocamlc) của trình biên dịch. Vì vậy, khi bạn xây dựng, đầu tiên nó sử dụng mã bytecode (của phiên bản trước của trình biên dịch) để tự biên dịch. Sau đó, mã bytecode mới được biên dịch có thể biên dịch trình biên dịch gốc. Vì vậy, kho lưu trữ Ocaml svn chứa cả *.ml[i]tệp nguồn và boot/ocamlctệp bytecode.

  • Các gỉ tải trình biên dịch (sử dụng wget, vì vậy bạn cần một kết nối Internet làm việc) một phiên bản trước của hệ nhị phân của nó để biên dịch riêng của mình.

  • MELT là một ngôn ngữ giống như Lisp để tùy chỉnh và mở rộng GCC . Nó được dịch sang mã C ++ bởi một trình dịch khởi động. Mã C ++ được tạo của trình dịch được phân phối, do đó, kho lưu trữ svn chứa cả *.melttệp nguồn và tệp melt/generated/*.cc"đối tượng" của trình dịch.

  • Hệ thống trí tuệ nhân tạo CAIA của J.Pitrat hoàn toàn tự tạo ra. Nó có sẵn dưới dạng tập hợp hàng nghìn [A-Z]*.ctệp được tạo (cũng với dx.htệp tiêu đề được tạo ) với bộ sưu tập hàng nghìn _[0-9]*tệp dữ liệu.

  • Một số trình biên dịch Scheme cũng được khởi động. Scheme48, Chicken Scheme, ...

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.