Compiler, Interpreter : chúng là gì và cách chúng hoạt động.

Có thể bạn đã biết, những ngôn ngữ lập trình chúng ta đang dùng là ngôn ngữ lập trình con người đọc được (Programming language human readable).

Máy tính là thiết bị điện tử với CPU là trung tâm, mọi yêu cầu của ta cho máy tính đều phải được chuyển thành lệnh để nạp vào CPU, những lệnh này được gọi là các Chỉ-lệnh-máy (Machine instructions ), CPU sẽ thực hiện các hành động tương ứng với các chỉ-lệnh này, một tập hợp các chỉ-lệnh-máy được gọi là chương-trình-mã-máy hoặc chương-trình-thực-thi (executive program)

Để thực hiện một đoạn mã đơn giản như :

int result = + 5;

phải đưa về mã máy (tham khảo, nó có thể chưa chính xác hoàn toàn) :

//lưu trữ giá trị

0000 0000 0000 1000
0000 0000 0000 0101
0000 0000 0000 0000 

// tập các chỉ-lệnh
1000 1010 0000 0000 // chỉ-lệnh thứ 1
1000 1011 0000 0001 // chỉ-lệnh thứ 2
0001 1100 1010 1011 // chỉ-lệnh thứ 3
1001 1100 0000 0010 // chỉ-lệnh cuối
 

