Nguồn gốc của \n
- Khi chạy lệnh
just foo, justfile sẽ ghi byte 0x0A vào một tệp có tên bar
just được viết bằng Rust, và trình phân tích của just chuyển đổi token chuỗi just có chứa escape sequence thành chuỗi UTF-8 thông qua hàm cook_string
Cách Rust xử lý
rustc xử lý mã escape trong hàm scan_escape
rustc được viết bằng Rust và tự biên dịch, nên việc hiểu ý nghĩa của '\n' được ủy thác cho rustc
- Các phiên bản đầu tiên của
rustc được viết bằng OCaml, và phiên bản rustc bằng OCaml xử lý escape ký tự trong lexer
Cách OCaml xử lý
- Trình biên dịch OCaml đánh giá
\n thành \010 rồi chèn kết quả đó vào
- Vì
0x0A là 10, nên khi trình biên dịch OCaml xử lý \n, nó thu được giá trị byte 0x0A
Kết luận
- Khi có escape ký tự
\n trong justfile, binary just sẽ ghi vào chuỗi cuối cùng với byte 0x0A được bao gồm
- Byte
0x0A này được rustc chèn vào, và điều đó bắt đầu từ việc trình biên dịch OCaml lần đầu chèn byte 0x0A vào binary rustc
Tóm tắt của GN⁺
- Bài viết này giải thích cách escape ký tự
\n được chuyển đổi thành byte 0x0A
- Lần theo nguồn gốc của byte
0x0A thông qua bối cảnh lịch sử của trình biên dịch Rust và OCaml
- Cung cấp một góc nhìn thú vị về cách trình biên dịch của các ngôn ngữ lập trình xử lý escape ký tự
- Là bài viết hữu ích để hiểu cách hoạt động của trình biên dịch Rust và OCaml
1 bình luận
Ý kiến trên Hacker News
Một người dùng nhắc rằng nơi đầu tiên họ đọc về ý tưởng này là ngày thứ 42 của bài viết "How I wrote a self-hosting C compiler in 40 days"
"\\n"trong literal chuỗi"\\n"không tự chứa thông tin mã ký tự ASCII thực tế, mà được truyền vào khi trình biên dịch biên dịch chính trình biên dịchCó ý kiến cho rằng với các hệ thống EBCDIC, cần lưu ý rằng các trình biên dịch C đời đầu đã xuất hiện trên những hệ thống không dùng ASCII
Trong chuẩn C, bảo đảm duy nhất về mã hóa ký tự là các chữ số
'0'-'9'phải được ánh xạ liên tiếp theo thứ tự tăng dầnMột người dùng nhắc đến bài diễn thuyết nhận giải Turing của Ken Thompson, "Reflections on Trusting Trust", và đoán rằng bài viết này có thể đã lấy cảm hứng từ đó
Có người thắc mắc liệu trình biên dịch clang có cùng đặc tính này không, và cho biết trong
lib/Lex/LiteralSupport.cppnó được mã hóa tường minh là 10Một người dùng tự hỏi vì sao lại cần đào sâu để hiểu lý do
"\\n"được mã hóa thành 10, vì điều đó với họ là điều hiển nhiênCó ý kiến nói bài viết này đọc như giao điểm giữa lập trình văn chương và thơ ca, khi cố gắng mô tả quá trình tạo ra byte
0x0Aqua hàng trăm chu kỳ sinh mãMột người dùng nói rằng vì ngôn ngữ C nên họ từng nghĩ
"\\0???"là escape bát phân, và hiểu"\\012"là"\\x0a"hoặc"0x0a", còn"\\010"là"0x08"Có người đặt ra câu hỏi thú vị rằng nếu ASCII hoặc chuỗi không có mã escape thì mã nguồn của chúng ta sẽ trông như thế nào
Một người dùng nhắc đến một quy tắc trong lập trình: khi có hai cách làm, và xác suất một cách đúng còn cách kia sai là 50/50, thì lúc đầu bạn nhiều khả năng sẽ chọn nhầm cách