Có thể tạo một trình thông dịch khởi động và không phụ thuộc vào phiên bản gốc của Windows không?


21

Theo Wikipedia, thuật ngữ "bootstrapping" trong bối cảnh viết trình biên dịch có nghĩa là :

Trong khoa học máy tính, bootstrapping là quá trình viết một trình biên dịch (hoặc trình biên dịch mã) bằng ngôn ngữ lập trình nguồn mà nó dự định biên dịch. Áp dụng kỹ thuật này dẫn đến một trình biên dịch tự lưu trữ.

Và tôi có thể hiểu làm thế nào điều đó sẽ làm việc. Tuy nhiên, câu chuyện có vẻ hơi khác đối với người phiên dịch. Bây giờ, tất nhiên, có thể viết một trình thông dịch tự lưu trữ. Đó không phải là những gì tôi đang hỏi. Điều tôi thực sự hỏi là: Có thể làm cho trình thông dịch tự lưu trữ độc lập với trình thông dịch gốc, phiên dịch đầu tiên . Để giải thích những gì tôi muốn nói, hãy xem xét ví dụ này:

Bạn viết phiên bản phiên dịch đầu tiên của bạn trong ngôn ngữ X , và người diễn giải cho một ngôn ngữ mới, bạn đang tạo ra, được gọi là Y . Trước tiên, bạn sử dụng trình biên dịch của ngôn ngữ X để tạo tệp thực thi. Bây giờ bạn có thể giải thích các file viết bằng ngôn ngữ mới của bạn Y sử dụng người phiên dịch viết bằng ngôn ngữ X .

Bây giờ, theo như tôi hiểu, để có thể "bootstrap" người phiên dịch bạn đã viết trong ngôn ngữ X , bạn cần phải viết lại các thông dịch viên bằng ngôn ngữ Y . Nhưng đây là nhược điểm: ngay cả khi bạn viết lại toàn bộ thông dịch viên bằng ngôn ngữ Y , bạn vẫn sẽ cần bản gốc thông dịch viên bạn đã viết trong ngôn ngữ X . Bởi vì để chạy trình thông dịch bằng ngôn ngữ Y , bạn sẽ phải giải thích các tệp nguồn. Nhưng chính xác những gì sẽ diễn giải các tập tin nguồn? Chà, dĩ ​​nhiên không có gì, vì vậy bạn buộc phải vẫn sử dụng trình thông dịch đầu tiên.

Cho dù bạn có viết bao nhiêu trình thông dịch mới bằng ngôn ngữ Y , bạn sẽ luôn phải sử dụng trình thông dịch đầu tiên được viết bằng X để phiên dịch các thông dịch viên tiếp theo. Đây dường như là một vấn đề đơn giản vì bản chất của phiên dịch viên.

Tuy nhiên , về mặt trái, bài viết Wikipedia này về phiên dịch viên thực sự nói về phiên dịch viên tự lưu trữ . Đây là một đoạn trích nhỏ có liên quan:

Trình thông dịch tự là một trình thông dịch ngôn ngữ lập trình được viết bằng ngôn ngữ lập trình có thể tự phiên dịch; một ví dụ là một thông dịch viên BASIC được viết bằng BASIC. Tự phiên dịch có liên quan đến trình biên dịch tự lưu trữ.

Nếu không có trình biên dịch tồn tại cho ngôn ngữ được diễn giải, việc tạo trình thông dịch tự yêu cầu thực hiện ngôn ngữ bằng ngôn ngữ máy chủ (có thể là ngôn ngữ lập trình hoặc trình biên dịch khác). Bằng cách có một trình thông dịch đầu tiên như thế này, hệ thống được khởi động và các phiên bản mới của trình thông dịch có thể được phát triển bằng chính ngôn ngữ

Nó vẫn chưa rõ ràng với tôi, làm thế nào chính xác điều này sẽ được thực hiện. Dường như không có vấn đề gì, bạn sẽ luôn bị buộc phải sử dụng phiên bản đầu tiên của trình thông dịch được viết bằng ngôn ngữ máy chủ.

