Giới thiệu
Một trình biên dịch điển hình thực hiện các bước sau:
- Phân tích cú pháp: văn bản nguồn được chuyển đổi thành cây cú pháp trừu tượng (AST).
- Độ phân giải của các tham chiếu đến các mô-đun khác (C hoãn lại bước này cho đến khi liên kết).
- Xác nhận ngữ nghĩa: loại bỏ các tuyên bố chính xác về mặt cú pháp mà không có ý nghĩa, ví dụ mã không thể truy cập hoặc khai báo trùng lặp.
- Các phép biến đổi tương đương và tối ưu hóa mức cao: AST được biến đổi để thể hiện một tính toán hiệu quả hơn với cùng một ngữ nghĩa. Điều này bao gồm, ví dụ tính toán sớm các biểu thức con phổ biến và biểu thức hằng, loại bỏ các bài tập cục bộ quá mức (xem thêm SSA ), v.v.
- Tạo mã: AST được chuyển đổi thành mã cấp thấp tuyến tính, với các bước nhảy, phân bổ đăng ký và tương tự. Một số cuộc gọi chức năng có thể được nội tuyến ở giai đoạn này, một số vòng lặp không được kiểm soát, v.v.
- Tối ưu hóa lổ nhìn trộm: mã cấp thấp được quét cho các hiệu quả cục bộ đơn giản được loại bỏ.
Hầu hết các trình biên dịch hiện đại (ví dụ, gcc và clang) lặp lại hai bước cuối cùng một lần nữa. Họ sử dụng một ngôn ngữ trung gian thấp nhưng độc lập với nền tảng để tạo mã ban đầu. Sau đó, ngôn ngữ đó được chuyển đổi thành mã dành riêng cho nền tảng (x86, ARM, v.v.) thực hiện điều tương tự theo cách tối ưu hóa nền tảng. Điều này bao gồm, ví dụ như việc sử dụng các hướng dẫn vectơ khi có thể, sắp xếp lại hướng dẫn để tăng hiệu quả dự đoán nhánh, v.v.
Sau đó, mã đối tượng đã sẵn sàng để liên kết. Hầu hết các trình biên dịch mã gốc đều biết cách gọi một trình liên kết để tạo ra một tệp thực thi, nhưng đó không phải là một bước biên dịch mỗi se. Trong các ngôn ngữ như liên kết Java và C # có thể hoàn toàn động, được thực hiện bởi VM khi tải.
Ghi nhớ những điều cơ bản
- Lam cho no hoạt động
- Làm cho nó đẹp
- Làm cho nó hiệu quả
Trình tự cổ điển này áp dụng cho tất cả các phát triển phần mềm, nhưng có sự lặp lại.
Tập trung vào bước đầu tiên của chuỗi. Tạo điều đơn giản nhất có thể có thể làm việc.
Đọc những cuốn sách!
Đọc Sách Rồng của Aho và Ullman. Điều này là cổ điển và vẫn còn khá áp dụng ngày nay.
Thiết kế trình biên dịch hiện đại cũng được ca ngợi.
Nếu công cụ này quá khó đối với bạn ngay bây giờ, hãy đọc một số phần giới thiệu về phân tích cú pháp trước; thường phân tích các thư viện bao gồm phần giới thiệu và ví dụ.
Hãy chắc chắn rằng bạn cảm thấy thoải mái khi làm việc với đồ thị, đặc biệt là cây cối. Những điều này là các chương trình công cụ được thực hiện ở mức độ logic.
Xác định ngôn ngữ của bạn tốt
Sử dụng bất kỳ ký hiệu nào bạn muốn, nhưng hãy chắc chắn rằng bạn có một mô tả đầy đủ và nhất quán về ngôn ngữ của bạn. Điều này bao gồm cả cú pháp và ngữ nghĩa.
Đã đến lúc viết đoạn mã bằng ngôn ngữ mới của bạn làm trường hợp thử nghiệm cho trình biên dịch trong tương lai.
Sử dụng ngôn ngữ yêu thích của bạn
Hoàn toàn ổn khi viết trình biên dịch bằng Python hoặc Ruby hoặc bất kỳ ngôn ngữ nào đều dễ dàng đối với bạn. Sử dụng các thuật toán đơn giản, bạn hiểu rõ. Phiên bản đầu tiên không nhất thiết phải nhanh, hiệu quả hoặc đầy đủ tính năng. Nó chỉ cần phải đủ chính xác và dễ dàng để sửa đổi.
Bạn cũng có thể viết các giai đoạn khác nhau của trình biên dịch bằng các ngôn ngữ khác nhau, nếu cần.
Chuẩn bị viết rất nhiều bài kiểm tra
Toàn bộ ngôn ngữ của bạn nên được bao phủ bởi các trường hợp thử nghiệm; có hiệu quả nó sẽ được xác định bởi họ. Làm quen với khung thử nghiệm ưa thích của bạn. Viết bài kiểm tra từ ngày đầu tiên. Tập trung vào các thử nghiệm 'dương' chấp nhận mã chính xác, trái ngược với việc phát hiện mã không chính xác.
Chạy tất cả các bài kiểm tra thường xuyên. Sửa các bài kiểm tra bị hỏng trước khi tiến hành. Sẽ là một sự xấu hổ khi kết thúc với một ngôn ngữ không xác định không thể chấp nhận mã hợp lệ.
Tạo một trình phân tích cú pháp tốt
Máy phát điện Parser rất nhiều . Chọn bất cứ thứ gì bạn muốn. Bạn cũng có thể viết phân tích cú pháp của riêng bạn từ đầu, nhưng nó chỉ có giá trị nó nếu cú pháp của ngôn ngữ của bạn là chết đơn giản.
Trình phân tích cú pháp sẽ phát hiện và báo cáo lỗi cú pháp. Viết rất nhiều trường hợp kiểm tra, cả tích cực và tiêu cực; sử dụng lại mã bạn đã viết trong khi xác định ngôn ngữ.
Đầu ra của trình phân tích cú pháp của bạn là một cây cú pháp trừu tượng.
Nếu ngôn ngữ của bạn có các mô-đun, đầu ra của trình phân tích cú pháp có thể là biểu diễn đơn giản nhất của 'mã đối tượng' mà bạn tạo. Có rất nhiều cách đơn giản để kết xuất cây vào một tệp và nhanh chóng tải lại.
Tạo một trình xác nhận ngữ nghĩa
Rất có thể ngôn ngữ của bạn cho phép các cấu trúc chính xác về mặt cú pháp có thể không có ý nghĩa trong các bối cảnh nhất định. Một ví dụ là một khai báo trùng lặp của cùng một biến hoặc truyền tham số của một loại sai. Trình xác nhận sẽ phát hiện các lỗi như vậy nhìn vào cây.
Trình xác nhận cũng sẽ giải quyết các tham chiếu đến các mô-đun khác được viết bằng ngôn ngữ của bạn, tải các mô-đun khác này và sử dụng trong quy trình xác thực. Ví dụ, bước này sẽ đảm bảo rằng số lượng tham số được truyền cho một chức năng từ một mô-đun khác là chính xác.
Một lần nữa, viết và chạy rất nhiều trường hợp thử nghiệm. Các trường hợp tầm thường là không thể thiếu trong việc khắc phục sự cố là thông minh và phức tạp.
Tạo mã
Sử dụng các kỹ thuật đơn giản nhất mà bạn biết. Thông thường, có thể dịch trực tiếp một cấu trúc ngôn ngữ (như một if
câu lệnh) sang một mẫu mã được tham số hóa nhẹ, không giống như một mẫu HTML.
Một lần nữa, bỏ qua hiệu quả và tập trung vào tính chính xác.
Nhắm mục tiêu VM cấp thấp độc lập với nền tảng
Tôi cho rằng bạn bỏ qua những thứ cấp thấp trừ khi bạn quan tâm sâu sắc đến các chi tiết cụ thể về phần cứng. Những chi tiết này là đẫm máu và phức tạp.
Lựa chọn của bạn:
- LLVM: cho phép tạo mã máy hiệu quả, thường là cho x86 và ARM.
- CLR: nhắm mục tiêu .NET, chủ yếu dựa trên x86 / Windows; có JIT tốt.
- JVM: nhắm mục tiêu thế giới Java, khá đa nền tảng, có JIT tốt.
Bỏ qua tối ưu hóa
Tối ưu hóa là khó. Hầu như luôn luôn tối ưu hóa là sớm. Tạo mã không hiệu quả nhưng đúng. Thực hiện toàn bộ ngôn ngữ trước khi bạn cố gắng tối ưu hóa mã kết quả.
Tất nhiên, tối ưu hóa tầm thường là OK để giới thiệu. Nhưng tránh mọi thứ xảo quyệt, nhiều lông trước khi trình biên dịch của bạn ổn định.
Vậy thì sao?
Nếu tất cả những thứ này không quá đáng sợ đối với bạn, vui lòng tiếp tục! Đối với một ngôn ngữ đơn giản, mỗi bước có thể đơn giản hơn bạn nghĩ.
Xem 'Thế giới xin chào' từ một chương trình mà trình biên dịch của bạn tạo ra có thể đáng để nỗ lực.