Ngôn ngữ này được sinh ra từ một văn phạm phi ngữ cảnh, vì thế ta thấy rằng họ của những ngôn ngữ chính qui là một tập con đúng của họ ngôn ngữ phi ngữ cảnh, nghĩa là văn phạm chính qui
Trang 1Chương 5
NGÔN NGỮ PHI NGỮ CẢNH
Trong những chương trước, chúng ta đã nhận thấy rằng không phải tất cả ngôn ngữ đều là chính qui Chỉ vì các ngôn ngữ chính qui có hiệu quả trong việc mô tả những trường hợp đơn giản, nên người ta không quan tâm đến những ví dụ về ngôn ngữ không chính qui Tuy nhiên trong ngôn ngữ lập trình, nó đòi hỏi phải mở rộng họ ngôn ngữ chính qui Điều này dẫn đến ngôn ngữ và văn phạm phi ngữ cảnh
Chúng ta bắt đầu chương này với định nghĩa văn phạm và ngôn ngữ phi ngữ cảnh, bằng những ví dụ đơn giản Tiếp đến, chúng ta tìm hiểu các vấn đề có liên quan Cụ thể chúng ta hỏi rằng nếu cho trước một chuỗi, thì chuỗi đó được sinh ra từ văn phạm nào đã biết Giải thích một câu mà thông qua một văn phạm thì rất quen thuộc với chúng ta Trong ngôn ngữ tự nhiên, ta gọi việc đó là phân tích cú pháp (Parsing) Parsing là phương pháp mô tả cấu trúc một câu Phân tích cú pháp là điều tối cần trong nhiều lãnh vực của máy tính như : dịch từ một ngôn ngữ này sang một ngôn ngữ khác, xây dựng trình biên dịch, trình thông dịch và những chương trình dịch khác
Chủ đề của ngôn ngữ phi ngữ cảnh là chủ đề quan trọng nhất của lý thuyết ngôn ngữ hình thức, vì nó áp dụng cho ngôn ngữ lập trình Ngôn ngữ lập trình có nhiều chức năng và liên kết với những dạng của ngôn ngữ phi ngữ cảnh Lý thuyết ngôn ngữ hình thức cho ta những áp dụng quan trọng trong việc thiết kế ngôn ngữ lập trình cũng như viết những trình biên dịch
5.1 VĂN PHẠM PHI NGỮ CẢNH
Các luật sinh trong văn phạm chính quy bị hạn chế cả vế trái và vế phải Để tạo ra những văn phạm có nhiều tính năng hơn, chúng ta phải lược bỏ một số những hạn chế này Bằng các giữ lại hạn chế bên vế trái, nhưng cho phép tự do bên vế phải Khi đó, chúng ta được văn phạm phi ngữ cảnh
Trang 2Định nghĩa 5.1
Một văn phạm G = (V, T, S, P) được gọi là phi ngữ cảnh nếu tất cả luật sinh trong P có dạng
A-> x
Với A ∈V và x ∈ (V U T) *
Một ngôn ngữ L được gọi là phi ngữ cảnh nếu và chỉ nếu có một văn phạm
phi ngữ cảnh G sao cho L = L (G)
Mọi văn phạm chính qui là phi ngữ cảnh, do vậy một ngôn ngữ chính qui cũng
là phi ngữ cảnh Nhưng như chúng ta đã biết {a n b n} là môt ngôn ngữ không chính qui Ngôn ngữ này được sinh ra từ một văn phạm phi ngữ cảnh, vì thế ta thấy rằng họ của những ngôn ngữ chính qui là một tập con đúng của họ ngôn ngữ phi ngữ cảnh, nghĩa là văn phạm chính qui thụộc về ngôn ngữ phi ngữ cảnh
Các ví dụ của ngôn ngữ phi ngữ cảnh
Ví dụ 5.1
Cho ngôn ngữ G = ({S},{a,b},S, P ), với các luật sinh
S -> aSa
S -> bSb
S -> λ,
Là phi ngữ cảnh Một dẫn xuất cho văn phạm trên là
S => aSa => aaSaa => aabSbaa => aabbaa
Điều này dễ thấy rằng
L(G) = {ww R , w ∈ (a,b) * }
Ngôn ngữ này là phi ngữ cảnh, nhưng không chính qui
Ví dụ 5.2
Cho văn phạm G, với các luật sinh
S -> abB
A -> aaBb
B -> bbAa
A -> λ
là phi ngữ cảnh
Trang 3Hãy chỉ ra rằng L(G) = {ab(bbaa) n bba(ba) n : n ≥ 0} (coi như bài tập)
Cả hai ví dụ ở trên đều bao gồm các văn phạm mà không chỉ là phi ngữ cảnh, mà còn tuyến tính, những văn phạm chính qui và tuyến tính thì rõ ràng là
phi ngữ cảnh, nhưng văn phạm phi ngữ cảnh không nhất thiết phải tuyến tính.
Ví dụ 5.3
Ngôn ngữ L = {a n b m : m ≠ n }
Là phi ngữ cảnh
Để thấy được vấn đề này, chúng ta tìm một văn phạm phi ngữ cảnh cho
ngôn ngữ đó Trườâng hợp m = n đã được giải quyết trong ví dụ 1.5 và chúng ta
có thể xây dựng lời giải trên cơ sở đó
Trường hợp m < n , chúng ta tạo ra một chuỗi với số lương kí tự a và kí tự
b bằng nhau, sau đó thêm vào các kí tự a ở vế trái như sau
S AS1
S 1 aS1 b | λ
A aA |a.
Một cách tương tự như trên, trường hợp n < m, ta có câu trả lời
S AS1 | S1B
S 1 -> aS1b| λ,
A -> aA| a,
B -> bB| b.
Kết quả là văn phạm phi ngữ cảnh, do đó L là ngôn ngữ phi ngữ cảnh Tuy nhiên
văn phạm thì không tuyến tính
Ví dụ 5.4
Xem xét văn phạm với luật sinh
S aSb | SS | λ Đây là văn phạm phi ngữ cảnh, nhưng không tuyến tính Một vài chuỗi trong
L(G) là abaabb, aababb, và ababab Không khó để ta phỏng đoán và chứng
minh rằng
L = {w∈ {a,b} * : n a (w) = n b (w) và n a (v) ≥ n b (v)}
(với v là tiền tố của w bất kỳ )
Chúng ta dễ thấy mối liên kết với các ngôn ngữ lập trình, nếu chúng ta
thay thế a và b bởi các dấu mở ngoặc và đóng ngoặc tương ứng Ngôn ngữ L
Trang 41 22 3 4 5
bao gồm chuỗi như (( )) và ( )( )( ) và thật ra là việc lồng dấu ngoặc trong ngôn ngữ lập trình
Dẫn xuất trái nhất và dẫn xuất phải nhất
Trong văn phạm phi ngữ cảnh không tuyến tính, một dẫn xuất có thể bao gồm những hình thức câu có nhiều hơn một biến Trong những trường hợp như vậy, chúng ta có thể chọn cách để thay thế các biến
Lấy ví dụ văn phạm G = ({A, B, S},{a,b},S,P ) với các luật sinh
1 S AB,
2 A aaA
3 A λ.
4 B Bb
5 B λ Dễ thấy rằng văn phạm này sinh ra ngôn ngữ L(G) ={ a 2n b m : n ≥ 0, m ≥ 0 }
Bây giờ ta xem hai dẫn xuất
S ⇒ AB ⇒ aaAB ⇒ aaB ⇒ aaBb ⇒ aab
Và
S ⇒ AB ⇒ ABb ⇒ aaABb ⇒ aaAb ⇒ aab.
Để chỉ ra dẫn xuất nào được sử dụng, chúng ta đánh số các luật sinh và viết
số tương ứng lên trên kí hiệu ⇒ Từ đây chúng ta thấy rằng hai dẫn xuất không chỉ là cho kết quả cùng một câu mà còn sử dụng những luật sinh như nhau Sự khác nhau chỉ là trong thứ tự luật sinh được áp dụng, Để loại bỏ đi những nhân tố không thích hợp này, chúng ta thường yêu cầu các biến được thay thế theo một thứ tự cụ thể
Định nghĩa 5.2
Một dẫn xuất được gọi là trái nhất ( leftmost derivation) nếu trong mỗi bước biến bên trái nhất trong dạng câu được thay thế Nếu biến bên phải nhất được thay thế, chúng ta gọi là dẫn xuất phải nhất (rightmost derivation)
Trang 5
-Ví dụ 5.5 Xét văn phạm với các luật sinh
S -> aAB
A -> bBb
B -> A | λ
Thì
S ⇒ aAB ⇒ abBbB ⇒ abAbB ⇒ abbBbbB ⇒ abbbbB ⇒ abbbb
là một dẫn xuất trái nhất của chuỗi abbbb Một dẫn xuất phải nhất của
cùng một chuỗi này là :
S ⇒ aAB ⇒ aA ⇒ abBb ⇒ abAb ⇒ abbBbb ⇒ abbbb
Cây dẫn xuất
Một cách thứ hai để trình bày các dẫn xuất, độc lập với thứ tự các luật sinh được áp dụng, là cây dẫn xuất Một cây dẫn xuất là cây có thứ tự, trong đó mỗi nút được gán nhãn là vế trái của luật sinh, các con của các nút đó biểu diễn vế phải tương ứng Ví dụ, hình 5.1 trình bày một phần của cây dẫn xuất biểu diễn luật sinh
A -> abABc
A
a b A B c
Trong cây dẫn xuất, nút được gán nhãn với biến bên trái của luật sinh có con là những kí tự bên phải của luật sinh Bắt đầu, gốc được gán nhãn với kí hiệu khởi đầu và lá là kí hiệu kết thúc, cây dẫn xuất chỉ ra cách mà mỗi biến được thay thế trong dẫn xuất
Định nghĩa 5.3
Cho G = ( V, T, S, P) là một văn phạm phi ngữ cảnh Mộât cây cĩ thứ tự là cây
dẫn xuất cho G nếu và chỉ nếu nó có các tính chất sau
1 Gốc được gán nhãn là S.
2 Mỗi lá có một nhãn lấy từ T ∪ {λ}
3 Mỗi nút bên trong (không phải là nút lá) có một nhãn lấy từ V.
4 Nếu mỗi nút có nhãn là A ∈ V, và các con của nó được gán nhãn (từ trái
sang phải) a1, a 2 , , a n , thì P phải chứa một luật sinh có dạng
A -> a1a 2 a n
5 Một lá không có anh em được gán nhãn là λ, nghĩa là nút có một con được
Hình 5.1
Trang 6gán nhãn là λ khi không có con nào khác.
Một cây mà có các tính chất 3, 4 và 5, nhưng trong đó không nhất thiết có tính chất 1 và 2 được thay thế bằng:
2a Mỗi lá có nhãn lấy từ V ∪ T∪{λ}
thì được gọi là cây dẫn xuất riêng phần
Chuỗi kí hiệu nhận bằng cách đọc các nút lá của cây từ trái sang phải, bỏ qua bất kỳ λ nào, là kết quả của cây
-Ví dụ 5.6 Xét văn phạm G, với các luật sinh
S -> aAB,
A -> bBb,
B -> A |λ,
Cây trong hình 5.2 là cây dẫn xuất riêng phần cho G, trong khi cây
trong hình 5.3 là một cây dẫn xuất Kết quả của cây thứ nhất là chuỗi
abBbB chính là một dạng câu của G Kết quả của cây thứ hai, abbbb là một câu của L(G).
Hình 5.2
Hình 5.3
S
Trang 7Quan hệ giữa dạng câu và cây dẫn xuất
Cây dẫn xuất dùng mô tả một cách tường minh những dẫn xuất Tuy nhiên, chúng ta phải thiết lập sự kết nối giữa dẫn xuất và cây dẫn xuất
Định Lý 5.1
Cho G = ( V, T, S, P ) là một văn phạm phi ngữ cảnh Thì với mỗi
w ∈ L(G), tồn tại một cây dẫn xuất của G mà kết quả của nó là w Ngược lại, kết quả của một cây dẫn xuất bất kì là thuộc L(G) Cũng vậyï, nếu t G là
cây dẫn xuất riêng phần bất kì của G mà gốc của nó được gán nhãn là S thì kết quả của tG là một dạng câu của G.
BÀI TẬP
1 Tìm văn phạm phi ngữ cảnh cho ngôn ngữ ( n, m ≥ 0)
a) L = { a n b m : m + 3 ≥ n }
b) L = { a n b m : n = 2m }
2 Tìm cây dẫn xuất cho chuỗi aabbbb với văn phạm
S -> AB|λ
A -> aB
B -> Sb
Mô tả ngôn ngữ được sinh bởi văn phạm này
3 Cho văn phạm với luật sinh
S -> aaB
A -> bBb|λ
B -> Aa Chỉ ra rằng chuỗi aabbabba không phải là ngôn ngữ được sinh bởi văn phạm này
Trang 85.2 PHÂN TÍCH CÚ PHÁP VÀ TÍNH NHẬP NHẰNG
Chúng ta đã tìm hiểu, có văn phạm G, từ G cho chúng ta những chuỗi được
sinh ra từ nó Trong các ứng dụng thực tế, chúng ta cũng cần quan tâm đến vấn đề
phân tích văn phạm, nghĩa là, cho một chuỗi w, chúng ta muốn biết w có được sinh ra bởi L(G) hay không Nếu được sinh ra bởi L(G), khi đó có thể tìm một dẫn xuất cho
w Giải thuật để xác định w thuộc L(G) được gọi là giải thuật thành viên Thuật ngữ phân tích cú pháp (parsing) là tìm một dãy các luật sinh mà một chuỗi w ∈ L(G)
được dẫn xuất ra
Phân tích cú pháp và thành viên
Cho một chuỗi w thuộc L(G), chúng ta có thể phân tích cú pháp nó Nghĩa là đi tìm một dẫn xuất nào đó có dẫn ra chuỗi w hay không, cách thực hiện là : Ở
lượt thứ nhất xem xét các các luật sinh có dạng
S x
tìm tất cả những x mà có thể được dẫn xuất từ S trong luật này Nếu không tìm
được, ta đi đến lượt tiếp theo, áp dụng các luật sinh có thể dẫn đến biến bên trái nhất
của mỗi x Thao tác này sẽ cho ta một tập các dạng câu, một vài dạng câu trong đó có khả năng dẫn tới w.
Trong mỗi lượt kế tiếp, chúng ta lại lấy tất cả các biến trái nhất và áp dụng tất cả các luật sinh có thể Có thể rằng một số trong các dạng câu này có thể bị từ chối
vì lý do rằng w không bao giờ có thể được dẫn xuất từ chúng Sau lượt đầu tiên, chúng ta có thể có các dạng câu mà có thể được dẫn xuất từ S bằng cách áp dụng
một luật sinh, sau lượt thứ hai chúng ta có các dạng câu mà có thể được dẫn xuất từ
S với hai luật sinh, tiếp tục như thế Nếu w∈ L(G) thì nó phải có một dẫn xuất trái
nhất có độ dài hữu hạn Vì vậy phương pháp này, cuối cùng sẽ tìm ra được một dẫn
xuất trái nhất của w.
Chúng ta gọi phương pháp này là phương pháp phân tích cú pháp vét cạn, nó thuộc dạng phân tích cú pháp từ trên xuống
Ví dụ 5.7
Xét văn phạm
S SS | aSb | bSa| λ
và chuỗi w = aabb Ở lượt thứ nhất cho ta
1 S => SS
2 S => aSb
3 S => bSa
4 S => λ
Trang 9
Hai trường hợp 3 và 4 có thể loại bỏ, vì không thể dẫn xuất ra được w
Tiếp tục lượt thứ hai với trường hợp 1 và 2 ta có các dạng câu sau:
( thay những biến S bên trái của vế phải bằng những luật sinh )
S => SS => SSS
S => SS => aSbS
S => SS => bSaS
S => SS => S
Tương tự , ta loại bỏ những trường hợp mà dạng câu không thể khớp với w,
áp dụng những luật sinh có thể cho những trường hợp còn lại,
ta có những dạng câu có thể là:
S => aSb => aSSb
S => aSb => aaSbb
S => aSb => abSab
S => aSb => ab
Một lần nữa, ta thấy có thể loại bỏû một vài dạng câu theo như trên Trên lượt kế tiếp ta tìm thấy chuỗi
S => aSb => aaSbb => aabb
Vì vậy, aabb thuộc ngôn ngữ được sinh ra bởi văn phạm đang xét.
Phương pháp phân tích cú pháp vét cạn có một số nhược điểm, kém hiệu
qủa Điều khá quan trọng là, phương pháp này luôn phân tích ra được những chuỗi w
∈ L(G), nếu chuỗi không thuộc L(G), phương pháp này có thể không dừng Chẳng
hạn với w = abb phương pháp này sẽ đi đến việc sinh ra vô hạn các dạng câu mà
không dừng lại, trừ phi, chúng ta xây dựng thêm trong nó một cách nào đó để dừng lại
Vấn đề không kết thúc của phương pháp phân tích cú pháp vét cạn là tương đối dễ khắc phục, nếu chúng ta giới hạn dạng mà văn phạm có thể có Nếu chúng ta
khảo sát ví dụ 5.7 chúng ta thấy rằng khó để áp dụng được luật sinh S λ, luật sinh này có thể sử dụng để làm giảm độ dài của các dạng câu kế tiếp Vì vậy không thể nói một cách dễ dàng, khi nào phương pháp này dừng lại, nếu chúng ta không có bất kỳ luật sinh nào như vậy Thực tế có hai luật sinh chúng ta muốn loại trừ: những luật sinh dạng A λ cũng như các luật sinh có dạng A B Như chúng ta sẽ thấy trong
chương tiếp theo, sự giới hạn này (loại trừ các luật sinh nói trên) không ảnh hưởng đến kết qủa của những văn phạm về bất kỳ khía cạnh nào
Trang 10Ví dụ 5.8
Cho văn phạm
S SS | aSb | bSa | ab | ba
Thỏa mãn các yêu cầu đã nêu Nó sinh ra ngôn ngữ trong ví dụ 5.7 không
có chuỗi rỗng
Cho một chuỗi bất kỳ w∈ {a,b}+ , phương pháp phân tích cú pháp vét cạn sẽ luôn luôn kết thúc sau không quá |w| lượt Điều này rõ ràng vì chiều dài
của dạng câu tăng ít nhất là một kí hiệu sau mỗi lượt
Sau |w| lượt , ta có kết qủa w có thuộc L(G) hay không.
Ý tưởng trong ví dụ này có thể đưa ra định lý sau cho ngôn ngữ phi ngữ
cảnh
Định lý 5.2
Giả sử rằng G = ( V, T, S, P ) là một văn phạm phi ngữ cảnh mà không có
bất kỳ luật sinh nào có dạng:
A λ
hay A B
Trong đó: A, B ∈ V thì phương pháp phân tích cú pháp vét cạn có thể tạo
thành thành một giải thuật mà đối với bất kỳ w ∈ ∑* hoặc tạo ra được sự phân
tích cú pháp của w hoặc cho ta biết không có sự phân tích cú pháp nào có
thểù
Chứng minh
Với mỗi dạng câu, xét chiều dài và số kí hiệu kết thúc Mỗi bước trong dẫn xuất tăng ít nhất là ( hoặc chiều dài, hoặc số ký hiệu kết thúc) Vì cả chiều dài
lẫn số kí hiệu kết thúc đều không vượt quá |w| nên quá trình dẫn xuất sẽ không nhiều hơn 2|w| lượt, tại thời điểm đó chúng ta hoặc phân tích cú pháp thành công hoặc w không thể được sinh ra bởi văn phạm.
Sự nhập nhằng trong ngôn ngữ và văn phạm
Coi w ∈ L(G), phương pháp phân tích cú pháp vét cạn sẽ sinh ra một cây
dẫn xuất cho w Chúng ta nói “một” cây dẫn xuất cho w, bởi vì có thể có một số cây
dẫn xuất khác Tình huống này đưa đến sự nhập nhằng