Có rất nhiều ngôn ngữ lập trình hỗ trợ việc bao gồm các ngôn ngữ mini. PHP được nhúng trong HTML. XML có thể được nhúng trong JavaScript. LINQ có thể được nhúng trong C#. Biểu thức chính quy có thể được nhúng trong Perl.Ngữ pháp tổng hợp
// JavaScript example
var a = <node><child/></node>
Nghĩ về điều đó, hầu hết các ngôn ngữ lập trình đều có thể được mô hình hóa thành các ngôn ngữ mini khác nhau. Java, ví dụ, có thể được chia thành một ít nhất bốn biệt mini-ngôn ngữ:
- Một langauge type-khai (gói chỉ thị, chỉ thị nhập khẩu, khai báo lớp)
- Một ngôn ngữ thành viên khai (bổ truy cập, khai báo phương thức, thành viên vars)
- Một ngôn ngữ statement (dòng điều khiển, thực hiện tuần tự)
- Một ngôn ngữ biểu thức (literals, bài tập, so sánh, số học)
có thể để thực hiện bốn ngôn ngữ khái niệm đó thành bốn ngữ pháp riêng biệt, chắc chắn sẽ cắt giảm rất nhiều tính spaghetti mà tôi thường thấy trong phân tích cú pháp phức tạp và triển khai trình biên dịch.
Tôi đã triển khai các trình phân tích cú pháp cho các loại ngôn ngữ khác nhau trước đây (sử dụng trình phân tích cú pháp gốc, JavaCC và tùy chỉnh đệ quy) và khi ngôn ngữ trở nên thực sự lớn và phức tạp, bạn thường kết thúc bằng một ngữ pháp huuuuuuge. việc triển khai trình phân tích cú pháp thực sự rất xấu.
Lý tưởng nhất là khi viết một trình phân tích cú pháp cho một trong các ngôn ngữ đó, thật tuyệt khi thực hiện nó như một bộ sưu tập các trình phân tích cú pháp có thể kết hợp, chuyển điều khiển qua lại giữa chúng.
Điều phức tạp là thường xuyên, ngôn ngữ có chứa (ví dụ: Perl) xác định dấu gửi cuối của riêng nó cho ngôn ngữ được chứa (ví dụ: biểu thức chính quy). Dưới đây là ví dụ tốt:
my $result ~= m|abc.*xyz|i;
Trong mã này, mã perl chính xác định một điểm cuối không chuẩn "|" cho cụm từ thông dụng. Việc thực hiện trình phân tích cú pháp regex hoàn toàn khác biệt với trình phân tích cú pháp perl sẽ thực sự khó, vì trình phân tích cú pháp regex sẽ không biết cách tìm cụm từ biểu thức mà không tham khảo bộ phân tích cú pháp gốc.
Hoặc, cho phép nói rằng tôi đã có một ngôn ngữ cho phép sự bao gồm các biểu thức LINQ, nhưng thay vì kết thúc với một dấu chấm phẩy (như C# không), tôi muốn uỷ quyền cho các biểu thức LINQ xuất hiện trong dấu ngoặc vuông:
var linq_expression = [from n in numbers where n < 5 select n]
Nếu tôi đã xác định ngữ pháp LINQ trong ngữ pháp ngôn ngữ gốc, tôi có thể dễ dàng viết một sản xuất rõ ràng cho một "LinqExpression" bằng cách sử dụng cú pháp lookahead để tìm khung giá đỡ. Nhưng sau đó ngữ pháp của cha mẹ tôi sẽ phải hấp thụ toàn bộ đặc điểm kỹ thuật của LINQ. Và đó là một kéo. Mặt khác, một trình phân tích cú pháp Linq con riêng biệt sẽ có một thời gian rất khó khăn để tìm ra nơi dừng lại, vì nó sẽ cần phải thực hiện lookahead cho các loại token ngoài.
Và điều đó sẽ loại trừ khá nhiều bằng cách sử dụng các giai đoạn lexing/phân tích cú pháp riêng biệt, vì trình phân tích cú pháp LINQ sẽ xác định toàn bộ các quy tắc mã thông báo khác với trình phân tích cú pháp gốc. Nếu bạn đang quét tìm một mã thông báo tại một thời điểm, làm thế nào để bạn biết khi nào cần chuyển quyền kiểm soát trở lại trình phân tích từ vựng của ngôn ngữ gốc?
Các bạn nghĩ sao?Các kỹ thuật tốt nhất hiện nay có sẵn để thực hiện các ngữ pháp ngôn ngữ riêng biệt, tách rời và tổng hợp cho việc bao gồm các ngôn ngữ nhỏ trong ngôn ngữ mẹ lớn hơn là gì?
OMeta có điều này! Bạn có thể soạn nhiều ngữ pháp cùng nhau hoặc thậm chí kế thừa các ngữ pháp hiện có theo kiểu OOP. – CMCDragonkai