Tiếp nội dung phần 1, Bài giảng Chương trình dịch: Phần 2 cung cấp cho người học những kiến thức như: Trình bày các kiến thức cơ bản về: Vị trí, nhiệm vụ của giai đoạn phân tích cú pháp và các phương pháp phân tích cú pháp. Các kỹ thuật biến đổi văn phạm: khử đệ quy trái, thừa số hoá bên trái, khử nhập nhằng. Phương pháp phân tích top – down: phân tích cú pháp đệ quy xuống, phân tích cú pháp dự đoán. Phương pháp phân tích bottom – up: phân tích cú pháp đẩy thu, phân tích cú pháp LR(k).
Trang 1Chương 3 PHÂN TÍCH CÚ PHÁP Mục tiêu:
Giúp sinh viên có khả năng:
- Biết được vị trí, nhiệm vụ của giai đoạn phân tích cú pháp
- Biết được các phương pháp phân tích cú pháp
- Hiểu được các kỹ thuật biến đổi văn phạm
- Hiểu được các kỹ thuật trong phương pháp phân tích top - down
- Hiểu được các kỹ thuật trong phương pháp phân tích bottom - up
- Vận dụng các kỹ thuật vào phân tích cú cho một số văn phạm đơn giản
3.1 Giai đoạn phân tích cú pháp
3.1.1 Vị trí, chức năng, nhiệm vụ của giai đoạn phân tích cú pháp
Giai đoạn phân tích cú pháp là giai đoạn tiếp theo của giai đoạn phân tích từ vựng và trước giai đoạn phân tích ngữ nghĩa
Chức năng của giai đoạn phân tích cú pháp là phân tích chương trình nguồn
về mặt cú pháp: Xây dụng cây phân tích cú pháp hoặc báo lỗi Nhiệm vụ chính của giai đoạn này là nhận vào dòng các thẻ từ (token) có được từ giai đoạn phân tích từ vựng và xác nhận rằng nó có thể được sinh ra từ văn phạm của ngôn ngữ nguồn bằng cách tạo ra cây phân tích cú pháp cho dòng thẻ từ này và đầu ra của nó là cây phân tích cú pháp (parsing tree) Ngoài ra, bộ phân tích cú pháp còn có cơ chế ghi nhận các lỗi cú pháp theo một phương thức linh hoạt và có khả năng phục hồi được
Trang 2các lỗi thường gặp để có thể tiếp tục xử lý phần còn lại của xâu vào Có thể chỉ ra vị trí của giai đoạn này với các giai đoạn liên quan ở hình 3.1
Hình 3.1 Vị trí của bộ phân tích cú pháp
3.1.2 Xử lý lỗi cú pháp
Chương trình nguồn có thể chứa các lỗi ở nhiều mức độ khác nhau:
- Lỗi từ vựng: như tên, từ khóa, toán tử viết không đúng
- Lỗi cú pháp: như ghi một biểu thức toán học với các dấu ngoặc đóng và mở không cân bằng, thiếu dấu chấm phảy (;), thiếu từ khoá
- Lỗi ngữ nghĩa: như một toán tử áp dụng vào một toán hạng không tương thích, sai kiểu dữ liệu
- Lỗi logic: như thực hiện một lời gọi đệ quy không thể kết thúc
Phần lớn việc phát hiện và phục hồi lỗi trong một chương chương trình biên dịch tập trung vào giai đoạn phân tích cú pháp Vì thế, bộ xử lý lỗi (error handler) trong quá trình phân tích cú pháp phải đạt được mục đích sau:
- Ghi nhận và thông báo lỗi một cách rõ ràng và chính xác
- Phục hồi lỗi một cách nhanh chóng để có thể xác định các lỗi tiếp theo
- Không làm chậm tiến trình của một chương trình đúng
3.1.3 Các chiến lược phục hồi lỗi
Phục hồi lỗi là kỹ thuật vượt qua các lỗi để tiếp tục quá trình dịch Nhiều chiến lược phục hồi lỗi có thể dùng trong bộ phân tích cú pháp Mặc dù không có chiến lược nào được chấp nhận hoàn toàn nhưng một số trong chúng đã được áp dụng rộng rãi Ở đây sẽ giới thiệu một số chiến lược:
1) Phương thức "hoảng sợ" (panic mode recovery)
Bảng
ký hiệu
Yêu cầu Thẻ từ mới
Phần còn lại của front end
Trang 3Đây là phương pháp đơn giản nhất cho cài đặt và có thể dùng cho hầu hết các phương pháp phân tích Khi một lỗi được phát hiện thì bộ phân tích cú pháp bỏ qua từng ký hiệu một cho đến khi tìm thấy một tập hợp được chỉ định của các token đồng bộ (synchronizing tokens), các token đồng bộ thường là dấu chấm phẩy (;) hoặc end
2) Chiến lược mức ngữ đoạn (phrase_level recovery)
Khi phát hiện một lỗi, bộ phân tích cú pháp có thể thực hiện sự hiệu chỉnh
cục bộ trên phần còn lại của xâu vào Cụ thể là thay thế phần đầu còn lại bằng một chuỗi ký tự có thể tiếp tục Chẳng hạn, dấu phẩy (,) bởi dấu chấm phẩy (;), xóa một dấu phẩy lạ hoặc thêm vào một dấu chấm phẩy
3) Chiến lược dùng các luật sinh sửa lỗi (error production)
Thêm vào văn phạm của ngôn ngữ những luật sinh lỗi và sử dụng văn
phạm này để xây dựng bộ phân tích cú pháp, giúp có thể sinh ra bộ đoán lỗi thích hợp để chỉ ra cấu trúc lỗi được nhận biết trong xâu vào
4) Chiến lược hiệu chỉnh toàn cục (global correction)
Một cách lý tưởng là chương trình biên dịch tạo ra một số thay đổi trong khi xử
lý một lỗi Có những giải thuật để lựa chọn một số tối thiểu các thay đổi để đạt được một hiệu chỉnh có chi phí toàn cục nhỏ nhất Cho một xâu vào có lỗi x và một văn phạm G, các giải thuật này sẽ tìm được một cây phân tích cú pháp cho xâu y mà số lượng các thao tác chèn, xóa và thay đổi token cần thiết để chuyển x thành y là nhỏ nhất Nói chung, hiện nay kỹ thuật này vẫn còn ở dạng nghiên cứu lý thuyết
3.1.4 Các phương pháp phân tích cú pháp
Hiện tại có nhiều phương pháp phân tích cú pháp khác nhau; tuy nhiên, người ta có thể phân chúng thành 3 loại: phương pháp phân tích tổng hợp, phương pháp phân tích top – down và phương pháp phân tích bottom – up
1) Phương pháp phân tích tổng hợp (Universal parsing)
Tiêu biểu cho phương pháp phân tích tổng hợp là giải thuật Cooke – Young Kasami và giải thuật Earley; Người ta gọi chúng là giải thuật tổng hợp hay giải thuật vạn năng vì chúng phân tích cú pháp cho văn phạm bất kỳ Tuy nhiên do tính vạn năng của chúng cho nên nói chung phương pháp này không hiệu quả với một
Trang 4văn phạm cụ thể; vì lý do trên, người ta ít sử dụng chúng để viết các chương trình
dịch (Compiler)
2) Phương pháp phân tích Top – Down
Về mặt trực giác có thể coi phương pháp phân tích Top – Down là phương
pháp xây dựng cây phân tích cú pháp từ trên xuống hay có thể xem như một nỗ lực
xây dựng cây phân tích cú pháp bắt đầu từ nút gốc và phát sinh dần xuống lá (Root
– Leaves)
3) Phương pháp phân tích Bottom – Up
Về mặt trực giác có thể coi phương pháp phân tích Bottom – Up là xây dựng
cây phân tích cú pháp từ dưới lên trên hay hay có thể xem như một nỗ lực xây dựng
cây phân tích cú pháp bắt đầu từ các nút lá và thu gọn dần về gốc (Leaves – root)
3.2 Biến Ðổi văn phạm phi ngữ cảnh
Nhiều ngôn ngữ lập trình có cấu trúc đệ quy mà nó có thể được định nghĩa
bằng các văn phạm phi ngữ cảnh (context-free grammar) G với 4 thành phần
G = (N, T, P, S), trong đó:
- N : là tập hữu hạn các ký hiệu chưa kết thúc hay các biến (variables)
- T : là tập hữu hạn các ký hiệu kết thúc (terminals) với N T =
- P : là tập luật sinh của văn phạm (productions) có dạng:
A với A N và V* = (NT)*
- S N: là ký hiệu bắt đầu của văn phạm (start symbol)
Ví dụ: Văn phạm với các luật sinh sau cho phép định nghĩa các biểu thức số học
đơn giản (với E là một biểu thức - expression) :
E → EAE | (E) | - E | id ;
A → + | - | * | / | ↑
3.2.1 Cây phân tích cú pháp (Parsing tree) và dẫn xuất
Ta nói rằng αAβ dẫn xuất ra αγβ (ký hiệu: αAβ αγβ) nếu A → γ là một
luật sinh, α và β là các chuỗi tùy ý các ký hiệu văn phạm
Trang 5nghĩa L(G) một ngôn ngữ được sinh ra bởi G Xâu các ký hiệu kết thúc w thuộc
được sinh ra bởi một văn phạm phi ngữ cảnh gọi là ngôn ngữ phi ngữ cảnh Nếu hai văn phạm cùng sinh ra cùng một ngôn ngữ thì chúng được gọi là hai văn phạm tương đương
Nếu S *α, trong đó α có thể chứa một ký hiệu chưa kết thúc thì ta nói rằng
α là một dạng câu (sentential form) của G Một câu là một dạng câu chứa toàn các
Hình 3.2 Minh họa một cây phân tích cú pháp
Một cách hình thức, cho một văn phạm phi ngữ cảnh thì cây phân tích cú pháp
là một cây có các tính chất sau đây:
1 Nút gốc có nhãn là ký hiệu bắt đầu
Trang 62 Mỗi một lá có nhãn là một ký hiệu kết thúc hoặc ε
3 Mỗi nút trong có nhãn là một ký hiệu chưa kết thúc
4 Nếu A là một ký hiệu chưa kết thúc được dùng làm nhãn cho một nút trong nào đó và X1, ., Xn là nhãn của các con của nó theo thứ tự từ trái sang phải thì
A → X1X2 Xn là một luật sinh Ở đây X1, , Xn có thể là ký hiệu kết thúc hoặc chưa kết thúc Ðặc biệt, nếu A → ε thì nút có nhãn A có thể có một con có nhãn ε
Một cây phân tích cú pháp có thể xem như một biểu diễn cho một dẫn xuất
Ðể hiểu được bộ phân tích cú pháp làm việc ta cần xét dẫn xuất trong đó chỉ
có ký hiệu chưa kết thúc trái nhất trong bất kỳ dạng câu nào được thay thế tại mỗi bước, dẫn xuất như vậy được gọi là dẫn xuất trái nhất Nếu α β trong đó ký hiệu chưa kết thúc trái nhất trong α được thay thế, ta viết α *
l m β Nếu S *
l m α thì ta nói α là dạng câu trái nhất của văn phạm
Tương tự, ta có dẫn xuất phải nhất - còn gọi là dẫn xuất chính tắc (canonical derivations)
Ví dụ 3.1:
Cho văn phạm G = ( N, T, P, S);
Tập P gồm các quy tắc:
E E + E; E E * E; E (E); E - E; E id
Khi đó cây phân tích cú pháp cho xâu - (id + id) có dạng ở hình 3.2
Hình 3.3 Minh họa một cây phân tích cú pháp
Ðể thấy mối quan hệ giữa cây phân tích cú pháp và dẫn xuất, ta xét một dẫn xuất: α
1 α
2 α
n Với mỗi α
i ta xây dựng một cây phân tích cú pháp Ví dụ với dẫn xuất:
E
) (
Trang 7E -E - (E) - (E + E) - (id + E) - (id + id)
Quá trình xây dựng cây phân tích cú pháp nhƣ sau:
Văn phạm đƣợc gọi là nhập nhằng nếu tồn tại một xâu có hai cây phân tích
cú pháp khác nhau Nói cách khác văn phạm đƣợc gọi là nhập nhằng nếu tồn tại một xâu có nhiều hơn một cây phân tích cú pháp cho dẫn xuất trái nhất hay phải nhất
Ngôn ngữ đƣợc sinh bởi văn phạm nhập nhằng gọi là ngôn ngữ nhập nhằng
E
-
E
) (
Trang 8Hình 3.5 Hai cây phân tích cú pháp của xâu id + id * id
Vậy văn phạm trên là văn phạm nhập nhằng
3.2.3 Kỹ thuật khử nhập nhằng
Nếu một văn phạm là nhập nhằng thì khi gặp một xâu có nhiều hơn một cây phân tích cú pháp; ta không thể xác định đƣợc cây phân tích cú pháp nào sẽ đƣợc chọn Vì vậy, ta phải viết lại văn phạm nhằm loại bỏ sự nhập nhằng của nó Chẳng hạn, xét văn phạm với các luật sinh :
Ký hiệu E là biểu thức; S là câu lệnh và xét câu lệnh sau:
IF E1 THEN IF E2 THEN S1 ELSE S2
id
id
Trang 9Văn phạm trên là văn phạm nhập nhằng vì câu lệnh trên có hai cây phân tích
cú pháp trái nhất ở hình 3.6a và hình 3.6b
Hình 3.6 Hai cây phân tích cú pháp của cùng một xâu
Để khử tính nhập nhằng của văn phạm nêu trên, người ta thường khắc phục bằng cách cho mỗi ELSE ứng với THEN gần nhất trước đó Theo nguyên tắc này, ta sửa lại các luật sinh như sau:
<sttm> <sttm1> <sttm2>
<sttm1> IF <expr> THEN <sttm1> ELSE <sttm1> other
<sttm2> IF <expr> THEN <sttm>
<sttm2> IF <expr> THEN <sttm1> ELSE <sttm2>
3.2.4 Kỹ thuật khử đệ quy trái
Trong lý thuyết ngôn ngữ hình thức, khi xét dạng chuẩn Greibach đã đề cập đến các A - luật sinh Các A - luật sinh thường làm cho văn phạm trở thành đệ quy
S2
E1
a) sttm
Trang 10trái Ở đây, ta sẽ nhắc lại khái niệm và kỹ thuật khử đệ quy trái đã nêu trong các bổ
Ðệ quy trái có hai loại :
Vì S Aa Sda nhờ áp dụng các luật sinh S → Aa; A→ Sd
và A Sd Aad nhờ áp dụng các luật sinh A→ Sd; S → Aa
2) Kỹ thuật khử đệ quy trái
a) Khử đệ quy trái trực tiếp
Nếu luật sinh có dạng: A → Aα1 | Aα2 | | Aαm | β1 | β2 | | βn
thì thêm vào một biến mới A‟ và thay luật sinh đó bởi các luật sinh:
A → β1A‟ | β2A‟ | | βnA‟
Và A‟→ α1A‟| α2A‟| | αm A‟| ε
Trang 11Áp dụng kỹ thuật nêu trên, ta có:
+ Với các luật sinh E E + T; E T có thể viết lại là E E + T | T
và nó được thay thế bằng các luật sinh E TE1 và E1 + TE1|
+ Với các luật sinh T T*F; T F có thể viết lại là T T*F | F và nó được thay thế bằng các luật sinh T FT1 và T1 *FT1 |
Sau khi khử đệ quy trái, ta thu được văn phạm không đệ quy trái với tập các luật sinh:
Với mỗi biến đệ quy trái gián tiếp:
+ Biến đổi và thay thế để đưa nó về đệ quy trái trực tiếp
+ Khử đệ quy trái trực tiếp
- Giải thuật loại bỏ đệ quy trái gián tiếp
Input: Văn phạm không tuần hoàn và không có các – luật sinh (nghĩa là văn phạm không chứa các dẫn xuất dạng A + A và A )
Output: Văn phạm tương đương không đệ quy trái
Trang 12Áp dụng giải thuật trên
1 Sắp xếp các ký hiệu chƣa kết thúc theo thứ tự S, A
2 - Với i = 1:
+ j = 0 nên vòng lặp theo j bị bỏ qua;
+ Không có đệ quy trái trực tiếp nên không có điều gì xảy ra
+ j = 0 nên vòng lặp theo j bị bỏ qua;
+ Khử đệ quy trái trực tiếp cho S- luật sinh:
Trang 13Bổ sung thêm biến S‟;
Thay S Sc| Aa| b bằng S AaS‟| bS‟ ; S‟ cS‟|
-Với i = 2:
+ j =1:
Không tồn tại luật sinh dạng Ai Aj nên việc thay thế bị bỏ qua + Khử đệ quy trái trực tiếp cho A - luật sinh:
Bổ sung thêm biến A‟;
Thay A Ac| Bd| b bằng A BdA‟ | bA‟ ; A‟ cA‟|
Thay luật sinh B Bb| BdA‟aS‟a | bA‟aS‟a | bS‟a | d bằng
B bA‟aS‟a B‟| bS‟aB‟ | dB‟ và B‟ bB‟| dA‟aS‟aB‟| Vậy sau khi khử đệ quy trái ta thu được văn phạm với các luật sinh sau:
S AaS‟| bS‟; S‟ cS‟| ;
A BdA‟ | bA‟ ; A‟ cA‟| ;
B bA‟aS‟a B‟| bS‟aB‟ | dB‟; B‟ bB‟| dA‟aS‟aB‟|
3.2.5 Kỹ thuật thừa số hoá bên trái
Trong quá trình phân tích từ trên xuống (Top – Down); ta có thể thay một biến ở vế trái bằng một xâu ở vế phải Vấn đề nảy sinh là ở mỗi bước phân tích trong tập P có thể có nhiều luật sinh có thể sử dụng được nhưng ta không biết chọn luật sinh nào là thích hợp cho các bước tiếp theo Để khắc phục tình trạng trên, người ta sử dụng kỹ thuật thừa số hoá bên trái
Trang 141) Ý tưởng
Ý tưởng cơ bản của kỹ thuật này là viết lại các A – luật sinh của văn phạm nhằm “hoãn” lại việc quyết định cho đến khi đủ thông tin cho một lựa chọn đúng với quá trình phân tích
Ví dụ 3.6:
Xét văn phạm có các luật sinh sau cho câu lệnh IF:
<sttm> IF <expr> THEN <sttm> ELSE <sttm>
ta nhận biết luật sinh cần sử dụng chính xác và nhanh chóng hơn
2) Giải thuật thừa số hoá bên trái
Input: Văn phạm G
Output: Văn phạm tương đương đã thừa số hoá bên trái
Process:
Bước 1: Với mỗi biến A thực hiện
- Tìm tiền tố chung dài nhất cho tất cả các vế phải của các luật sinh có
vế trái là A;
- Nếu tìm thấy A 1| 2 | … | n | ; trong đó: là các vế phải không có tiền tố chung với các vế phải khác thì
Trang 15+ Bổ sung vào một biến mới A‟;
+ Thay tập luật sinh tìm đƣợc bằng A A‟|
b) Cho văn phạm với các luật sinh:
S aaaAcBd | aaaAcDE | aaaFe | bbS| cD;
Áp dụng giải thuật trên:
1 -Với biến S, ta thay S aaaAcBd | aaaAcDE | aaaFe | bbS| cD bằng
S aaaS1 | bbS| cD;
S1 AcBd | AcDE | Fe
Trang 16- Với biến A, ta thay A bbCd | bbb bằng A bbA1 và A1 Cd | b
- Với các biến B, C, D, E, F: không có tiền tố chung
2 - Với biến S1, ta thay S1 AcBd | AcDE | Fe bằng
S1 AcS2 | Fe;
S2 Bd | DE
- Với biến A1: không có tiền tố chung
3 Với biến S2: Không có tiền tố chung
Kết quả ta thu được văn phạm tương đương với tập các luật sinh:
c) Cho văn phạm với các luật sinh:
S aaaAcBd | aaaAcde | bbbBe | bbS| cC;
A aba;
B bba;
C abc
Áp dụng giải thuật trên:
1 Với biến S, thay S aaaAcBd | aaaAcde | bbbBe | bbSdd| cD bằng
Trang 17Ta có thể viết lại giải thuật trên nhƣ sau:
Với mỗi biến A thực hiện
+ Bổ sung vào một biến mới A‟;
+ Thay tập luật sinh tìm đƣợc bằng A A‟|
Áp dụng giải thuật trên:
-Với biến S, ta thay S aaaAcBd | aaaAcDE | aaaFe | bbS| cD bằng
- Với biến S2: không có tiền tố chung
- Với biến A, ta thay A bbCd | bbb bằng A bbA1 và A1 Cd | b
- Với biến A : không có tiền tố chung
Trang 18- Với các biến B, C, D, E, F: không có tiền tố chung
Kết quả ta thu được văn phạm tương đương với tập các luật sinh:
3.3 Phân tích cú pháp từ trên xuống
Kỹ thuật phân tích cú pháp từ trên xuống dựa vào ý tưởng cơ bản là cố gắng tìm một dẫn xuất trái nhất cho xâu vào, xuất phát từ ký tự bắt đầu của văn phạm Hay nói một cách khác là xây dựng một cây phân tích cho xâu vào, bắt đầu từ nút gốc phát sinh dần xuống nút lá Kỹ thuật phân tích cú pháp từ trên xuống được chia thành hai loại:
- Phân tích cú pháp từ trên xuống có quay lui - gọi là phân tích cú pháp đệ
quy xuống
- Phân tích cú pháp từ trên xuống theo nguyên tắc dự đoán (Preditive parse)
3.3.1 Phân tích cú pháp đệ quy xuống
1) Ý tưởng
Ý tưởng của kỹ thuật này được minh hoạ qua ví dụ cụ thể sau:
Cho văn phạm với các luật sinh:
1 S cAd
2 A ab
3 A a
Trang 19Cần xây dựng cây phân tích cú pháp cho từ w = cad
Hình 3.7 a, b, c Mô tả quá trình phân tích xâu w = cad
Bắt đầu với gốc có nhãn S, con trỏ trỏ vào ký tự đầu tiên của xâu w là c; áp dụng luật sinh 1 ta được cây ở hình a) Đối chiếu với lá của cây trong hình a) từ bên trái ta thấy nhãn của nút lá trái nhất là c trùng với ký tự mà con trỏ đang trỏ trên xâu vào; Vì vậy, con trỏ trỏ đến ký tự thứ 2 là a Xét nút lá thứ 2 cây a), nút có nhãn A,
sử dụng luật sinh thứ 2 ta được cây b) So sánh nhãn nút lá cực trái của cây con này với ký tự mà con trỏ trỏ trên xâu w; chúng giống nhau, đó là ký tự a Con trỏ trên xâu w trỏ sang ký tự d So sánh nhãn của nút lá tiếp theo của cây con gốc A với ký
tự mà con trỏ đang trỏ trên xâu w; ta thấy chúng khác nhau Việc sử dụng luật sinh 2 coi như thất bại; ta cần phải quay lui lại nút gốc có nhãn A và con trỏ trên xâu w cũng lui lại ký tự thứ 2 là a Bây giờ, ta lại thử sử dụng luật sinh 3; kết quả ta
có cây dẫn xuất hình 3.7c So sánh nhãn của nút lá trong cây gốc A với ký tự con trỏ đang trỏ, chúng trùng nhau Khi đó con trỏ trên w dịch đến ký tự thứ 3 và việc so sánh lại được tiến hành với nút lá có nhãn d Kết quả ta xây dựng xong cây phân tích cho w; giải thuật kết thúc
2) Giải thuật phân tích cú pháp đệ quy xuống
Trước tiên, để đảm bảo có thể phân tích cú pháp đệ quy xuống; ta cần thực hiện các bước chuẩn bị sau:
- Loại bỏ đệ quy trái;
- thực hiện thừa số hoá bên trái
Input: Văn phạm đã loại bỏ đệ quy trái, thừa số hoá bên trái, Xâu vào
Output: Cây phân tích cú pháp
Trang 20Bước 1: - Sử dụng một con trỏ trỏ đến xâu vào Ký hiệu trên xâu vào đang được con trỏ chỉ đến gọi là ký hiệu vào hiện tại Ví trí đầu tiên của con trỏ là ký hiệu bên trái nhất của xâu vào
- Khởi tạo cây với nút gốc là ký tự khởi đầu S của văn phạm; nút đang xét là S
Bước 2: Nếu nút đang xét là:
- Ký hiệu không kết thúc A thì tìm luật sinh đầu tiên có vế trái là A Giả sử là
A X1X2…Xk thì bổ sung vào cây các nút X1, X2, …, Xk làm con của A và lấy X1làm nút đang xét Trường hợp k = 0 tức là A thì bổ sung nút có nhãn là làm con của A và lấy nút ngay bên phải A làm nút đang xét
- Ký hiệu kết thúc a thì so sánh a với ký hiệu vào hiện tại
+ Nếu trùng nhau thì lấy nút bên phải a làm nút đang xét và dịch chuyển con trỏ trên xâu vào sang ký tự tiếp theo
+ Nếu khác nhau thì quay lại nút do luật sinh ngay trước đó tạo ra; điều chỉnh lại con trỏ trên xâu vào và lựa chọn luật sinh tiếp theo Nếu không còn lựa chọn nào nữa thì quay lui
Bước 3: Nếu đã duyệt hết xâu vào và cây không còn nút nào chưa xét thì ta thu được cây phân tích cú pháp Ngược lại, nếu đã quay lui lại tất cả các trường hợp mà không thu được cây phân tích cú pháp thì thông báo lỗi
Trang 213.3.2 Phân tích cú pháp dự đoán (phân tích LL(1))
Kỹ thuật phân tích cú pháp đệ quy xuống đã xem xét ở trên có đặc điểm là trong quá trình phân tích, khi gặp “thất bại” công việc phải quay lui trở lại nút gốc của cây con gần nhất Kỹ thuật trên có một số nhược điểm sau:
- Tốn thời gian, trong nhiều trường hợp làm cho chương trình dịch làm việc chậm do “sa lầy” vào vòng lặp đệ quy
- Thiếu không gian nhớ nếu mức lồng đệ quy lớn
Khi xem xét nhiều văn phạm người ta nhận thấy rằng: bằng cách viết văn phạm cẩn thận, khử đệ quy trái, thừa số hoá bên trái giúp có thể thu được văn phạm mới mà quá trình phân tích không cần phải quay lui
Ta xét một kỹ thuật phân tích từ trên xuống nhưng không quay lui và được gọi
là kỹ thuật phân tích dự đoán (Preditive paser)
1) Ý tưởng
Ý tưởng của kỹ thuật phân tích dự đoán là giả sử cho trước xâu vào
w = x1x2…xn; con trỏ hiện đang trỏ vào ký tự xi và quá trình xây dựng cây phân tích đang ở nút có nhãn là biến A Vấn đề đặt ra là cần phải sử dụng luật sinh nào trong
số m các A - luật sinh có thể sử dụng A i với i = 1, 2, …, m để dẫn ra cây phân tích thích hợp của từ w Rõ ràng, nếu trong m các A - luật sinh chỉ có một luật sinh
A ik là thích hợp nhất trong trường hợp này
Phân tích dự đoán còn gọi là phân tích LL đưa ra cách thức chọn luật sinh để triển khai
Cho các luật sinh A i với i = 1, 2, …, m thoả mãn tính chất các xâu i với
i = 1, 2, …, m suy dẫn ra các xâu có ký hiệu đầu tiên là các ký hiệu kết thúc khác nhau Khi đó chỉ cần nhìn vào ký tự tiếp theo trên xâu vào thì sẽ xác định được cần triển khai A theo i nào Một văn phạm thỏ mãn điều này gọi là văn phạm LL(1)
Ví dụ 3.9:
Xét văn phạm sinh ra các câu lệnh trong ngôn ngữ lập trình Pascal:
<sttm> IF <expr> THEN <sttm> ELSE <sttm>
<sttm> WHILE <expr> DO <sttm>
<sttm> BEGIN <sttm_list> END
Trang 22n
xn
x1 x2
Trong ví dụ này, rõ ràng là nếu đang ở nút của cây phân tích có nhãn <sttm>
và con trỏ đang trỏ vào ký tự „I‟ hoặc „W‟ hoặc „B‟ trên xâu vào thì có thể xác
định được ngay cần sử dụng luật sinh nào trong 3 luật sinh trên
2) Phân tích dự đoán dựa trên sơ đồ chuyển
Sơ đồ chuyển được sử dụng như một công cụ để thể hiện giải thuật phân tích
cú pháp dự đoán Trước hết, hãy xét cách xây dựng sơ đồ chuyển cho bộ phân tích
cú pháp dự đoán
a) Xây dựng sơ đồ chuyển cho bộ phân tích dự đoán
Giả sử cho văn phạm G, trước hết ta thực hiện:
- Khử tính nhập nhằng của văn phạm;
- Khử đệ quy trái;
- Thừa số hoá bên trái;
Sau đó, với mỗi biến hay Nonterminal A ta xây dựng một sơ đồ chuyển cho
A - luật sinh dạng A x1x2… xn như sau:
- Tạo một trạng thái bắt đầu và một trạng thái kết thúc
- Tạo một đường đi từ trạng thái bắt đầu đến trạng thái kết thúc bằng các cung
có hướng mang nhãn xi với i = 1, 2, …, n như hình 3.8
Hình 3.8 Sơ đồ chuyển của một biến
Một cách cụ thể, sơ đồ chuyển được xây dựng theo các nguyên tắc sau:
1 Mỗi ký hiệu chưa kết thúc tương ứng với một sơ đồ chuyển trong đó nhãn cho các cung là token hoặc ký hiệu kết thúc hoặc chưa kết thúc
2 Mỗi token hoặc ký hiệu kết thúc tương ứng với việc đoán nhận token hoặc
ký hiệu kết thúc đó và đọc t tiếp theo
3 Mỗi ký hiệu chưa kết thúc tương ứng với lời gọi thủ tục cho ký hiệu đó
x-
8 A-
Trang 234 Mỗi luật sinh có dạng A → α
Trang 24Các sơ đồ chuyển tương ứng:
Hình 3.9 Sơ đồ chuyển cho các biến
Các sơ đồ chuyển có thể được đơn giản hóa bằng cách thay sơ đồ này vào sơ
đồ khác, những thay thế này tương tự như những phép biến đổi trên văn phạm
13: T‟:
17:
Trang 25Hình 3.10 Sơ đồ chuyển rút gọn b) Giải thuật phân tích dự đoán dựa vào sơ đồ chuyển
Quá trình phân tích cú pháp từ trên xuống theo phương pháp dự đoán dựa vào
sơ đồ chuyển được tiến hành như sau:
Input: Sơ đồ chuyển và xâu vào w$
Output: phân tích được xâu vào?
Process:
Bước 1: Xuất phát từ trạng thái bắt đầu của ký tự khởi đầu trong tập N, con trỏ trỏ vào ký tự đầu tiên của xâu vào w
Bước 2: Nếu trên sơ đồ chuyển đang ở nút i và cung đi ra đầu tiên có nhãn
là đang nối với nút j thì khi đó:
- Nếu là ký tự kết thúc (Terminal) và ký tự mà con trỏ đang trỏ trong w cũng là
thì con trỏ trỏ đến ký tự tiếp theo của xâu w; quá trình duyệt chuyển sang nút j
- Nếu là biến (Nonterminal) thì quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong sơ đồ chuyển của biến
+ Nếu quá trình duyệt đến được trạng thái kết thúc của biến thì quá trình duyệt quay trở lại nút j
+ Ngược lại
* Nếu ở nút i còn cung đi ra thì chọn cung đi ra tiếp theo và quay lại bước 2
* Nếu đã xét hết các cung đi ra khỏi nút i và quá trình duyệt không đến được trạng thái kết thúc của biến thì báo lỗi
- Nếu từ nút i đến nút j có cung mang nhãn , thì quá trình duyệt chuyển thẳng đến nút j và con trỏ trỏ vào ký tự trên xâu vào w đứng yên
Bước 3: Nếu quá trình duyệt đã duyệt hết xâu vào và:
F
F: ( 15 16 17
Trang 26- Nếu quá trình duyệt đến đƣợc trạng thái kết thúc của một sơ đồ chuyển thì thông báo thành công
- Ngƣợc lại, nếu không đến đƣợc trạng thái kết thúc của một sơ đồ chuyển thì thông báo lỗi
Vì T là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong sơ đồ chuyển của T là 7
Trên sơ đồ chuyển của T đang ở nút 7 và cung đi ra có nhãn là F đang nối với nút có nhãn là 8
Vì F là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của F là 14
Trên sơ đồ chuyển của F đang ở nút 14 và có 2 cung đi ra có nhãn là id và ( đang nối với nút có nhãn là 17 và 15 Chọn cung đi ra có nhãn là id, trùng với token đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo
là +, tức là ký tự đầu tiên của xâu + id * id$ Quá trình duyệt chuyển sang nút có nhãn là 17
Vì 17là nút kết thúc của F nên quá trình duyệt chuyến sang nút có nhãn là 8 trong sơ đồ chuyển của T
Trên sơ đồ chuyển của T đang ở nút 8 và có 2 cung đi ra có nhãn là * và
đang nối với nút có nhãn là 7 và 13 Chọn cung đi ra có nhãn là
Vì nhãn là , do đó quá trình duyệt chuyển sang duyệt nút 13 Vì 13là nút kết thúc của T nên quá trình duyệt chuyến sang nút có nhãn là 3 trong sơ đồ chuyển của E Trên sơ đồ chuyển của E đang ở nút 3 và có 2 cung đi ra có nhãn là + và đang nối với nút có nhãn là 0 và 6 Chọn cung đi ra có nhãn là +, trùng với token đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo là id, tức là ký tự đầu tiên của xâu id * id$ Quá trình duyệt chuyển sang nút có nhãn là 0
Trang 27Trên sơ đồ chuyển của E đang ở nút 0 và cung đi ra có nhãn là T đang nối với nút có nhãn là 3
Vì T là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của T là 7
Trên sơ đồ chuyển của T đang ở nút 7 và cung đi ra có nhãn là F đang nối với nút có nhãn là 8 trong sơ đồ chuyển của T
Vì F là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của F là 14
Trên sơ đồ chuyển của F đang ở nút 14 và có 2 cung đi ra có nhãn là id và ( đang nối với nút có nhãn là 17 và 15 Chọn cung đi ra có nhãn là id, trùng với token đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo là
*, tức là ký tự đầu tiên của xâu * id$ Quá trình duyệt chuyển sang nút có nhãn là 17
Vì 17là nút kết thúc của F nên quá trình duyệt chuyến sang nút có nhãn là 8 trong sơ đồ chuyển của T
Trên sơ đồ chuyển của T đang ở nút 8 và có 2 cung đi ra có nhãn là * và
đang nối với nút có nhãn là 7 và 13 Chọn cung đi ra có nhãn là *, trùng với ký tự đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo
là id, tức là ký tự đầu tiên của xâu id$ Quá trình duyệt chuyển sang nút có nhãn là 7 của sơ đồ chuyển của T
Trên sơ đồ chuyển của T đang ở nút 7 và cung đi ra có nhãn là F đang nối với nút có nhãn là 8
Vì F là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của F là 14
Trên sơ đồ chuyển của F đang ở nút 14 và có 2 cung đi ra có nhãn là id và ( đang nối với nút có nhãn là 17 và 15 Chọn cung đi ra có nhãn là id, trùng với token đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo
là $, tức là ký tự kết thúc xâu Quá trình duyệt chuyển sang nút có nhãn là 17
Vì 17là nút kết thúc trong sơ đồ chuyển của F và đã duyệt hết xâu vào nên quá trình duyệt kết thúc và thông báo thành công
- w = id + * id + id$
Trang 28Xuất phát từ trạng thái 0của ký hiệu khởi đầu E của văn phạm Con trỏ trỏ vào ký tự đầu tiên của xâu vào id + * id + id$ là id Trên sơ đồ chuyển của E đang ở nút 0 và cung đi ra có nhãn là T đang nối với nút có nhãn là 3
Vì T là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong sơ đồ chuyển của T là 7
Trên sơ đồ chuyển của T đang ở nút 7 và cung đi ra có nhãn là F đang nối với nút có nhãn là 8
Vì F là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của F là 14
Trên sơ đồ chuyển của F đang ở nút 14 và có 2 cung đi ra có nhãn là id và ( đang nối với nút có nhãn là 17 và 15 Chọn cung đi ra có nhãn là id, trùng với token đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo
là +, tức là ký tự đầu tiên của xâu + * id + id$ Quá trình duyệt chuyển sang nút có nhãn là 17 của sơ đồ F
Vì 17là nút kết thúc của F nên quá trình duyệt chuyến sang nút có nhãn là 8 trong sơ đồ chuyển của T
Trên sơ đồ chuyển của T đang ở nút 8 và có 2 cung đi ra có nhãn là * và
đang nối với nút có nhãn là 7 và 13 Chọn cung đi ra có nhãn là
Vì nhãn là , do đó quá trình duyệt chuyển sang duyệt nút 13 Vì 13là nút kết thúc của T nên quá trình duyệt chuyến sang nút có nhãn là 3 trong sơ đồ chuyển của E
Trên sơ đồ chuyển của E đang ở nút 3 và có 2 cung đi ra có nhãn là + và
đang nối với nút có nhãn là 0 và 6 Chọn cung đi ra có nhãn là +, trùng với token đƣợc trỏ bởi con trỏ trên xâu vào Con trỏ trên xâu vào chuyển sang ký tự tiếp theo
là *, tức là ký tự đầu tiên của xâu * id + id$ Quá trình duyệt chuyển sang nút có nhãn là 0
Trên sơ đồ chuyển của E đang ở nút 0 và cung đi ra có nhãn là T đang nối với nút có nhãn là 3
Vì T là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của T là 7
Trên sơ đồ chuyển của T đang ở nút 7 và cung đi ra có nhãn là F đang nối với nút có nhãn là 8 trong sơ đồ chuyển của T
Trang 29Vì F là biến, do đó quá trình duyệt chuyển sang duyệt trạng thái bắt đầu trong
sơ đồ chuyển của F là 14
Trên sơ đồ chuyển của F đang ở nút 14 và có 2 cung đi ra có nhãn là id và ( đang nối với nút có nhãn là 17 và 15 Các nhãn này là token id và ký tự kết thúc ( đều không trùng với ký hiệu kết thúc * đang được trỏ bởi con trỏ trên xâu vào
Vì đã xét hết các cung đi ra khỏi các nút 14, 7 và 0 và quá trình duyệt không đến được trạng thái kết thúc của một sơ đồ chuyển nào nên quá trình duyệt dừng để thông báo lỗi
2) Phân tích dự đoán dựa vào ngăn xếp (không đệ quy )
Trong phương pháp phân tích cú pháp Top - Down cả hai kỹ thuật nêu trên đều
sử dụng thủ tục đệ quy Với phương pháp phân tích dự đoán sử dụng ngăn xếp (Stack), ta có thể tránh được thủ tục đệ quy
a) Ý tưởng
Mô hình tổ chức dữ liệu cho kỹ thuật này gồm các khối sau:
- Một ngăn đệm (Buffer) dùng để chứa xâu vào w, với việc bổ sung ký hiệu hết xâu $
- Một ngăn xếp (Stack) với ký hiệu $ chỉ đáy ngăn xếp và có bổ sung ký hiệu khởi đầu S vào ngăn xếp
- Một bộ chương trình điều khiển quá trình phân tích
- Một bảng phân tích cú pháp M[A, a], bảng này chứa các A - luật sinh dạng
A ; (NT)+
- Một ngăn đệm dùng để chứa kết quả phân tích
Hình 3.11 Mô tả hình tổ chức dữ liệu của kỹ thuật dự đoán
Bảng phân tích
cú pháp
Dòng kết quả
Trang 30Chương trình phân tích hoạt động theo nguyên tắc sau:
- Con trỏ ip trỏ vào ký tự a trên xâu vào w
- Xét ký tự X trên đỉnh ngăn xếp, khi đó chương trình hành động như sau: + Nếu X = a = $ chương trình dừng, đưa ra thông báo quá trình phân tích kết thúc thành công
+ Nếu X = a $ thì đẩy X ra khỏi đỉnh Stack, con trỏ trên w dịch sang vị trí tiếp theo
+ Nếu X là biến (Nonterminal), chương trình dò tìm luật sinh X trên bảng M tại M[X , a], nếu có luật sinh này thì được đưa vào ngăn xếp và quay lại bước 1, nếu không có, chương trình báo lỗi
b) Giải thuật phân tích cú pháp dự đoán dựa vào ngăn xếp
Input: G - CFG, xâu vào w$
Output: Dẫn xuất trái nhất của w hoặc thông báo lỗi
Process:
1 Khởi tạo:
+ Bổ sung ký tự $ vào Stack chỉ đáy ngăn xếp;
+ Đưa ký hiệu chưa kết thúc bắt đầu S vào đỉnhStack;
+ Đưa vào ngăn đệm xâu vào w$;
+ Con trỏ ip trỏ tới ký hiệu đầu tiên của xâu w$ ;
2 REPEAT
- X là ký hiệu nằm trên đỉnh Stack;
- ip đang trỏ vào ký tự a của xâu vào w$;
Trang 31begin
- Đẩy X ra khỏi Stack;
- Đẩy Yk , Y2, …, Y1 vào Stack { Y1 ở đỉnh};
- Đƣa luật sinh X Y1 Y2….Yk ra Buffer kết quả;
Trang 32Bảng 3.2 Phân tích cú pháp cho xâu vào id + id * id
Cây phân tích cú pháp đƣợc hình thành từ output :
Hình 3.12 Cây phân tích cú pháp cho xâu vào id + id * id
được xây dựng từ dưới lên
Trang 33Nhận xét:
- Mỗi văn phạm có một bảng phân tích M tương ứng
- Chương trình không cần thay đổi cho các văn phạm khác nhau
c) Xây dựng bảng phân tích cú pháp
Với mục đích hỗ trợ cho giải thuật xây dựng bảng phân tích cú pháp M và phục hồi lỗi theo chiến lược panic_mode; ta xét cách xác định hai hàm FIRST và FOLLOW
Hàm FIRST
- Định nghĩa
Cho văn phạm G = (N, T, P, S); giả sử là xâu các ký hiệu văn phạm, tức là
(N T)* FIRST(α) là tập hợp các ký hiệu kết thúc a mà a là ký hiệu bắt đầu của một xâu được dẫn xuất từ α
FIRST() = a T * a; (NT)*
Nếu trong P có * thì cũng thuộc FIRST ()
FIRST() cho ta biết xâu có thể dẫn xuất đến tận cùng thành một xâu bắt đầu bằng một ký hiệu kết thúc nào
- Cách xác định hàm FIRST(X) với X là một ký hiệu văn phạm
1 Nếu X là ký tự kết thúc thì FIRST(X) = {X}
2 Nếu X là một luật sinh thì thêm vào FIRST(X)
3 Nếu X Y1Y2…Yk là một luật sinh thì thêm FIRST(Y1) trừ vào FIRST(X) Nếu FIRST(Y1) thì tiếp tục thêm FIRST(Y2) trừ vào FIRST(X) Nếu FIRST(Y1) FIRST(Y2) thì tiếp tục thêm FIRST(Y3) trừ vào FIRST(X) Nếu FIRST(Yt) với mọi t = 1, 2, , i và i < k thì tiếp tục thêm FIRST(Yi+1) trừ
vào FIRST(X) Cuối cùng thêm vào FIRST(X) nếu k
i 1
FIRST(Yi)
Để tính FIRST của các ký tự không kết thúc trong một văn phạm, ta lần lượt xét tất cả các luật sinh Tại mỗi luật sinh, áp dụng các quy tắc trên để thêm các ký tự vào các tập FIRST Quá trình này được tiếp tục cho đến khi gặp một lượt duyệt mà không bổ sung thêm được bất kỳ một ký tự kết thúc nào hoặc vào các tập FIRST thì kết thúc
Trang 34- Từ luật sinh (3), theo quy tắc 2 ta thêm đƣợc vào FIRST(E')
- Không còn luật sinh nào có vế trái là E' nữa Vì vậy, ta không thể thêm ký hiệu nào vào FIRST(E') nữa FIRST(E') = { +, }
Trang 35Ta cũng có thể tính FIRST của một xâu như sau:
Giả sử = Y1Y2….Yk Trong trường hợp này, ta tính FIRST() như quy tắc 3
ở trên:
1 thêm FIRST(Y1) trừ vào FIRST()
2 Nếu FIRST(Y1) thì tiếp tục thêm FIRST(Y2) trừ vào FIRST() Nếu
FIRST(Y1) FIRST(Y2) thì tiếp tục thêm FIRST(Y3) trừ vào FIRST() Nếu
FIRST(Yt) với mọi t = 1, 2, , i và i < k thì tiếp tục thêm FIRST(Yi+1) trừ vào FIRST() Cuối cùng thêm vào FIRST() nếu k
i 1
FIRST(Yi)
Hàm FOLLOW
- Ðịnh nghĩa
Cho văn phạm G = (N, T, P, S); A là một ký hiệu chưa kết thúc
FOLLOW(A) là tập hợp các ký hiệu kết thúc a mà nó xuất hiện ngay sau A (bên
phía phải của A) trong một dạng câu nào đó Tức là tập hợp các ký hiệu kết thúc a, sao cho tồn tại một dẫn xuất dạng S * αAaβ Chú ý rằng nếu A là ký hiệu bên phải nhất trong một dạng câu nào đó thì $ FOLLOW(A) ($ là ký hiệu kết thúc xâu vào)
1 Đặt $ vào FOLLOW(S), trong đó S là ký hiệu bắt đầu của văn phạm và $ là
ký hiệu thêm vào để đánh dấu kết thúc chuỗi nhập
2 Nếu có một luật sinh B A thì thêm mọi phần tử khác của FIRST()
3 Nếu có luật sinh B A,
hoặc B A mà FIRST() thì thêm tất cả các phần
FOLLOW(B)
Trang 36Để tính FOLLOW của các ký tự không kết thúc trong một văn phạm, ta lần lƣợt xét tất cả các luật sinh Tại mỗi luật sinh, áp dụng các quy tắc trên để thêm các
ký tự vào các tập FOLLOW Quá trình này đƣợc tiếp tục cho đến khi gặp một lƣợt duyệt mà không bổ sung thêm đƣợc bất kỳ một ký tự kết thúc nào vào các tập FOLLOW thì kết thúc
- Vì E là ký hiệu khởi đầu, theo quy tắc 1 ta thêm $ vào FOLLOW(E)
- Áp dụng quy tắc 2 cho luật sinh (7):
F (E) ) FOLLOW(E) FOLLOW(E) ={$, )}
- Không còn áp dụng đƣợc quy tắc nào cho E nữa Vậy FOLLOW(E) ={$, )} Tính FOLLOW(E'):
- Áp dụng quy tắc 3 cho luật sinh (1): E TE' ta thêm mọi ký hiệu của
- Không thêm đƣợc ký hiệu nào vào FOLLOW(E') nữa
FOLLOW(E') ={$, )}
- Áp dụng luật 2 cho luật sinh (1): E TE' + FOLLOW(T)
- Áp dụng luật 3 cho luật sinh (2, 3): E‟ +TE' , E'
- Áp dụng quy tắc 3 cho luật sinh (4): T FT' thì FOLLOW(T') = FOLLOW(T) = {+, ), $ }
Trang 37Áp dụng quy tắc 2 cho luật sinh (4): T FT' * FOLLOW(F)
Áp dụng quy tắc 3 cho luật sinh (5, 6): T' *FT' ; T'
Vậy ta có: FOLLOW(E) = FOLLOW(E') = { $, ) }
FOLLOW(T) = FOLLOW(T') = { +, ), $ }
FOLLOW(F) = {*, +, ), $ }
Giải thuật xây dựng bảng phân tích cú pháp
Sử dụng các hàm FIRST , FOLLOW có thể đưa ra giải thuật xây dựng bảng phân tích cú pháp cho một văn phạm phi ngữ cảnh như sau:
Input: Văn phạm phi ngữ cảnh
Output: Bảng phân tích cú pháp M
Process:
Bước 1: Với mỗi luật sinh A P thực hiện bước 2, 3
Bước 2: Với mỗi a FIRST() thì M[A, a]:= “A ” (đưa luật sinh A
Trang 38- Xét luật sinh E TE':
Tính FIRST(TE') = FIRST(T) = {(,id}
M[E, id] và M[E,( ] chứa luật sinh E TE'
- Xét luật sinh E' + TE' :
Tính FIRST(+TE') = FIRST(+) = {+}
M[E', +] chứa E' +TE'
- Xét luật sinh E' : Vì FIRST(E') và FOLLOW(E') = { ), $ }
E nằm trong M[E', )] và M[E', $]
Trang 39xảy ra tình trạng ở mỗi vị trí M[A, a] có thể chứa nhiều luật sinh Chẳng hạn khi G
là văn phạm đệ quy trái hoặc là văn phạm nhập nhằng thì chắc chắn sẽ tồn tại ít nhất một ô trong bảng phân tích cú pháp M chứa nhiều luật sinh Trong trường hợp như vậy kỹ thuật phân tích cú pháp dự đoán sẽ hạn chế hiệu quả, vì là dẫn đến tình trạng không biết sử dụng luật sinh nào trong số các luật sinh ghi ở vị trí M[A, a] cho phù hợp với phân tích từ vào Ví dụ sau đây chỉ ra tình trạng trên
Ví dụ 3.16:
Xét văn phạm:
S → i E t S | i E t S e S | a
E → b Sau khi thừa số hoá bên trái, ta có văn phạm tương đương:
Một văn phạm được gọi là văn phạm LL(1) nếu mọi ô trong bảng phân tích
cú pháp của nó chỉ chứa không quá một luật sinh
Ở đây ký tự “L” thứ nhất chỉ rằng quá trình dò đọc xâu vào được tiến hành
từ bên trái (Left) Ký tự “L” thứ hai chỉ rằng quá trình phân tích cú pháp sẽ chỉ ra dẫn xuất trái nhất, cuối cùng chữ số “1” chỉ số ký tự cần biết để dự đoán cần phải chọn luật sinh nào cho thích hợp
Trang 40Người ta đã chứng minh được rằng nếu văn phạm G là văn phạm LL(1) thì
sử dụng giải thuật xây dựng bảng phân tích cú pháp nêu trên có thể phân tích được mọi xâu vào của L(G)
b) Các tính chất của LL(1)
Văn phạm LL(1) có một số tính chất đặc biệt sau:
1 Nếu văn phạm G là LL(1) thì G không là văn phạm nhập nhằng
2 Nếu văn phạm G là LL(1) thì G không là văn phạm đệ quy trái
3 Văn phạm G là LL(1) khi và chỉ khi hai luật sinh khác nhau
A và A của G thoả mãn điều kiện sau:
- Không tồn tại a T để * a và * a
- Chỉ có thể có tối đa một trong hai dẫn xuất * hoặc *
- Nếu * thì không thể dẫn ra xâu bắt đầu bằng a T và a FOLLOW(A)
4) Phục hồi lỗi trong phân tích dự đoán
Một lỗi sẽ được tìm thấy trong quá trình phân tích dự đoán khi gặp một trong hai trường hợp sau:
1 Ký hiệu kết thúc trên đỉnh Stack không phù hợp với token kế tiếp trong xâu vào
2 Trên đỉnh Stack là ký hiệu chưa kết thúc A, token trong xâu vào là a nhưng M[A,a] rỗng
Phục hồi lỗi theo phương pháp panic_mode là bỏ qua các ký hiệu trong xâu vào cho đến khi gặp một phần tử trong tập hợp các token đồng bộ (synchronizing token)
Tính hiệu quả của phương pháp này tùy thuộc vào cách chọn tập hợp các token đồng bộ Một số mẹo (heuristics) có thể là: