Giải thích vs Biên dịch: Một sự phân biệt hữu ích?


29

Rất nhiều câu hỏi được hỏi ở đây về việc diễn giải và thực hiện ngôn ngữ được biên dịch. Tôi đang tự hỏi liệu sự khác biệt thực sự có ý nghĩa gì. (Trên thực tế các câu hỏi thường là về ngôn ngữ, nhưng họ thực sự đang suy nghĩ về việc triển khai phổ biến nhất các ngôn ngữ đó).

Ngày nay hầu như không thực hiện được giải thích nghiêm ngặt. tức là khá nhiều người không phân tích cú pháp và chạy mã một dòng tại một thời điểm. Ngoài ra, việc thực hiện biên dịch mã máy cũng trở nên ít phổ biến hơn. Càng ngày, trình biên dịch nhắm vào một số loại máy ảo.

Trong thực tế, hầu hết việc thực hiện đều hội tụ trên cùng một chiến lược cơ bản. Trình biên dịch tạo mã byte được giải thích hoặc biên dịch thành mã gốc thông qua JIT. Nó thực sự là một sự pha trộn của các ý tưởng truyền thống về biên soạn và giải thích.

Vì vậy, tôi hỏi: Có một sự phân biệt hữu ích giữa các triển khai được giải thích và thực hiện biên dịch những ngày này?


7
@DeadMG Không mới như bạn nghĩ: Lịch sử ngắn gọn về thời gian ...
yannis

4
@DeadMG Cho rằng phần lớn các ngôn ngữ mới được giới thiệu trong 10 năm qua hoặc chủ yếu chạy trên một số loại VM, tôi muốn nói rằng anh ta có một điểm. Tất nhiên vẫn còn (và sẽ trong nhiều thập kỷ tới) các ngôn ngữ được biên dịch thành mã gốc, và một JIT sẽ vẫn còn xa xỉ (hoặc không, nếu các chàng trai PyPy có cách của họ). Vì vậy, vâng, có thể nói quá, nhưng tôi đồng ý rằng dòng chính (hiện tại và tương lai có thể thấy được) dường như là trình biên dịch mã byte + có thể là JIT.

4
@DeadMG, bạn phải có một bộ râu dài màu trắng, nếu mô hình VM là "mới" cho bạn. P-codeđã được giới thiệu vào năm 1966 đầu tiên. IBM Aix xuất hiện từ năm 1986.
SK-logic

6
Những thứ như vỏ unix, Tcl và giống nhau sẽ luôn được giải thích thuần túy, vì vậy sự khác biệt có ý nghĩa, ít nhất là trong một CS học thuật. Nhưng sự thật là khi các lập trình viên đang lẩm bẩm về trình thông dịch so với trình biên dịch, họ sẽ không có ý nghĩa gì trong hầu hết các trường hợp.
SK-logic

3
@ SK-logic, tôi nghĩ rằng nhận xét của bạn là câu trả lời tốt hơn sau đó bất kỳ câu trả lời nào thực sự được đăng
Winston Ewert

Câu trả lời:


23

Điều quan trọng cần nhớ là phiên dịch và biên dịch không chỉ là lựa chọn thay thế cho nhau. Cuối cùng, bất kỳ chương trình nào bạn viết (bao gồm một chương trình được biên dịch thành mã máy) đều được diễn giải. Giải thích mã đơn giản là lấy một bộ hướng dẫn và trả lời câu trả lời.

Biên dịch, mặt khác, có nghĩa là chuyển đổi một chương trình trong một ngôn ngữ sang ngôn ngữ khác. Thông thường, giả định rằng khi quá trình biên dịch diễn ra, mã được biên dịch sang ngôn ngữ "cấp thấp hơn" (ví dụ: mã máy, một số loại mã byte VM, v.v.). Mã biên dịch này vẫn được giải thích sau này.

Liên quan đến câu hỏi của bạn về việc liệu có sự phân biệt hữu ích giữa các ngôn ngữ được dịch và biên dịch hay không, ý kiến ​​cá nhân của tôi là mọi người nên có một sự hiểu biết cơ bản về những gì đang xảy ra với mã họ viết trong quá trình giải thích. Vì vậy, nếu mã của họ đang được biên dịch JIT, hoặc được lưu trong bộ nhớ cache, v.v., lập trình viên ít nhất nên có một sự hiểu biết cơ bản về điều đó có nghĩa là gì.


3
Có lập trình viên nên có một sự hiểu biết cơ bản. Nhưng tôi tự hỏi nếu thuật ngữ được biên dịch / giải thích không cản trở điều đó.
Winston Ewert

2
Cảm ơn bạn!! Giải thích chỉ là một từ đồng nghĩa với "thực thi" và đó là cách tất cả các chương trình được chạy.
vườn

9

Sự khác biệt có ý nghĩa sâu sắc bởi vì các ngôn ngữ được biên dịch hạn chế ngữ nghĩa theo những cách mà ngôn ngữ diễn giải không nhất thiết phải có. Một số kỹ thuật diễn giải là rất khó (thực tế không thể) để biên dịch.

Mã được giải thích có thể thực hiện những việc như tạo mã trong thời gian chạy và cung cấp khả năng hiển thị mã đó thành các ràng buộc từ vựng của một phạm vi hiện có. Đó là một ví dụ. Một điều nữa là các trình thông dịch có thể được mở rộng bằng mã thông dịch có thể kiểm soát cách đánh giá mã. Đây là cơ sở cho "fexprs" Lisp cổ đại: các hàm được gọi với các đối số không được đánh giá và quyết định phải làm gì với chúng (có toàn quyền truy cập vào môi trường cần thiết để đi bộ mã và đánh giá các biến, v.v.). Trong các ngôn ngữ được biên dịch, bạn không thể thực sự sử dụng kỹ thuật đó; thay vào đó, bạn sử dụng macro: các hàm được gọi tại thời điểm biên dịch với các đối số không được đánh giá và dịch mã thay vì diễn giải.

Một số triển khai ngôn ngữ được xây dựng xung quanh các kỹ thuật này; các tác giả của họ từ chối biên dịch là một mục tiêu quan trọng, và thay vào đó nắm lấy loại linh hoạt này.

Phiên dịch sẽ luôn hữu ích như một kỹ thuật để khởi động trình biên dịch. Để có một ví dụ cụ thể, hãy xem CLISP (một triển khai phổ biến của Common Lisp). CLISP có một trình biên dịch được viết bằng chính nó. Khi bạn xây dựng CLISP, trình biên dịch đó sẽ được diễn giải trong các bước xây dựng ban đầu. Nó được sử dụng để tự biên dịch, và sau đó khi nó được biên dịch, quá trình biên dịch sẽ được thực hiện bằng trình biên dịch được biên dịch.

Nếu không có kernel phiên dịch, bạn sẽ cần bootstrap với một số Lisp hiện có, giống như SBCL.

Với giải thích, bạn có thể phát triển một ngôn ngữ từ đầu tuyệt đối, bắt đầu với ngôn ngữ lắp ráp. Phát triển các I / O cơ bản và các thói quen cốt lõi, sau đó viết một ngôn ngữ máy tĩnh. Một khi bạn đã có eval, hãy viết bằng ngôn ngữ cấp cao; hạt nhân mã máy thực hiện việc đánh giá. Sử dụng cơ sở này để mở rộng thư viện với nhiều thói quen hơn và cũng viết một trình biên dịch. Sử dụng trình biên dịch để biên dịch các thường trình đó và chính trình biên dịch.

Dịch nghĩa: một bước đệm quan trọng trong con đường dẫn đến việc biên soạn!


1
IMO, đây là câu trả lời tốt nhất. Tôi đang làm việc với ngôn ngữ đồ chơi của riêng mình và đoạn cuối mô tả cách tôi đang phát triển nó. Nó thực sự làm cho những ý tưởng mới dễ dàng hơn nhiều. Cũng +1 để đề cập đến quá trình bootstrap CLISP.
sinan

Về lý thuyết, bất kỳ ngôn ngữ nào được dịch bằng tiếng Nhật có thể được tạo thành một ngôn ngữ được biên dịch bằng cách tạo ra một tệp EXE bao gồm trình thông dịch cộng với mã nguồn hoặc mã byte cho chương trình được dịch. Có thể không rất hiệu quả, mặc dù.
dan04

Đọc về cách Wirth et al phát minh ra mã P để đơn giản hóa việc chuyển PASCAL sang các kiến ​​trúc máy mới. Đó là vào đầu những năm 1970.
John R. Strohm

1
Tôi nghi ngờ đoạn mở đầu của bạn là phần biên dịch và diễn giải khó hiểu với hành vi tĩnh và động, nhưng tôi sẽ cho bạn lợi ích của sự nghi ngờ và chỉ hỏi một ví dụ về ngôn ngữ có ngữ nghĩa "thực tế không thể biên dịch". Về bootstrapping một trình biên dịch, đúng là việc triển khai đầu tiên cần phải được viết bằng thứ gì đó không phải là ngôn ngữ bạn đang thực hiện, nhưng nó không phải là một trình thông dịch, nó có thể là một trình biên dịch được viết bằng ngôn ngữ khác.
8bittree

1

Trên thực tế rất nhiều triển khai ngôn ngữ vẫn được diễn giải nghiêm ngặt, bạn chỉ có thể không nhận thức được chúng. Để đặt tên cho một số: các ngôn ngữ hệ vỏ UNIX, các vỏ Windows cmd và PowerScript, Perl, awk, sed, MATLAB, Mathicala, v.v.


3
Tôi tin rằng Perl được biên dịch nội bộ thành mã byte, và ít nhất Mathicala có thể được biên dịch. Và không có gì chỉ ra việc thực hiện awk và sed (tôi tin rằng một số lõi của GNU biên dịch các biểu thức chính quy để tự động hữu hạn trước khi thực thi, có thể đưa chúng vào loại "biên dịch thành biểu diễn trung gian, diễn giải điều đó").