Bây giờ bài viết được đề cập ở trên liên kết đến một bài viết khác trong đó Wikipedia đưa ra một số ví dụ về các phiên dịch viên tự lưu trữ . Tuy nhiên, khi kiểm tra kỹ hơn, có vẻ như phần "phiên dịch" chính của nhiều trình thông dịch tự lưu trữ (đặc biệt là một số phiên dịch phổ biến hơn như PyPy hoặc Rubinius) thực sự được viết bằng các ngôn ngữ khác như C ++ hoặc C.

Vì vậy, những gì tôi mô tả ở trên có thể? Một thông dịch viên tự lưu trữ có thể độc lập với máy chủ ban đầu của nó? Nếu vậy, làm thế nào chính xác điều này sẽ được thực hiện?

Câu trả lời:


24

Câu trả lời ngắn gọn là: bạn đúng trong sự nghi ngờ của mình, bạn luôn cần một trình thông dịch khác được viết bằng X hoặc trình biên dịch từ Y sang một số ngôn ngữ khác mà bạn đã có trình thông dịch. Thông dịch viên thực thi, trình biên dịch chỉ dịch từ ngôn ngữ này sang ngôn ngữ khác, tại một số điểm trong hệ thống của bạn, phải có một trình thông dịch, ngay cả khi đó chỉ là CPU.

Cho dù bạn có viết bao nhiêu trình thông dịch mới bằng ngôn ngữ Y , bạn sẽ luôn phải sử dụng trình thông dịch đầu tiên được viết bằng X để phiên dịch các thông dịch viên tiếp theo. Đây dường như là một vấn đề đơn giản vì bản chất của phiên dịch viên.

Chính xác. Những gì bạn có thể làm là viết một trình biên dịch từ Y đến X (hoặc một ngôn ngữ khác mà bạn có một thông dịch viên), và bạn thậm chí có thể làm điều đó trong Y . Sau đó, bạn có thể chạy trình biên dịch Y được viết bằng Y trên trình thông dịch Y viết bằng X (hoặc trên trình thông dịch Y được viết bằng Y chạy trên trình thông dịch Y viết bằng X hoặc trên trình thông dịch Y viết bằng Y chạy trên trình thông dịch Y viết bằng Y chạy trên Ytrình thông dịch được viết bằng X , hoặc quảng cáo infinitum) để biên dịch trình thông dịch Y của bạn được viết bằng Y thành X , để sau đó bạn có thể thực hiện nó trên trình thông dịch X. Bằng cách đó, bạn đã thoát khỏi trình thông dịch Y được viết bằng X , nhưng bây giờ bạn cần trình thông dịch X (mặc dù chúng tôi biết rằng chúng tôi đã có một trình thông dịch X , vì nếu không, chúng tôi không thể chạy trình thông dịch X được viết bằng Y ) bạn trước tiên phải viết một trình biên dịch Y -to - X .

Tuy nhiên , về mặt trái, bài viết Wikipedia về phiên dịch viên thực sự nói về phiên dịch viên tự lưu trữ. Đây là một đoạn trích nhỏ có liên quan:

Trình thông dịch tự là một trình thông dịch ngôn ngữ lập trình được viết bằng ngôn ngữ lập trình có thể tự phiên dịch; một ví dụ là một thông dịch viên BASIC được viết bằng BASIC. Tự phiên dịch có liên quan đến trình biên dịch tự lưu trữ.

Nếu không có trình biên dịch tồn tại cho ngôn ngữ được diễn giải, việc tạo trình thông dịch tự yêu cầu thực hiện ngôn ngữ bằng ngôn ngữ máy chủ (có thể là ngôn ngữ lập trình hoặc trình biên dịch khác). Bằng cách có một trình thông dịch đầu tiên như thế này, hệ thống được khởi động và các phiên bản mới của trình thông dịch có thể được phát triển bằng chính ngôn ngữ

