- vừa được xem lúc

Cùng tìm hiểu về Compiler #1: Làm quen với compiler

0 0 2

Người đăng: Trần Hải Đăng

Theo Viblo Asia

Giới thiệu

Trước khi đi vào một dãy kiến thức dày đặc phía sau thì hãy bắt đầu với vài cái đơn giản về thứ mà bạn sắp đọc trước. Đây là một series mà mình, sẽ cùng các bạn tìm hiểu về compiler, dựa trên chuỗi video "Compiler Design" của Neso Academy trên youtube. Mục đích và mục tiêu của series này là học, không phải dạy, nên nếu mình có mắc 1 hay 1 vài sai lầm nhỏ to gì đấy, thì mong các bạn giúp mình sửa chữa, coi như là cùng nhau học.

1. Dẫn nhập

Nếu bạn là một người lập trình, cho dù hoàn toàn chưa dùng đến những ngôn ngữ "biên dịch", chắc hẳn cũng ít nhất là một lần từng nghe đến từ "Compiler". Vậy cụ thể, nó là gì?

Máy tính là một loại "Máy điện"(Electronic machine), nên nó chỉ có thể hiểu được 0 và 1, hay cụ thể hơn là dòng điện có hay không chạy qua bóng bán dẫn của CPU. Và rõ ràng việc nhập từng số 0 và 1 vào máy tính là một việc chẳng thú vị gì. Nếu bạn vẫn chưa hình dung ra thì đây là "Hello World" trong hệ nhị phân(theo bảng mã ascii): 01001000 01000101 01001100 01001100 01001111 00100000 01010111 01001111 01010010 01001100 01000100

Nó dài như vậy là vì mỗi ký tự được chứa trong 1 byte, và 1 byte chứa tới 8 bit(1 bit là 0 hoặc 1).

Vì sự dài dòng và bất tiện đó nên ta mới cần Compiler, thứ mà sẽ dịch những chương trình C, C++,... sang hợp ngữ(Assembly) và từ Assembly sang mã máy nhờ Assembler.

2. Punched card(thẻ đục lỗ)

Nhưng trước khi Assembler và Compiler ra đời, các lập trình viên vẫn phải làm việc với những số 0 và 1. Và nếu bạn thắc mắc rằng "Khiên và Giáo" của họ trông như thế nào thì.

Punched card(Thẻ đục lỗ): image.png

Và Punched tape(Băng đục lỗ): image.png

Những cái lỗ ấy sẽ tượng trưng cho 1, còn lại là 0.

3. Language Translator

Tất nhiên là chả ai thích việc ngồi bấm mấy cái lỗ lên giấy cả ngày. Thế nên sự khó khăn thôi thúc con người vươn lên(dù chính họ tạo ra sự khó khăn này).

Kết quả của sự vươn lên ấy là việc những Language Translator lần lượt ra đời. Về cơ bản, Language Translator là chương trình sẽ dịch source code của bạn, thứ được viết bằng ngôn ngữ không phải mã máy thành 1 ngôn ngữ khác hoặc trực tiếp sang mã máy. Language Translator sơ khai nhất Assembler dành cho Assembly. Trên nền tảng Assembly, các ngôn ngữ bậc cao hơn cũng như Compiler và Interpreter ra đời. image.png

4. Assembler, Interpreter và Compiler?

1. Assembler

Assembler là trình thông dịch của hợp ngữ(Assembly). Assembly là ngôn ngữ lập trình gần với mã máy nhất, về cả cấu trúc chương trình và việc nó thao tác trực tiếp với CPU. Vì sự gần gũi ấy nên Assembly chỉ cần 1 Assembler để biên dịch trực tiếp sang mã máy mà không cần các bước xử lí trung gian. Screenshot-2019-03-01-at-4.13.08-PM.png

2. Interpreter

Interpreter là tên gọi chung của các trình thông dịch(nói chung là chương trình để chạy) của các ngôn ngữ thông dịch(interpet). Source của các ngôn ngữ thông dịch không cần dịch sang Assembly, nên có vẻ nó sẽ tự do hơn trong cú pháp, nhưng vấn đề lớn nhất của ngôn ngữ thông dịch là tốc độ... cực kì rùa. Tiêu biểu trong giới này là: Python, Javascript, PHP,... image.png

3. Compiler

Compiler cũng giống như Interpreter, là tên gọi chung của trình biên dịch, chương trình để biến đống chữ của bạn thành thứ máy tính hiểu được. Nhưng không như Interpreter chạy luôn, Compiler sẽ qua 1 vài bước trung gian để chuyển source thành Assembly, rồi đùn đẩy cho Assembler. Tiêu biểu nhất trong giới biên dịch là C, là nền tảng của rất nhiều ngôn ngữ sau này, tiếp theo là C++, Erlang,... image.png

5. Language Translator(Compile) Internal Architecture (Kiến trúc bên trong của một Language Translator)

Chú ý: Kiến trúc của Language Translator ở đây là của C Compiler và những hình ảnh sau sẽ được lấy từ video của Neso Academy