1
Trên thực tế tôi khá chắc chắn rằng Perl, MATLAB, Mathicala đều biên dịch thành mã byte. Tôi không quen thuộc với PowerScript, ý bạn là Powershell? Nếu vậy, sử dụng CLR và sử dụng mã byte.
Winston Ewert

@WinstonEwert, xin lỗi tôi có nghĩa là PowerShell. Hiểu biết của tôi là việc dịch sang dạng trung gian không có nghĩa là một cái gì đó không được giải thích. Heck, trình thông dịch gốc của Dartmouth BASIC đã dịch nguồn thành mã thông báo trước khi phiên dịch. Mỗi công cụ tôi đã đề cập có một chế độ trong đó 1) đọc một dòng nguồn, 2) dịch dòng đó thành một dạng thực thi (có thể là một số mã trung gian thay vì mã gốc), 3) thực thi mã cho dòng đó, 4) lặp lại 1). Điều đó tương ứng với sự hiểu biết của tôi về một thông dịch viên.
Charles E. Grant

2
Bytecode không ngụ ý biên dịch. Trình biên dịch mã byte đơn giản là một chương trình lấy nguồn và chuyển đổi nó thành mã byte. Do đó, tất cả việc sử dụng mã byte phải liên quan đến trình biên dịch mã byte. Nhưng mã byte cũng phải được giải thích (hoặc JITted). Vì vậy, bất cứ điều gì sử dụng mã byte là một trình biên dịch / trình biên dịch lai.
Winston Ewert

4
Thực sự, điều của tôi là mọi người đưa ra các câu như "python được diễn giải" và "Java được biên dịch" mà không hiểu gì về các triển khai. Tôi đang tìm kiếm liệu nó có hữu ích để mô tả một triển khai trong các điều khoản đó hay không. Sự thật thường phức tạp hơn và cố gắng giải thích / biên dịch nó không hữu ích.
Winston Ewert

1

Tôi nghĩ: Hoàn toàn có .

Trên thực tế, hầu hết việc thực hiện đều hội tụ trên cùng một chiến lược cơ bản

Thực sự, C ++ nhằm mục đích chuyển sang miền biên dịch một số khái niệm cấp cao thường được trao cho người phiên dịch, nhưng nó vẫn thuộc về phía thiểu số ...


2
Đợi cho đến khi Clang + LLVM trở thành công cụ biên dịch phổ biến nhất.
SK-logic

@ SK-logic, mặc dù tên, tôi tin rằng Clang + LLVM tạo mã gốc.
Winston Ewert

1
@Winston Ewert, chỉ khi bạn muốn. Sau đó, bạn có thể dừng ở cấp độ LLVM IR và làm bất cứ điều gì bạn muốn với nó - diễn giải nó, biên dịch JIT, sử dụng nó theo bất kỳ cách nào bạn muốn. Bạn thậm chí có thể dịch nó sang Javascript và sau đó chuyển qua một trình thông dịch: github.com/kripken/emscripten/wiki
SK-logic

@ SK-logic, đồ gọn gàng! Không biết LLVM có thể làm điều đó.
Winston Ewert

1
Cái hay của llvm là sự tách biệt có chủ ý giữa mặt trước và mặt sau. Và các công cụ để thao tác giữa trước khi nhắm mục tiêu tập lệnh. Bạn có thể hợp nhất toàn bộ dự án của mình vào mã byte và sau đó tối ưu hóa toàn bộ, với các trình biên dịch khác, bạn sẽ cần phải có một nguồn tệp duy nhất hoặc ít nhất một nguồn bao gồm thông qua cây nguồn để trình biên dịch hoạt động trên một nguồn kết hợp. Ngoài ra, một bộ công cụ theo llvm là chung cho tất cả các mục tiêu, bạn không phải xây dựng cho từng mục tiêu, một trình biên dịch phù hợp với tất cả (ít nhất là với asm của mục tiêu).
old_timer

-1

Phân biệt hữu ích: các chương trình diễn giải có thể tự sửa đổi bằng cách thêm hoặc thay đổi các chức năng khi chạy.


8
Vô lý. Mã tự sửa đổi (máy) là thủ thuật lâu đời nhất trong cuốn sách. Sau đó, một lần nữa, một số lập luận thậm chí mã gốc cuối cùng được phiên dịch bởi một trình thông dịch được đúc thành silicon (CPU). Nhưng nếu chúng ta giả định rằng, tất cả các mã được diễn giải và không có sự phân biệt để thực hiện.

2
@del Nam nói đúng. Tôi sẽ chỉ thêm rằng các ngôn ngữ hiện đại có thể tự sửa đổi bằng cách tạo các lớp mới một cách linh hoạt và tải / dỡ thư viện (hoặc "tập hợp" trong .NET chẳng hạn)
Jalayn

5
Lisp chung được biên dịch, nhưng bạn vẫn có thể thay thế các định nghĩa hàm trong thời gian chạy một cách dễ dàng.
SK-logic

Đó là một tính năng thực sự thú vị và cần thiết (ví dụ như trong Prolog).
CapelliC
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.