Nó vẫn chưa rõ ràng với tôi, làm thế nào chính xác điều này sẽ được thực hiện. Dường như không có vấn đề gì, bạn sẽ luôn bị buộc phải sử dụng phiên bản đầu tiên của trình thông dịch được viết bằng ngôn ngữ máy chủ.

Chính xác. Lưu ý rằng bài viết Wikipedia nói rõ ràng rằng bạn cần triển khai ngôn ngữ thứ hai và không nói rằng bạn có thể thoát khỏi ngôn ngữ thứ nhất.

Bây giờ bài viết được đề cập ở trên liên kết đến một bài viết khác trong đó Wikipedia đưa ra một số ví dụ về các phiên dịch viên tự lưu trữ. Tuy nhiên, khi kiểm tra kỹ hơn, có vẻ như phần "phiên dịch" chính của nhiều trình thông dịch tự lưu trữ (đặc biệt là một số phiên dịch phổ biến hơn như PyPy hoặc Rubinius) thực sự được viết bằng các ngôn ngữ khác như C ++ hoặc C.

Một lần nữa, chính xác. Đó là những ví dụ thực sự tồi tệ. Lấy Rubinius, ví dụ. Đúng, đúng là phần Ruby của Rubinius là tự lưu trữ, nhưng nó là một trình biên dịch, không phải là trình thông dịch: nó biên dịch thành mã nguồn Ruby thành mã byte Rubinius. Phần thông dịch OTOH không tự lưu trữ: nó thông dịch mã Rubinius, nhưng nó được viết bằng C ++. Vì vậy, gọi Rubinius là "trình thông dịch tự lưu trữ" là sai: phần tự lưu trữ không phải là trình thông dịch và phần phiên dịch không tự lưu trữ .

PyPy tương tự, nhưng thậm chí còn không chính xác hơn: nó thậm chí không được viết bằng Python ở nơi đầu tiên, nó được viết bằng RPython, một ngôn ngữ khác. Nó về mặt cú pháp tương tự như Python, về mặt ngữ nghĩa là một "tập hợp con mở rộng", nhưng thực ra nó là một ngôn ngữ được gõ tĩnh gần như ở cùng mức độ trừu tượng như Java và triển khai của nó là một trình biên dịch có nhiều phụ trợ để biên dịch RPython thành mã nguồn C, ECMAScript mã nguồn, mã byte CIL, mã byte JVM hoặc mã nguồn Python.

Vì vậy, những gì tôi mô tả ở trên có thể? Một thông dịch viên tự lưu trữ có thể độc lập với máy chủ ban đầu của nó? Nếu vậy, làm thế nào chính xác điều này sẽ được thực hiện?

Không, không phải của riêng mình. Bạn cần phải giữ trình thông dịch gốc hoặc viết trình biên dịch và biên dịch trình thông dịch tự của bạn.

được một số meta-tròn máy ảo, chẳng hạn như Klein (viết bằng Tự ) và Maxine (viết bằng Java). Tuy nhiên, lưu ý rằng ở đây định nghĩa của "meta-tròn" vẫn khác: các VM này không được viết bằng ngôn ngữ mà chúng thực thi: Klein thực thi Self bytecode nhưng được viết bằng Self, Maxine thực thi JVM bytecode nhưng được viết bằng Java. Tuy nhiên, mã nguồn Self / Java của VM thực sự được biên dịch thành mã byte Self / JVM và sau đó được VM thực thi, do đó, khi VM được thực thi, nó sẽ ở ngôn ngữ mà nó thực thi. Phù.

Cũng lưu ý rằng điều này khác với các máy ảo như SqueakVMJike RVM . Jike được viết bằng Java và SqueakVM được viết bằng tiếng lóng (một tập hợp cú pháp và ngữ nghĩa được gõ tĩnh của Smalltalk gần như ở cùng mức độ trừu tượng như một trình biên dịch cấp cao) và cả hai đều được biên dịch tĩnh thành mã gốc trước khi chúng được chạy. Họ không chạy trong chính mình. Tuy nhiên, bạn có thể tự chạy chúng trên đầu (hoặc trên đầu máy ảo / JVM nhỏ khác). Nhưng đó không phải là "siêu vòng tròn" theo nghĩa này.

