Trong thế giới lập trình, biểu thức S (hay biểu thức tượng trưng) là biểu diễn của dữ liệu danh sách lồng nhau (cấu trúc cây). Cách biểu diễn này lần đầu tiên được đề xuất và phổ biến bởi ngôn ngữ lập trình Lisp và đã được sử dụng rộng rãi trong cả mã nguồn và dữ liệu của ngôn ngữ này. Biểu thức S là một cuộc cách mạng trong lập trình và biểu diễn cấu trúc dữ liệu. Chúng ta hãy cùng xem xét kỹ hơn các tính năng và cách sử dụng chính của nó.
Trong cú pháp ngoặc truyền thống của Lisp, định nghĩa của biểu thức S khá đơn giản: nó có thể là một nguyên tử hoặc một biểu thức có dạng (x . y), trong đó x và y là các biểu thức S. Định nghĩa này phản ánh khái niệm của Lisp về việc biểu diễn một danh sách dưới dạng một chuỗi "ô", mỗi ô là một cặp có thứ tự.
Định nghĩa đệ quy này có nghĩa là cả biểu thức S và danh sách đều có thể biểu diễn bất kỳ cây nhị phân nào.
Ngoài ra, các phương ngữ Lisp hiện đại như Common Lisp và Scheme cung cấp cú pháp sử dụng thẻ dữ liệu để chỉ ra cấu trúc chung của các đối tượng, cho phép các biểu thức mang theo các chu kỳ tham chiếu mà không gây ra đệ quy vô hạn.
Dạng ngữ pháp của biểu thức S có nhiều biến thể để hỗ trợ biểu diễn các kiểu dữ liệu khác nhau. Những loại phổ biến nhất bao gồm:
Do đó, ký tự # thường được dùng để thêm tiền tố vào phần mở rộng cú pháp, ví dụ, #x10 cho số nguyên thập lục phân hoặc #\C cho một ký tự.
Trong Lisp, khi thể hiện mã nguồn, phần tử đầu tiên của biểu thức S thường là tên toán tử hoặc hàm và các phần tử sau được coi là tham số. Đây được gọi là "ký hiệu tiền tố" hoặc "ký hiệu Ba Lan". Ví dụ, biểu thức Boolean C 4 == (2 + 2) được biểu diễn trong biểu thức S của Lisp là (= 4 (+ 2 2)).
Định nghĩa chính xác về "atom" khác nhau giữa các ngôn ngữ cùng họ với Lisp; chuỗi được trích dẫn thường có thể chứa bất kỳ ký tự nào, nhưng các định danh không được trích dẫn không thể chứa dấu ngoặc kép, ký tự khoảng trắng, dấu ngoặc đơn và các ký tự đặc biệt khác.
Biểu thức S được đọc thông qua hàm READ và hàm PRINT được sử dụng để xuất ra biểu thức S. Khả năng đọc và ghi lẫn nhau này làm cho các chương trình Lisp không chỉ là biểu diễn của mã nguồn mà còn là các cấu trúc dữ liệu có thể xử lý được. Chương trình Lisp có thể được định dạng thành biểu thức S đẹp mắt và xuất ra nhiều định dạng khác nhau thông qua hàm PPRINT.
Trong việc sử dụng biểu thức S, một so sánh quan trọng là sự khác biệt của nó với XML: Biểu thức S chỉ có một dạng bao gồm, tức là cặp dấu chấm, trong khi thẻ XML có thể chứa các thuộc tính đơn giản, các thẻ khác hoặc CDATA. Biểu thức S đơn giản hơn XML trong các trường hợp sử dụng đơn giản, nhưng trong các ứng dụng nâng cao, XML cung cấp các ngôn ngữ truy vấn như XPath, giúp các công cụ và thư viện xử lý dữ liệu XML có nhiều lợi thế hơn.
Nhiều ngôn ngữ lập trình bắt nguồn từ Lisp có thông số cú pháp biểu thức S riêng, bao gồm Common Lisp (ANSI INCITS 226-1994 (R2004)), Scheme (R5RS và R6RS) và ISLISP. Mặc dù Bản thảo Internet do Ron Rivest đề xuất năm 1997 không trở thành RFC, nhưng các thông số kỹ thuật lưu trữ và trao đổi dữ liệu chung được định nghĩa dựa trên biểu thức S của Lisp vẫn được trích dẫn và sử dụng trong các tài liệu khác.
Rivest định nghĩa định dạng này là một chuỗi octet hoặc một danh sách hữu hạn các biểu thức S khác và mô tả các định dạng truyền của ba cấu trúc biểu thức.
Những phát triển này chắc chắn đã thúc đẩy việc ứng dụng biểu thức S trong trao đổi và phân tích dữ liệu, cũng như tính phổ biến và linh hoạt của lập trình. Thông qua những phát triển chuẩn hóa này, chúng ta thấy được vai trò quan trọng của biểu thức S trong thế hệ lập trình tiếp theo.
Tóm lại, trạng thái của biểu thức S trong Lisp không chỉ là yêu cầu về ngữ pháp mà còn là sự trình bày tích hợp của cấu trúc dữ liệu và mã nguồn. Nó thách thức quan điểm vốn có của chúng ta về ngôn ngữ lập trình. Vậy, liệu biểu thức S có thể tìm thấy ứng dụng và ý nghĩa mới trong lập trình trong tương lai không?