Quy tắc chung để viết trình biên dịch X thành Z trong Y


9

Giả sử X là ngôn ngữ đầu vào, Z là ngôn ngữ đầu ra, sau đó f là trình biên dịch, được viết bằng ngôn ngữ Y.

f = X -> Z

Vì f chỉ là một chương trình, tôi nghĩ Y có thể là bất kỳ ngôn ngữ nào, phải không? Vì vậy, chúng ta có thể có các trình biên dịch F1, f2, mỗi trình biên dịch bằng Y1, Y2.

f1 = f Y1    
f2 = f Y2

g = Z -> M
h = g . f    # We get a compiler X -> M

Lấy trình biên dịch cpython làm ví dụ, X là Python, Z là mã VM Python, Y là C.

cpython = Python -> PythonVMCode C
interpreter = PythonVMCode -> Nothing
interpreter2 = PythonVMCode -> MachineCode

Các nguồn Python được biên dịch thành mã Python VM, các tệp .pyc, sau đó được phiên dịch bởi trình thông dịch. Có vẻ như có thể tồn tại một trình biên dịch có thể trực tiếp làm Python -> MachineCode, mặc dù rất khó thực hiện:

   hardpython = interpreter2 . cpython 

Chúng ta cũng có thể viết một trình biên dịch khác thực hiện công việc Python -> PythonVMCode, bằng ngôn ngữ khác, nói chính Python.

mypython = Python -> PythonVMCode Python
mypython2 = Python -> PythonVMCode Ruby

Bây giờ, đây là ví dụ phức tạp PyPy. Tôi chỉ là người mới của PyPy, hãy sửa tôi nếu tôi sai:

Tài liệu PyPy http://doc.pypy.org/en/latest/arch architecture.html #pypy-the-translation-framework

Mục tiêu của chúng tôi là cung cấp một giải pháp khả thi cho vấn đề của những người thực hiện ngôn ngữ: phải viết trình thông dịch l * o * p cho các ngôn ngữ động và nền tảng p với các quyết định thiết kế quan trọng.

Chúng ta có thể nghĩ l là X, p là Y. Tồn tại một chương trình dịch tất cả các chương trình RPython sang C:

 rpython_compiler = RPython -> C  Python

 pypy = Python -> Nothing RPython

 translate = compile the program pypy written in RPython using rpython_compiler

 py2rpy = Python -> RPython  Python
 py2c = Python -> C Python 
 py2c = rpython_compiler . py2rpy

Các chương trình RPython giống như các hướng dẫn VM, rpython_compiler là VM.

q1. pypy là trình thông dịch, một chương trình RPython có thể diễn giải mã Python, không có ngôn ngữ đầu ra, vì vậy chúng ta không thể coi nó là một trình biên dịch, phải không?

Thêm:

  • Tôi chỉ thấy rằng ngay cả sau khi dịch, pypy vẫn là một thông dịch viên, chỉ lần này được viết bằng C.
  • Nếu chúng ta nhìn sâu vào pypy trình thông dịch, tôi tin rằng phải tồn tại một loại trình biên dịch nào đó, nó biên dịch các nguồn Python thành một số AST, sau đó thực thi

như thế này:

compiler_inside_pypy = Python -> AST_or_so

q2. Trình biên dịch py2rpy có thể tồn tại, chuyển đổi tất cả các chương trình Python thành RPython không? Trong đó ngôn ngữ nó được viết là không liên quan. Nếu có, chúng tôi nhận được một trình biên dịch py2c khác. Sự khác biệt giữa pypy và py2rpy trong tự nhiên là gì? Là py2rpy khó viết hơn nhiều so với pypy?

q3. Có một số quy tắc chung hoặc lý thuyết có sẵn về điều này?

Trình biên dịch khác:

gcc_c = C -> asm? C  # not sure, gimple or rtl?
g++ =   C++ -> asm? C
clang = C -> LLVM_IR  C++
jython = Python -> JVMCode java
ironpython = Python -> CLI C#