Maxine và Klein, OTOH làmchạy bên trong chính mình; họ thực thi mã byte riêng bằng cách sử dụng triển khai riêng của họ. Đây thực sự là tâm trí! Nó cho phép một số cơ hội tối ưu hóa thú vị, ví dụ vì VM tự thực thi cùng với chương trình người dùng, nó có thể gọi nội tuyến từ chương trình người dùng đến VM và ngược lại, ví dụ như gọi đến bộ thu gom rác hoặc bộ cấp phát bộ nhớ có thể được đưa vào người dùng mã và các cuộc gọi lại phản chiếu trong mã người dùng có thể được nhập vào VM. Ngoài ra, tất cả các thủ thuật tối ưu hóa thông minh mà các máy ảo hiện đại thực hiện, trong đó chúng xem chương trình thực thi và tối ưu hóa nó tùy thuộc vào khối lượng công việc và dữ liệu thực tế, VM có thể áp dụng các thủ thuật tương tự cho chính nó trong khi nó đang thực thi chương trình người dùng trong khi chương trình người dùng đang thực hiện khối lượng công việc cụ thể. Nói cách khác, VM rất chuyên môn hóa cho điều đóchương trình cụ thể chạy khối lượng công việc cụ thể.

Tuy nhiên, lưu ý rằng tôi đã bỏ qua việc sử dụng từ "thông dịch viên" ở trên và luôn luôn sử dụng "thực thi"? Chà, những VM đó không được xây dựng xung quanh các trình thông dịch, chúng được xây dựng xung quanh các trình biên dịch (JIT). Sau đó, có một trình thông dịch được thêm vào Maxine, nhưng bạn luôn cần trình biên dịch: bạn phải chạy VM một lần trên một VM khác (ví dụ: Oracle HotSpot trong trường hợp Maxine), để VM có thể tự biên dịch. Trong trường hợp của Maxine, JIT sẽ biên dịch pha khởi động của chính nó, sau đó tuần tự hóa mã gốc đã biên dịch thành hình ảnh VM bootstrap và dán một bộ tải khởi động rất đơn giản ở phía trước (thành phần duy nhất của VM được viết bằng C, mặc dù đó chỉ là để thuận tiện , nó cũng có thể có trong Java). Bây giờ bạn có thể sử dụng Maxine để thực thi chính nó.


Diệp . Tôi không bao giờ biết thế giới của các thông dịch viên tự lưu trữ là rất dính! Cảm ơn đã cho một cái nhìn tổng quan tốt đẹp mặc dù.
Christian Dean

1
Haha, tại sao thế giới nên ít suy nghĩ hơn so với khái niệm này? ;-)
Jörg W Mittag

3
Tôi đoán một trong những vấn đề là mọi người thường chơi nhanh và lỏng lẻo với các ngôn ngữ liên quan. Ví dụ, Rubinius thường được gọi là "Ruby in Ruby", nhưng đó chỉ là một nửa câu chuyện. Đúng, nói đúng ra , trình biên dịch Ruby trong Rubinius được viết bằng Ruby, nhưng VM thực thi mã byte thì không. Và thậm chí tệ hơn: PyPy thường được gọi là "Python trong Python", ngoại trừ thực tế không có một dòng Python nào trong đó. Toàn bộ điều được viết bằng RPython, được thiết kế quen thuộc với các lập trình viên Python, nhưng không phải là Python . Tương tự như vậy SqueakVM: nó không được viết bằng Smalltalk, nó có thể
Jörg W Mittag

Bài được viết bằng tiếng lóng, mà theo những người đã thực sự mã hóa trong nó, thậm chí còn tệ hơn C về khả năng trừu tượng hóa của nó. Ưu điểm duy nhất mà Slang có, đó là một tập hợp con của Smalltalk thích hợp, có nghĩa là bạn có thể phát triển nó (và chạy và quan trọng nhất là gỡ lỗi VM trên) một IDE Smalltalk mạnh mẽ.
Jörg W Mittag

