Cho một văn phạm phi ngữ cảnh (CFG) với ký hiệu bắt đầu S, gồm n luật sinh ban đầu.
Quy ước biểu diễn văn phạm phi ngữ cảnh (CFG) dùng chung cho đề này:
A-Z).(, ), +, *, id, num, ...) là ký hiệu kết thúc (terminal); terminal có thể dài nhiều ký tự nhưng không chứa khoảng trắng.e ở vế phải nghĩa là luật sinh sinh ra chuỗi rỗng ε (ví dụ A -> e).$ khi cần dùng tới FOLLOW.Sau đó, một luật sinh mới được đề xuất bổ sung vào văn phạm (thêm làm một lựa chọn thay thế cho một ký hiệu chưa kết thúc đã có sẵn, hoặc cho một ký hiệu hoàn toàn mới). Gọi văn phạm sau khi thêm luật sinh này là văn phạm mở rộng.
Hãy kiểm tra xem văn phạm mở rộng có còn thỏa điều kiện LL(1) hay không. Cụ thể, với mỗi ký hiệu chưa kết thúc A có từ 2 luật sinh trở lên A→α1∣α2∣…, gọi SELECT(A→αi)=FIRST(αi)∖{ε}, cộng thêm FOLLOW(A) nếu ε∈FIRST(αi) (đây chính là tập các ký hiệu kết thúc/$ khiến bộ phân tích LL(1) chọn luật sinh này). Văn phạm là LL(1) khi và chỉ khi với mọi A, các tập SELECT của các luật sinh khác nhau của A đôi một rời nhau.
Lưu ý quan trọng: việc thêm luật sinh mới có thể làm thay đổi FIRST/FOLLOW của toàn bộ văn phạm (ví dụ nếu luật sinh mới là A→ε khiến A trở nên nullable), vì vậy phải tính lại FIRST/FOLLOW trên toàn bộ văn phạm mở rộng rồi mới kiểm tra.
Với văn phạm biểu thức số học kinh điển, nếu thêm luật sinh X -> - T X (một lựa chọn mới cho X dùng dấu trừ), văn phạm mở rộng vẫn là LL(1) (in ra LL1) vì - không trùng với SELECT của các luật sinh khác của X.
A -> X1 X2 ... Xk hoặc A -> e.A -> X1 X2 ... Xk hoặc A -> e (ký hiệu A ở vế trái có thể trùng hoặc không trùng với các ký hiệu đã có).Quy ước biểu diễn văn phạm phi ngữ cảnh (CFG) dùng chung cho đề này:
A-Z).(, ), +, *, id, num, ...) là ký hiệu kết thúc (terminal); terminal có thể dài nhiều ký tự nhưng không chứa khoảng trắng.e ở vế phải nghĩa là luật sinh sinh ra chuỗi rỗng ε (ví dụ A -> e).$ khi cần dùng tới FOLLOW.Nếu văn phạm mở rộng (sau khi thêm luật sinh) vẫn là LL(1), in ra đúng một dòng LL1.
Ngược lại, in dòng đầu tiên là KHONG-LL1, sau đó in danh sách tất cả các cặp (A, a) — với A là ký hiệu chưa kết thúc và a là một terminal hoặc $ — sao cho tồn tại ít nhất 2 luật sinh của A mà a thuộc SELECT của cả hai (tức a gây xung đột tại A). Mỗi cặp in trên một dòng riêng theo định dạng A a, các dòng được sắp xếp tăng dần trước hết theo tên A (từ điển), sau đó theo tên a (từ điển); mỗi cặp (A,a) chỉ in một lần dù có thể có nhiều hơn 2 luật sinh cùng gây xung đột tại đó.
Ví dụ:
Đầu vào:
E
8
E -> T X
X -> + T X
X -> e
T -> F Y
Y -> * F Y
Y -> e
F -> ( E )
F -> id
F -> id
Đầu ra:
KHONG-LL1
F id
Đầu vào:
E
8
E -> T X
X -> + T X
X -> e
T -> F Y
Y -> * F Y
Y -> e
F -> ( E )
F -> id
X -> - T X
Đầu ra:
LL1
Đang tải editor...