q4. Cho f = X -> Z, một chương trình P được viết bằng X. Khi chúng ta muốn tăng tốc P, chúng ta có thể làm gì? Cách khả thi:

  • viết lại P trong thuật toán hiệu quả hơn

  • viết lại f để tạo Z tốt hơn

  • nếu Z được thông dịch, hãy viết một trình thông dịch Z tốt hơn (PyPy có ở đây không?)

  • tăng tốc các chương trình viết bằng Z đệ quy

  • có được một máy tốt hơn

ps. Câu hỏi này không phải là về các công cụ công nghệ về cách viết trình biên dịch, mà là tính khả thi và độ phức tạp của việc viết một trình biên dịch loại nhất định.


Không liên quan trực tiếp, nhưng phần nào là một khái niệm tương tự: en.wikipedia.org/wiki/Supercompilation
SK-logic

1
Tôi không chắc câu hỏi này thực sự phù hợp với Stack Overflow, đặc biệt là có rất nhiều câu hỏi con trong đó, nhưng tôi vẫn ngưỡng mộ ý nghĩ đã đi vào vấn đề này.

4
Bất chấp những gì bạn có thể đã được dạy, AST không bắt buộc - đó đơn giản là chiến lược mà một số trình biên dịch sử dụng.

1
Có lẽ điều này thuộc về cstheory.stackexchange.com
9000

3
Việc triển khai Python của PyPy, giống như hầu hết các "trình thông dịch", thực sự là một trình biên dịch mã byte và một trình thông dịch cho định dạng mã byte đó trong một.

Câu trả lời:


4

q1. pypy là trình thông dịch, một chương trình RPython có thể diễn giải mã Python, không có ngôn ngữ đầu ra, vì vậy chúng ta không thể coi nó là một trình biên dịch, phải không?

PyPy tương tự như CPython, cả hai đều có trình biên dịch + trình thông dịch. CPython có một trình biên dịch được viết bằng C, biên dịch mã Python sang Python VM, sau đó thực thi mã byte trong một trình thông dịch viết bằng C. PyPy có một trình biên dịch được viết bằng RPython biên dịch mã Python sang Python VM, sau đó thực thi nó trong Trình thông dịch PyPy được viết bằng RPython.

q2. Trình biên dịch py2rpy có thể tồn tại, chuyển đổi tất cả các chương trình Python thành RPython không? Trong đó ngôn ngữ nó được viết là không liên quan. Nếu có, chúng tôi nhận được một trình biên dịch py2c khác. Sự khác biệt giữa pypy và py2rpy trong tự nhiên là gì? Là py2rpy khó viết hơn nhiều so với pypy?

Một trình biên dịch py2rpy có thể tồn tại? Về mặt lý thuyết là có. Turing hoàn thành đảm bảo như vậy.

Một phương pháp để xây dựng py2rpylà chỉ cần bao gồm mã nguồn của trình thông dịch Python được viết bằng RPython trong mã nguồn được tạo. Một ví dụ về trình biên dịch py2rpy, được viết bằng Bash:

// suppose that /pypy/source/ contains the source code for pypy (i.e. Python -> Nothing RPython)
cp /pypy/source/ /tmp/py2rpy/pypy/

// suppose $inputfile contains an arbitrary Python source code
cp $inputfile /tmp/py2rpy/prog.py

// generate the main.rpy
echo "import pypy; pypy.execfile('prog.py')" > /tmp/py2rpy/main.rpy

cp /tmp/py2rpy/ $outputdir

bây giờ bất cứ khi nào bạn cần dịch mã Python sang mã RPython, bạn gọi tập lệnh này tạo ra - trong $ outputdir - một RPython main.rpy, mã nguồn Thông dịch Python của RPython và một prog.py blob nhị phân. Và sau đó bạn có thể thực thi tập lệnh RPython được tạo bằng cách gọi rpython main.rpy.

(lưu ý: vì tôi không quen thuộc với dự án rpython, cú pháp gọi trình thông dịch rpython, khả năng nhập pypy và làm pypy.execfile và phần mở rộng .rpy hoàn toàn được tạo ra, nhưng tôi nghĩ bạn hiểu rõ)