2
Chỉ cần thêm một sự phức tạp khác: Một số ngôn ngữ được giải thích (ví dụ FORTH và có thể là TeX) có khả năng ghi hình ảnh bộ nhớ có thể tải của hệ thống đang chạy, dưới dạng tệp thực thi. Theo nghĩa đó, các hệ thống như vậy sau đó có thể chạy mà không cần trình thông dịch gốc. Ví dụ, tôi đã từng viết một trình thông dịch FORTH bằng cách sử dụng phiên bản FORTH 16 bit để "phiên dịch chéo" phiên bản 32 bit cho một CPU khác và để chạy trên một hệ điều hành khác. (Lưu ý, ngôn ngữ FORTH bao gồm trình biên dịch riêng của nó, do đó, "FORTH VM" (thường chỉ có 10 hoặc 20 hướng dẫn mã máy) có thể được viết bằng chính FORTH.)
alephzero

7

Bạn đã đúng khi lưu ý rằng trình thông dịch tự lưu trữ vẫn yêu cầu trình thông dịch tự chạy và không thể được bootstraged theo nghĩa tương tự như trình biên dịch.

Tuy nhiên, một ngôn ngữ tự lưu trữ không giống như một trình thông dịch tự lưu trữ. Việc xây dựng một trình thông dịch thường dễ hơn so với xây dựng trình biên dịch. Do đó, để triển khai một ngôn ngữ mới, trước tiên chúng tôi có thể triển khai trình thông dịch bằng ngôn ngữ không liên quan. Sau đó, chúng ta có thể sử dụng trình thông dịch đó để phát triển trình biên dịch cho ngôn ngữ của chúng ta. Ngôn ngữ sau đó được tự lưu trữ, vì trình biên dịch được diễn giải. Trình biên dịch sau đó có thể tự biên dịch, và sau đó có thể được coi là bootstrapping hoàn toàn.

Một trường hợp đặc biệt của điều này là thời gian chạy biên dịch JIT tự lưu trữ. Nó có thể bắt đầu với một trình thông dịch bằng ngôn ngữ máy chủ, sau đó sử dụng ngôn ngữ mới để thực hiện biên dịch JIT, sau đó trình biên dịch JIT có thể tự biên dịch. Điều này cảm thấy giống như một trình thông dịch tự lưu trữ, nhưng vượt qua vấn đề thông dịch viên vô hạn. Cách tiếp cận này được sử dụng, nhưng chưa phổ biến lắm.

Một kỹ thuật liên quan khác là một trình thông dịch mở rộng, nơi chúng ta có thể tạo các phần mở rộng bằng ngôn ngữ đang được diễn giải. Ví dụ: chúng tôi có thể triển khai các opcodes mới trong ngôn ngữ. Điều này có thể biến một trình thông dịch chân trần thành một trình thông dịch giàu tính năng, miễn là chúng ta tránh được sự phụ thuộc vòng tròn.

Một trường hợp thực sự xảy ra khá phổ biến là khả năng ngôn ngữ ảnh hưởng đến việc phân tích cú pháp của chính nó, ví dụ như các macro được đánh giá theo thời gian phân tích. Vì ngôn ngữ macro giống như ngôn ngữ đang được xử lý, nên nó có xu hướng giàu tính năng hơn nhiều so với ngôn ngữ macro chuyên dụng hoặc bị hạn chế. Tuy nhiên, thật đúng khi lưu ý rằng ngôn ngữ thực hiện tiện ích mở rộng là ngôn ngữ hơi khác so với ngôn ngữ sau khi mở rộng.

Khi sử dụng các thông dịch viên tự lưu trữ của Real Real, điều này thường được thực hiện vì lý do giáo dục hoặc nghiên cứu. Ví dụ, triển khai trình thông dịch cho Scheme bên trong Scheme là một cách hay để dạy ngôn ngữ lập trình (xem SICP).

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.