Language Translator có 4 giai đoạn khác nhau: image.png

1. Preprocessor(Bộ tiền xử lí)

Preprocesser sẽ xử lí để code của bạn "sạch" đủ để Compiler làm việc. Ví dụ như xóa những comment, cũng như là làm việc với những thằng include. image.png

2. Compiler

Ở giải đoạn này, code đã được xử lí ở Preprocesser(Pure High Level Language) sẽ được biên dịch sang Assembly. image.png

3. Assembler

Kế đến là công việc của Assembler, từ code Assembly ở trên, Assembler sẽ generate ra Relocatable Machine code(mã máy nhưng những địa chỉ ô nhớ có thể được đặt lại) bởi vì chúng ta sẽ không thể biết lúc chạy chương trình thì sẽ có những ô nhớ nào trống.

Và bạn cũng có thể thấy rằng trong hình, những địa chỉ i+0, i+1, i+2 là 1 dãy liên tiếp(sequence). image.png

4. Linker/loader

Cuối cùng là Linker/loader, công việc của nó là generate ra Absolute Machine Code(Mã máy tuyệt đối) hay cụ thể hơn là thêm địa chỉ vào Relocatable MC. Absolute MC là loại mã máy thực sự chạy được, và cơ bản là thứ sẽ được tải vào RAM. image.png

6. Compiler Internal Architecture (Kiến trúc của một Compiler)

Nhân vật chính của chúng ta, Compiler có 6 giai đoạn chính. 3 giai đoạn đầu được gọi chung là giai đoạn phân tích(Analysis Phase), 3 giai đoạn cuối là giai đoạn tổng hợp(Synthetic Phase). image.png Tuy nhiên, theo góc độ của phần mềm thì 4 giai đoạn đầu được gọi là Front-end, còn lại là Back-end. image.png Bởi vì, nếu bây giờ bạn đang có một C Compiler cho Window và muốn làm 1 cái cho anh bạn MacOS thì việc bạn cần làm là thay đổi Back-end và tadaa, bạn đó có 1 MacOS C Compiler.

Ngoài ra còn có 2 phần tử khác nữa. Đó là Symbol Table Manager và Error Handle: image.png Trong đó Symbol Table Manager sẽ lấy thông tin ở Analysis Phase và được sử dụng ở Synthetic Phase. Còn Error Handler với công việc chơi với bọ sẽ được sử dụng ở cả 6 phase.

7. Kết

Gần như toàn bộ kiến thức trong bài viết đều lấy từ video của Neso Academy, nên mong bạn sẽ ủng hộ video gốc ấy. Và việc diễn đạt nó bằng tiếng việt thực sự khó. Thế nên nếu bạn có cách giải thích nào hay hơn hoặc có bất kì câu hỏi nào, đừng ngại bình luận. Xin cảm ơn!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tại sao Rails lại dùng cả Webpack lẫn Sprocket?

Khi Rails 6 được ra mắt, có thể bạn đã từng tự hỏi. WTF, sao Webpack đã được add vào rồi, mà Sprocket vẫn tồn tại thế kia . Chẳng phải Webpack và Sprocket được dùng để giải quyết chung một công việc hay sao. Hoặc cả đây:.

0 0 47

- vừa được xem lúc

Tìm hiểu chung về LLVM

Không hề khó khăn khi nhận thấy rằng các ngôn ngữ lập trình được tạo ra cũng như cải tiến với tốc độ ngày một cao. Rust của Mozilla, Swift của Apple hay Kotlin của Jetbrain và nhiều ngôn ngữ khác cung cấp cho các nhà phát triển một loạt các lựa chọn mới về tốc độ, độ an toàn, sự tiện lợi, tính di độ

0 0 20

- vừa được xem lúc

Sự khác nhau giữa trình biên dịch và trình thông dịch

Trình biên dịch là trình dịch chuyển đổi từ ngôn ngữ nguồn (các ngôn ngữ lập trình bậc cao) thành ngôn ngữ đối tượng (ví dự như ngôn ngữ máy). Ngược lại với trình biên dịch, trình thông dịch là một ch

0 0 34

- vừa được xem lúc

002: JVM Compiler với C1 Compiler và C2 Compiler

Bài viết nằm trong series Java memory management & performance. Một ví dụ dễ hiểu như sau, ta có một văn bản bằng tiếng Anh, và muốn nó được dịch sang ngôn ngữ tiếng Nhật để được thực thi.

0 0 38

- vừa được xem lúc

003: JVM Code cache và Ahead of Time Compiler

Bài viết nằm trong series Java memory management & performance. Bài viết hôm nay sẽ tìm hiểu kĩ hơn về JVM Code cache, tuning JVM Code cache size và AoT Compiler.

0 0 26

- vừa được xem lúc

Bạn có thực sự hiểu JVM chạy thế nào?

Xin chào a/e đã đang và sẽ thành dev Java như em, chắc 99% mọi người đều biết jvm là máy ảo, java là ngôn ngữ biên dịch,… nhưng an hem có thực sự hiểu cơ chế hoạt động của java và jvm. Tại sao java lạ

0 0 132