q3. Có một số quy tắc chung hoặc lý thuyết có sẵn về điều này?

Có, về mặt lý thuyết, mọi ngôn ngữ Turing Complete đều có thể được dịch sang bất kỳ ngôn ngữ Turing Complete nào. Một số ngôn ngữ có thể khó dịch hơn nhiều so với các ngôn ngữ khác, nhưng nếu câu hỏi là "có thể không?", Câu trả lời là "có"

q4. ...

Không có câu hỏi ở đây.


Trình biên dịch py2rpy của bạn thực sự thông minh. Nó dẫn tôi đến một ý tưởng khác. 1. Pypy có phải được viết bằng RPython trong trình biên dịch của bạn không? Tất cả những gì bạn cần là một cái gì đó có thể diễn giải các tệp Python, phải không? 2. os.system ('python $ inputfile') cũng có thể hoạt động nếu được hỗ trợ trong RPython. Không chắc chắn liệu nó vẫn có thể được gọi là trình biên dịch, ít nhất là không theo nghĩa đen.

Có phải pypy vẫn đang sử dụng Python VM? Bây giờ thì rõ rồi. pypy_the_compiler = Python -> PythonVMCode RPython, pypy_the_interpreter = PythonVMCode -> Không có gì RPython, cpython_the_compiler = Python -> PythonVMCode C, cpython_the_interpreter = PythonVMCode -> Không có gì C

@jaimechen: Does pypy have to be written in RPython in your compiler?Không, không cần phải viết bằng RPython, nhưng RPython phải có thể nói với "trình thông dịch phụ" / "runtime" để thực thi mã Python. Đúng là đây không phải là một "trình biên dịch" theo nghĩa thực tế, nhưng nó là một bằng chứng mang tính xây dựng rằng nó có thể viết được Python -> RPython. Is pypy still using the Python VM?Tôi tin rằng pypy hoàn toàn không sử dụng CPython (tôi có thể sai), thay vào đó PyPy có cách triển khai "Python VM" riêng được viết bằng RPython.
Lie Ryan

@jaimechen: một trình biên dịch thực tế hơn có thể phân tích tệp đầu vào cho các chuỗi mã mà nó biết cách biên dịch và biên dịch chúng một cách riêng biệt và cũng là một cách để nhảy qua lại giữa Python "recompiled-to-RPython" và trình thông dịch " hỗ trợ "Python. Nó cũng có thể sử dụng các kỹ thuật thường được sử dụng trong quá trình biên dịch JIT để phát hiện xem một đầu vào cụ thể có thể tạo ra đầu ra khác nhau do sự khác biệt về ngữ nghĩa của RPython và Python và dự phòng trong các trường hợp đó. Tất cả đó là sự tinh tế có thể được nhìn thấy trong một Python -> RPythontrình biên dịch thực tế hơn .
Lie Ryan

Có lẽ nên thêm một ràng buộc ở đây: chuyển đổi máy trạng thái X thành máy Z, mà không cần sự trợ giúp của máy thứ 3 hiện có. Đây là trường hợp khi X hoàn toàn mới, cho đến nay không có trình biên dịch hoặc trình thông dịch nào tồn tại.
jaimechen

2

Để chỉ trả lời q2, có một cuốn sách biên dịch của William McKeeman, trong đó lý thuyết về trình biên dịch cho ngôn ngữ X được viết bằng ngôn ngữ Y tạo ra ngôn ngữ đầu ra Z được khám phá thông qua một hệ thống sơ đồ T. Xuất bản vào những năm 1970, tiêu đề không đến tay, xin lỗi.


Vâng, đây là nó, cảm ơn. vi.wikipedia.org/wiki/Tombstone_diagram
jaimechen

1

