Dự án cuối tuần của một cựu CTO Stripe để xây dựng trình biên dịch BASIC-to-Go đã châm ngòi cho một cuộc thảo luận sôi nổi trong cộng đồng lập trình về các phương pháp tốt nhất để xây dựng parser ngôn ngữ và điều gì thực sự tạo nên một trình biên dịch.
David Singleton đã chia sẻ trải nghiệm tạo ra toybasic, một phiên bản đơn giản hóa của TinyBASIC có thể biên dịch thành mã Go. Dự án chỉ mất vài giờ vào một thứ Bảy mưa, chứng minh rằng các công cụ hiện đại có thể làm cho việc xây dựng trình biên dịch trở nên dễ tiếp cận một cách đáng ngạc nhiên. Trình biên dịch của anh ấy tuân theo phương pháp ba giai đoạn cổ điển: phân tích từ vựng, phân tích cú pháp và tạo mã.
Các Thành Phần Kiến Trúc Trình Biên Dịch:
- Lexer: Chuyển đổi các ký tự mã nguồn thành các token có ý nghĩa bằng cách sử dụng Deterministic Finite Automata
- Parser: Xây dựng cây cú pháp từ các token và xác thực cấu trúc chương trình
- Code Generator: Duyệt qua cây cú pháp và xuất ra mã Go tương đương
Cuộc tranh luận lớn về Parser
Dự án đã khơi mào một sự chia rẽ thú vị trong cộng đồng phát triển về các phương pháp xây dựng parser. Một số lập trình viên có kinh nghiệm ủng hộ mạnh mẽ việc viết parser bằng tay, cho rằng chúng dễ viết và debug hơn nhiều người nghĩ. Họ chỉ ra rằng việc phân tích cú pháp thủ công cho phép tạo ra thông báo lỗi tốt hơn và mang lại cho lập trình viên nhiều quyền kiểm soát hơn đối với quá trình này.
Tuy nhiên, những người khác phản bác rằng khi bạn đang thử nghiệm với các ý tưởng ngôn ngữ mới, các trình tạo parser trở nên vô cùng có giá trị. Khả năng lặp lại nhanh chóng trên cú pháp mà không cần viết lại mã phân tích cú pháp bằng tay có thể tiết kiệm đáng kể thời gian phát triển. Một lập trình viên lưu ý rằng họ đã dành 80% thời gian thiết kế ngôn ngữ chỉ để viết và debug parser khi làm mọi thứ thủ công.
Sự căng thẳng giữa kiểm soát và tiện lợi này phản ánh một chủ đề rộng hơn trong phát triển phần mềm - liệu có nên sử dụng các công cụ tự động hay duy trì quyền kiểm soát trực tiếp đối với mọi khía cạnh của mã.
Điều gì tạo nên một trình biên dịch?
Một cuộc thảo luận bất ngờ đã nổi lên xung quanh thuật ngữ. Một số thành viên cộng đồng đặt câu hỏi liệu việc dịch BASIC sang Go có nên được gọi là trình biên dịch thay vì transpiler, vì nó không tạo ra mã máy trực tiếp. Điều này đã khơi mào một cuộc tranh luận hấp dẫn về các định nghĩa trong khoa học máy tính.
Sự đồng thuận dường như là bất kỳ chương trình nào dịch từ ngôn ngữ này sang ngôn ngữ khác đều đủ điều kiện là một trình biên dịch, bất kể ngôn ngữ đích là gì. Sau cả, nhiều trình biên dịch hiện đại xuất ra các biểu diễn trung gian hoặc bytecode thay vì các lệnh máy trực tiếp. Sự phân biệt giữa trình biên dịch và transpiler có vẻ mang tính học thuật hơn là thực tế.
Sức hấp dẫn bền bỉ của BASIC
Việc lựa chọn BASIC làm ngôn ngữ nguồn đã gây tiếng vang với nhiều lập trình viên vẫn còn nhớ nó như ngôn ngữ lập trình đầu tiên của họ. Bất chấp danh tiếng của BASIC trong một số nhóm, các thành viên cộng đồng đã nhấn mạnh khả năng tiếp cận đáng chú ý của nó - một ngôn ngữ mà các sinh viên chuyên ngành nhân văn có thể học trong một buổi chiều, nhưng vẫn đủ mạnh mẽ cho lập trình nghiêm túc.
Các biến thể BASIC hiện đại đã vượt xa mã có số dòng, nặng về GOTO khiến ngôn ngữ này có danh tiếng xấu. Nhiều lập trình viên đã chia sẻ những trải nghiệm tích cực với các phương ngữ BASIC có cấu trúc bao gồm luồng điều khiển thích hợp và các tính năng lập trình mô-đun.
Dự án này vừa là một chuyến đi hoài niệm vừa là một minh chứng thực tế rằng việc xây dựng trình biên dịch không nhất thiết phải đáng sợ. Với các công cụ phù hợp và hiểu biết rõ ràng về các nguyên tắc cơ bản, ngay cả những nhiệm vụ có vẻ phức tạp như xây dựng trình biên dịch cũng có thể trở thành một dự án cuối tuần thú vị.
Tham khảo: I wrote a compiler