Khiến Lua Hỗ Trợ Biến Tên Tiếng Trung Quốc
Trong quá trình triển khai hệ thống phân tích bảng dữ liệu, chúng tôi mong muốn trực tiếp nhúng các đoạn mã kịch bản vào bảng dữ liệu. Ngôn ngữ kịch bản chúng tôi sử dụng là Lua, do đó việc điền trực tiếp mã Lua vào là phương án đơn giản nhất. Tuy nhiên, các nhân sự thiết kế kịch bản nhất quyết đòi hỏi phải sử dụng tiếng Trung Quốc trong mã nguồn. Điều này gặp trở ngại vì Lua bản gốc không hỗ trợ biến tên chữ Hán. Ban đầu chúng tôi áp dụng giải pháp thay thế: xây dựng một từ điển ánh xạ các từ tiếng Trung thành phiên âm pinyin thông qua chương trình. Phương pháp này tạm thời hoạt động hiệu quả.
Trong lúc đi ăn trưa hôm qua, tôi chợt nảy ra ý tưởng mới và dành cả chiều để hiện thực hóa nó. Thực ra việc điều chỉnh bộ phân tích cú pháp của Lua để hỗ trợ chữ Hán không hề phức tạp. Tuy nhiên tôi không muốn can thiệp sâu vào lõi Lua bằng cách vá mã nguồn, bởi điều đó sẽ tạo ra một “phương ngữ” Lua riêng biệt cho dự án. Thay vào đó, tôi quyết định tiếp cận vấn đề theo hướng xử lý mã kịch bản từ bảng dữ liệu như một ngôn ngữ DSL (Domain Specific Language), tương tự cách tôi đã áp dụng cho hệ thống phân tích công thức trước đây. Phương pháp này giới hạn phạm vi ảnh hưởng của sự thay đổi, tránh lan rộng ra toàn bộ hệ thống.
Việc hỗ trợ biến tên tiếng Trung Quốc thực chất chỉ là vấn đề phân tích cú pháp. Khi mã nguồn đã được biên dịch thành bytecode, vấn đề này không còn tồn tại. Điều đó có nghĩa là khi chúng tôi chỉnh sửa Lua để hỗ trợ biến tên chữ Hán, bytecode được tạo ra hoàn toàn tương thích với môi trường Lua chưa chỉnh sửa - bao gồm cả thông tin gỡ lỗi.
Chúng tôi đã tích hợp một máy ảo Lua được sửa đổi dưới dạng thư viện vào môi trường Lua hiện tại. Bộ phân tích Lua được sửa đổi này sẽ xử lý mã kịch bản trích xuất từ bảng dữ liệu, biên dịch thành bytecode, sau đó chạy các bytecode này trong môi trường chính. May mắn thay, trước đó chúng tôi đã xây dựng hệ thống cơ sở dữ liệu đa trạng thái chia sẻ, hoàn toàn có thể sử dụng máy ảo Lua sửa đổi trong quá trình khởi tạo cơ sở dữ liệu.
Việc nhúng hai phiên bản Lua khác nhau vào cùng một môi trường yêu cầu thiết lập liên kết thư viện hết sức cẩn trọng do chúng sử dụng chung API. Giải pháp của tôi là định nghĩa một nhóm giao diện C đặc biệt chỉ dành cho biên dịch mã nguồn:
|
|
Trong đó, struct code_state
thực chất là lua_State
nhưng được đổi tên để phân biệt. Khi khởi tạo, tôi truyền vùng nhớ cần thiết từ bên ngoài để kiểm soát hiệu quả thông qua cơ chế phân bổ bộ nhớ tùy chỉnh (tận dụng chức năng lua_Alloc). Cách tiếp cận này đảm bảo máy ảo Lua độc lập vừa hiệu quả vừa dễ kiểm soát tài nguyên.
Nhóm API này được triển khai trong một thư viện động riêng biệt, liên kết tĩnh với phiên bản Lua đã sửa đổi mà không xuất bất kỳ hàm API nào liên quan đến Lua. Nhờ đó, nó hoàn toàn tách biệt khỏi môi trường Lua chính. Giai đoạn tiếp theo là xây dựng một thư viện mở rộng Lua tiêu chuẩn, liên kết động với nhóm API trên để dễ dàng tải các mã kịch bản tiếng Trung Quốc vào môi trường Lua mẹ.
Để sửa đổi Lua hỗ trợ biến tên tiếng Trung Quốc, trước tiên cần hiểu rõ cấu trúc mã nguồn Lua. Với Lua 5.2, logic phân tích cú pháp nằm trong file llex.c, nhưng thực tế không cần chỉnh sửa file này. Lua sử dụng hai hàm lislalpha
và lislalnum
để xác định tính hợp lệ của tên biến. Hai hàm này được định nghĩa trong lctype.h, đây mới là file cần điều chỉnh.
Tôi hy vọng Lua có thể nhận diện các ký tự tiếng Trung Quốc trong mã UTF-8 qua hàm lislalpha
. Dựa trên quy tắc mã hóa UTF-8, tôi tạm thời xác định các khoảng byte từ 0x80-0xbf và 0xe0-0xef chứa các ký tự tiếng Trung Quốc (dù cách xác định này chưa hoàn toàn chính xác nhưng đủ dùng cho dự án).
Lua cung cấp hai phiên bản lislalpha
tùy theo cấu hình: phiên bản dùng bảng tra cứu tối ưu cho ASCII và phiên bản gọi hàm isalpha
hệ thống. Với phiên bản bảng tra, tôi điều chỉnh trực tiếp file lctype.c bằng cách sửa đổi bảng mã 16x16 byte. Mỗi ô trong bảng này chứa các bit đánh dấu thuộc tính ký tự (ALPHA, số, hex, khả năng in được…). Tôi cập nhật các hàng từ 8 đến B và hàng E để đánh dấu các ký tự này là chữ (0x01) và có thể in được (0x05).