q1. Nói chung, một thông dịch viên không phải là một trình biên dịch. Sự khác biệt chính giữa trình biên dịch và trình thông dịch là trình thông dịch bắt đầu mới, với mã nguồn trong ngôn ngữ nguồn, mọi lúc. Nếu pypy của bạn thay vào đó là pyAST, hoặc mã pyP, và sau đó bạn có trình thông dịch mã AST hoặc P, thì bạn có thể gọi pyAST là trình biên dịch. Đây là cách trình biên dịch UCAS PASCAL cũ hoạt động (cũng như một vài trình khác): chúng được biên dịch thành một số mã P, được diễn giải khi chương trình được chạy. (Ngay cả .NET cũng cung cấp một cái gì đó như thế này, khi sự gọn nhẹ của mã đối tượng được tạo ra quan trọng hơn nhiều so với tốc độ.)

q2. Phải, tất nhiên. Xem UCSD PASCAL (và một loạt những người khác).

q3. Đào qua các văn bản cổ điển trong khoa học máy tính. Đọc về PASCAL đồng thời, bởi Per Brinch-Hansen (nếu bộ nhớ phục vụ cho tôi). Rất nhiều đã được viết về trình biên dịch và tạo mã. Tạo mã giả độc lập với máy thường dễ hơn rất nhiều so với việc tạo mã máy: mã giả thường không có các quirks mà máy thật luôn chứa.

q4. Nếu bạn muốn đối tượng được tạo của mình chạy nhanh hơn, bạn làm cho trình biên dịch thông minh hơn, để tối ưu hóa tốt hơn. Nếu đối tượng của bạn được giải thích, bạn xem xét việc đẩy các hoạt động phức tạp hơn xuống các cấu trúc giả nguyên thủy (CISC so với RISC là tương tự), thì bạn sẽ cố gắng hết sức để tối ưu hóa frack ra khỏi trình thông dịch.

Nếu bạn muốn trình biên dịch của mình chạy nhanh hơn, bạn phải xem MỌI THỨ nó làm, bao gồm cả việc xem xét lại mã nguồn của bạn. Sau khi tải trình biên dịch, phần biên dịch tốn nhiều thời gian nhất là LUÔN LUÔN đọc mã nguồn vào trình biên dịch. . chỉ cần đọc bốn hoặc năm dòng.)

Tôi không nhớ mình đã đọc nó ở đâu, nhưng trình biên dịch Oberon gốc tại ETH-Zurich có cơ chế bảng biểu tượng rất tinh vi, khá thanh lịch. Điểm chuẩn của Wirth về hiệu suất của trình biên dịch là thời gian để trình biên dịch tự biên dịch. Một buổi sáng, anh đi vào, kéo ra bảng biểu tượng siêu cây liên kết tuyệt đẹp và thay thế nó bằng một mảng tuyến tính đơn giản và tìm kiếm tuyến tính thẳng. Các sinh viên tốt nghiệp trong nhóm của mình đã bị SỐC. Sau khi thay đổi, trình biên dịch đã nhanh hơn, bởi vì các mô-đun mà nó đang biên dịch luôn đủ nhỏ để con quái vật tao nhã áp đặt tổng chi phí cao hơn so với tìm kiếm tuyến tính và mảng tuyến tính.


1
Cảm ơn. Trình biên dịch 'biên dịch', trong khi trình thông dịch 'thực thi', có thể có cái nhìn sâu sắc hơn về hai loại chương trình, như kiểu của chúng khác nhau không?
jaimechen

1

Các câu hỏi của bạn như đã nêu khiến tôi tin rằng những gì bạn thực sự muốn / cần là một lời giải thích về trình biên dịch là gì, trình thông dịch là gì và sự khác biệt giữa hai trình biên dịch.

Trình biên dịch ánh xạ một chương trình được viết bằng ngôn ngữ X thành một chương trình tương đương về chức năng được viết bằng ngôn ngữ Y. Ví dụ, trình biên dịch từ Pascal sang C có thể biên dịch

function Square(i: Integer)
begin
    Square := i * i
end

đến

int Square(int i)
{
    return i * i;
}

Hầu hết các trình biên dịch biên dịch 'xuống dưới', vì vậy chúng biên dịch các ngôn ngữ lập trình cấp cao hơn thành các ngôn ngữ cấp thấp hơn, ngôn ngữ cấp thấp cuối cùng là mã máy.