(Tham khảo : http://introcs.cs.princeton.edu/java/63programming/add.toy)

Đối với các CPU khác nhau dù thực hiện cùng hành động nhưng có thể các chỉ-lệnh sẽ khác nhau. (ở đây là chỉ-lệnh thứ 3)

+ CPU A : mã 0001 là lệnh cộng
+ CPU B : mã 0001 là lệnh trừ

Và còn vấn đề hệ điều hành nữa, như Linux không thể thực thi chương trình được tạo ra cho Window, bởi vì cấu trúc tệp thực thi của các nền tảng là khác nhau, tài nguyên cung cấp bởi các nền tảng cũng khác nhau (kiến trúc, các thư viện, chương trình con..)..v..v.., chúng ta sẽ không đi sâu bởi nó còn rắc rối hơn đã nói, nhưng tổng quan thì có nhiều vấn đề phải nghĩ tới phải không?

Hmm.. vậy là phải chuyển mã nguồn thành những tập chỉ-lệnh tương ứng để CPU có thể hiểu và thực thi, mà thêm nữa là phải phù hợp với từng loại CPU và hệ điều hành. Đó chính là mục đích của Complier và Interpreter, dịch mã nguồn thành tập chỉ-lệnh-máy tương ứng. Vậy chúng hoạt động như thế nào? và phân biệt ra sao?

Complier

Complier là một chương trình, nó sẽ dịch toàn bộ mã nguồn ngôn ngữ cấp cao sang ngôn ngữ cấp thấp hơn.

Trước khi được biên dịch, mã nguồn trải qua giai đoạn tiền xử lý,

Phân tích từ vựng (Lexical Analysis) : chuyển các ký tự trong mã nguồn thành các chuỗi đại diện (Token) dựa theo bảng ký tự (symbol table) phù hợp của ngôn ngữ đó, bỏ khoảng trắng, tab, comments. Đây là bước kiểm tra tính đúng đắn của mã nguồn

int result = + 5;

khi được phân tích sẽ trở thành dạng như thế này :

keyword(int)
identifier(result)
symbol(=)
symbol(+)
number(8)
symbol(*)
number(5)

int res”ult = + 5;

sẽ báo lỗi trong quá trình chuyển đổi vì res”ult không thuộc bất kỳ token nào (keyword, identifier, symbol, number,…) trong bảng (symbol table).

Việc chuyển đổi thế này có tác dụng :

  • Bằng cách xóa bỏ khoảng trắng và comments, cho phép trình phân tích cú pháp (syntactical analysis) hoạt động hiệu quả.
  • Tăng tốc độ đọc của bộ đệm trong khi biên dịch.
  • Tăng tính linh hoạt cho trình biên dịch.

Phân tích cú pháp (syntactic analysis) : sử dụng kết quả của bước trước để tiến hành kiểm tra cú pháp của mã nguồn, nếu có bất kỳ cú pháp nào sai trình biên dịch sẽ thông báo lại cho lập trình viên rằng nó không hiểu ở dòng nào.

  • You tried to use a variable that was not declared
  • You said that this variable was going to be number but then tried to assign a string to it.

Các thông báo lỗi trên có lẽ bạn thấy rất quen thuộc phải không? 

compilerstep

Tổng quát các bước trong một trình biên dịch

Nếu tất cả các bước kiểm tra đều không xảy ra lỗi, thì giờ trình biên dịch đã có thể tiến hành chuyển đổi mã nguồn từ ngôn ngữ cấp cao sang cấp thấp hơn.

Tại sao ỏ đây tôi không nói rằng mã nguồn sẽ được chuyển sang mã máy, mà lại dùng cụm từ cấp thâp hơn? lý do là bởi vì một trình biên dịch có thể sẽ không chuyển đổi trực tiếp mã nguồn sang mã máy mà nó sẽ chuyển về một mã trung gian khác, gọi là mã đối tượng (object code), Ví dụ ở Java là tệp *.class (bytecode) hoặc đối với C++ là tệp *.o (objectcode) sau đó được liên kết với các thư viện (library) để tạo thành tệp thực thi *.exe.

Intergreter

Thông dịch là một chương trình sẽ đọc từng lệnh và thực thi bằng cách chuyển thành chỉ-lệnh-máy.

Một quá trình thông dịch sẽ kết thúc khi chương trình hoàn thành hoạt động (completed)  hoặc xảy ra lỗi (error occurs). Điều đó có nghĩa là mỗi một lỗi xẩy ra chỉ được báo trong thời gian thực thi (runtime) tại thời điểm đó. Điều này khác Complier ở chổ, nếu một mã nguồn có lỗi thì toàn bộ chương trình không được thực thi trong khi đó Intergreter sẽ thực thi từng lệnh cho tới khi xảy ra lỗi.

Sự kết hợp

Ngày nay rất nhiều ngôn ngữ đã tận dụng kết hợp cả complier và intergreter để thực thi chương trình, bằng cách biên dịch mã nguồn thành object code và sử dụng intergreter để thực thi, với cách này việc thông dịch các chỉ lệnh sang chỉ-lệnh-máy được tăng tốc, việc kết hợp như vậy không mất nhiều tài nguyên để biên dịch liên tục các chương trình phù hợp với từng máy, mà chỉ cần ở máy khác có trình thông dịch là có thể thực thi chương trình.

Ví dụ điển hình là ngôn ngữ Java, tệp *.java được chuyển thành bytecode *.class và có thể thực thi bởi trình thông dịch trong JVM (Java virtual machine).

Ngoài ra, còn có các ngôn ngữ C#, Python, Ruby,…

Một cách tổng quát về cách hoạt động của sự kết hợp này :

  • Complier biên dịch mã nguồn thành object code với đầy đủ bước kiểm tra như đã nói, nếu có lỗi cú pháp sẽ được báo ngay.
  • Object code được gửi cho chương trình thông dịch để thực thi, chương trình sẽ bị ngắt nếu chương trình thực thi có lỗi xẩy ra.

Nhưng việc thực thi qua intergreter sẽ chậm hơn so với việc biên dịch mã nguồn sang trực tiếp mã máy, vì vậy một chế độ mới trong trình giả lập được tạo ra đó là JIT (Just-in-time complier), thay vì đọc và dịch từng lệnh một mỗi lần, nó sẽ biên dịch một khối các lệnh được sử dụng thường xuyên sang mã máy và lưu trữ để sử dụng trong tương lai, nếu bắt gặp một lệnh đã được biên dịch trước đó thì chỉ cần nạp lại mã máy đã được biên dịch trước đó. Điều đó sẽ giảm tiêu tốn tài nguyên thay vì phải đọc – dịch 1000 lần một lệnh giống nhau.

Cảm ơn bạn đã đọc, mong bài viết sẽ giúp bạn hiểu thêm về complier và intergreter.

Continue reading

Advertisements