Hầu hết các trình biên dịch biên dịch trực tiếp thành mã máy, nhưng một số (đáng chú ý là các ngôn ngữ Java và .NET) biên dịch thành 'mã byte' ( mã byte JavaCIL ). Hãy nghĩ về mã byte như mã máy cho một máy tính giả định. Mã byte này sau đó được giải thích hoặc JITted khi nó được chạy (nhiều hơn về sau).

Một trình thông dịch thực thi một chương trình được viết bằng một số ngôn ngữ Z. Một thông dịch viên đọc một chương trình từng chút một, thực hiện nó khi nó đi cùng. Ví dụ:

int i = 0;
while (i < 1)
{
    i++
}
return i;

Hãy tưởng tượng người phiên dịch nhìn vào dòng chương trình đó để kiểm tra dòng, kiểm tra dòng, thực hiện những gì nó làm, nhìn vào dòng tiếp theo và vv.

Ví dụ tốt nhất về trình thông dịch là CPU của máy tính của bạn. Nó diễn giải mã máy và thực thi nó. Cách thức hoạt động của CPU được chỉ định bằng cách xây dựng vật lý. Làm thế nào một chương trình thông dịch hoạt động được chỉ định bởi mã của nó trông như thế nào. Do đó, CPU diễn giải và thực thi chương trình thông dịch, lần lượt phiên dịch và thực thi đầu vào của nó. Bạn có thể xâu chuỗi phiên dịch theo cách này.

Một JITter là một trình biên dịch đúng lúc. Một JITter là một trình biên dịch. Sự khác biệt duy nhất là thời gian được thực thi: hầu hết các chương trình được viết, biên dịch, chuyển đến người dùng của họ và sau đó được thực thi, nhưng mã byte Java và CIL được chuyển đến người dùng của họ trước, và ngay trước khi chúng được thực thi, chúng được biên dịch vào máy mã của người dùng của họ.

C # -> (biên dịch) -> CIL -> giao cho khách hàng -> (biên dịch ngay trước khi thực hiện) -> mã máy -> (thực thi)

Điều cuối cùng bạn sẽ muốn biết là tính đầy đủ của Turing ( liên kết ). Một ngôn ngữ lập trình là Turing Complete nếu nó có thể tính toán mọi thứ mà một ' cỗ máy Turing ' có thể, tức là nó ít nhất là 'mạnh mẽ' như một máy Turing. Các Church-Turing luận án tiểu bang rằng một máy Turing là ít nhất là mạnh mẽ như bất kỳ máy chúng tôi bao giờ có thể xây dựng. Theo sau, mọi ngôn ngữ hoàn chỉnh của Turing đều mạnh mẽ như máy Turing, và do đó tất cả các ngôn ngữ hoàn chỉnh của Turing đều có sức mạnh như nhau.

Nói cách khác, miễn là ngôn ngữ lập trình của bạn hoàn thành Turing (gần như tất cả chúng), không quan trọng bạn chọn ngôn ngữ nào, vì tất cả chúng đều có thể tính toán những thứ giống nhau. Điều này cũng có nghĩa là nó không phù hợp với ngôn ngữ lập trình mà bạn chọn để viết trình biên dịch hoặc trình thông dịch. Cuối cùng nhưng không kém phần quan trọng, điều đó có nghĩa là bạn luôn có thể viết trình biên dịch từ ngôn ngữ X sang Y nếu X và Y đều hoàn thành Turing.

Lưu ý rằng việc hoàn thành Turing không nói bất cứ điều gì về việc ngôn ngữ của bạn có hiệu quả hay không, về tất cả các chi tiết triển khai của CPU và phần cứng khác, hoặc chất lượng của trình biên dịch bạn sử dụng cho ngôn ngữ. Ngoài ra, hệ điều hành của bạn có thể quyết định chương trình của bạn không có quyền mở tệp, nhưng điều đó không cản trở khả năng tính toán của bạn - tôi cố tình không định nghĩa điện toán, vì điều đó sẽ chiếm một bức tường văn bản khác.

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.