kiểm tra xem SP của chương trình có thỏa mãn cú pháp của ngôn ngữ hay không, bằng cách nhận chuỗi các token từ bộ phân tích từ vựng và xác định chuỗi đó có được sinh ra bởi văn phạm c
Trang 2Bài 3 Phân tích cú pháp
3.1 Vị trí của phân tích cú pháp
3.2 Một số vấn đề trong phân tích cú pháp
3.2.1 Văn phạm phi ngữ cảnh 3.2.2 Phân tích cú pháp từ trên xuống 3.2.3 Một số chiến lược phục hồi lỗi 3.2.4 Phân tích cú pháp từ dưới lên 3.3 Công cụ xây dựng SA
3.4 Bài tập thực hành
Trang 3Bài 3 Phân tích cú pháp
2.1 Vị trí của phân tích cú pháp
2.2 Một số vấn đề trong phân tích cú pháp
2.2.1 Văn phạm phi ngữ cảnh 2.2.2 Phân tích cú pháp từ trên xuống 2.2.3 Một số chiến lược phục hồi lỗi 2.2.4 Phân tích cú pháp từ dưới lên 2.3 Công cụ xây dựng SA
2.4 Bài tập thực hành
19/05/2012
3
©TS Hà Chí Trung, Khoa CNTT - HVKTQS
Trang 43.1 Vị trí của phân tích cú pháp
Chương trình nguồn (Source program)
Quản lí lỗi (Error handler)
Phân tích từ vựng (Lexical analyzer)
Phân tích cú pháp (Syntactic analyzer)
Sinh mã trung gian (Intermediate code generator)
Tối ưu mã (Code optimizer) Sinh mã (Code generator)
Chương trình đích (Target program)
Phân tích ngữ nghĩa (Semantic analyzer) Quản lí bảng kí tự
(Symbol-table manager)
Trang 53.1 Vị trí của phân tích cú pháp
Cú pháp của một PL có thể được miêu tả bởi một CFG Thông thường người ta sử dụng dạng BNF (Backus-Naur
Form) để diễn đạt chúng
kiểm tra xem SP của chương trình có thỏa mãn cú pháp của ngôn ngữ hay không, bằng cách nhận chuỗi các token từ bộ
phân tích từ vựng và xác định chuỗi đó có được sinh ra bởi
văn phạm của SL không
Thông thường, parser sẽ chỉ ra cấu trúc cú pháp của mã
nguồn, cấu trúc này trong hầu hết trường hợp có thể biểu diễn như là một parse tree
Ngược lại, trả về các thông báo lỗi
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 5
Trang 63.1 Vị trí của phân tích cú pháp
Các chiến lược phân tích cú pháp:
Phân tích từ trên xuống (top-down parsing): Cây cú pháp được
tạo từ trên xuống, bắt đầu từ gốc;
Phân tích từ dưới lên (bottom-up parsing): Cây cú pháp được tạo
từ dưới lên, bắt đầu từ các lá
Cả hai dạng parsers đều quét luồng dữ liệu vào từ trái qua phải (tại mỗi thời điểm thường là 1 token)
Source
program
Lexical analyzer Get next
Semantic analyzer
Trang 73.1 Vị trí của phân tích cú pháp
Vấn đề: Trong quá trình biên dịch xuất hiện nhiều lỗi do
đó SA phải phát hiện và thông báo lỗi chính xác cho người
lập trình đồng thời không làm chậm những chương trình được viết đúng
Trên thực tế, những parsers hiệu quả chỉ có thể ứng dụng
cho một lớp con CFGs:
Phân tích đệ quy (O(cn));
thuật toán phân tích CYK (Coke-Younger-Kasami) (O(n3));
(thuật toán phân tích Earley) (O(n3) hoặc O(n2) hoặc O(n));
LL(k) đối với top-down parsing (O(n));
LR(k) đối với bottom-up parsing (O(n))
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 7
Trang 83.4 Bài tập thực hành
Trang 93.2.1 Văn phạm phi ngữ cảnh
Để định nghĩa cấu trúc của PL ta dùng CFG:
tiếp trái nhất, phải nhất
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 9
Trang 113.2.1 Văn phạm phi ngữ cảnh
VD : parse tree cho biểu thức –(id+id) là:
Trang 123.2.1 Văn phạm phi ngữ cảnh
Tính nhập nhằng của văn phạm (ambiguity): Một văn phạm
sinh ra nhiều hơn một parse tree cho một câu được gọi là văn
phạm nhập nhằng (mơ hồ, đa nghĩa) Nói cách khác một văn phạm nhập nhằng sẽ sinh ra nhiều hơn một dẫn xuất trái nhất hoặc dẫn xuất phải nhất cho cùng một câu
Trang 13sẽ có hai parse tree:
Trang 143.2.1 Văn phạm phi ngữ cảnh
Đối với hầu hết parsers, đòi hỏi văn phạm phải là văn phạm không nhập nhằng
VD 2.4: Có thể loại bỏ sự nhập nhằng trong vd trước, ta đưa ra
qui tắc "Khớp mỗi else với một then chưa khớp gần nhất
trước đó" Với qui tắc này, ta viết lại văn phạm trên như sau:
Stmt matched_stmt | unmatched_stmt
matched_stmt if expr then matched_stmt
| otherstmt
unmatched_stmt if expr then stmt
| if expr then matched_stmt
Trang 153.2.1 Văn phạm phi ngữ cảnh
trái (left recursion) nếu tồn tại một dẫn xuất có dạng
𝐴 Aα (trong đó A là 1 kí hiệu chưa kết thúc, α là một +xâu)
Các phương pháp phân tích từ trên xuống không thể xử lí văn phạm đệ qui trái, do đó cần phải biến đổi văn phạm
để loại bỏ các đệ qui trái
Ðệ qui trái có hai loại:
Loại trực tiếp: Có dạng 𝐴 Aα
Loại gián tiếp: Gây ra do dẫn xuất của hai hoặc nhiều bước
VD: S Aa | b; A Sc | d
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 15
Trang 163.2.1 Văn phạm phi ngữ cảnh
Loại bỏ đệ quy trái trực tiếp:
Ta nhóm các luật sinh thành
A A1 | A2 | | Am | 1 | 2 | | n
trong đó 1 … n không bắt đầu với A
Thay luật sinh trên bởi các luật sinh sau:
A 1A' | 2A' | | nA' A' 1A'| 2A' | | mA'|
VD : Thay luật sinh A A | bởi
A A'
A' A' |
Trang 173.2.1 Văn phạm phi ngữ cảnh
Loại bỏ đệ qui trái gián tiếp:
2 Áp dụng thuật toán sau:
Trang 20Bài 3 Phân tích cú pháp
3.1 Vị trí của phân tích cú pháp
3.2 Một số vấn đề trong phân tích cú pháp
3.2.1 Văn phạm phi ngữ cảnh
3.2.2 Phân tích cú pháp từ trên xuống
3.2.3 Một số chiến lược phục hồi lỗi 3.2.4 Phân tích cú pháp từ dưới lên 3.3 Công cụ xây dựng SA
3.4 Bài tập thực hành
Trang 213.2.2 Phân tích cú pháp từ trên xuống
21
Top-down parser: Cây cú pháp được tạo từ gốc tới lá Có một
số kĩ thuật SA từ trên xuống như:
parsing);
Recursive-Descent Parsing:
quay lui thử áp dụng luật sinh khác)
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS
Trang 223.2.2 Phân tích cú pháp từ trên xuống
Predictive Parsing: O(n)
hóa trái (left-factored);
(Left-to-right parse, Leftmost-derivation, k-symbol lockahead);
Phép thừa số hóa trái (left-factoring) là phép biến đổi CFG để
có được một văn phạm thuận tiện cho việc phân tích dự đoán
Ý tưởng: khi không rõ luật sinh nào trong hai luật sinh có thể
dùng để khai triển một k{ hiệu chưa kết thúc A, ta có thể viết lại các A-luật sinh nhằm "hoãn" lại việc quyết định cho đến khi thấy đủ yếu tố cho một lựa chọn đúng
Trang 233.2.2 Phân tích cú pháp từ trên xuống
VD: Ta có hai luật sinh
stmt → if expr then stmt else stmt
| if expr then stmt
sau khi đọc if, ta không thể ngay lập tức quyết định sẽ dùng luật sinh nào để mở rộng stmt
Phép thừa số hóa trái:
Trang 253.2.2 Phân tích cú pháp từ trên xuống
SA đoán trước không đệ quy còn gọi là LL(1) parser hoặc table-driven parser(phân tích dựa trên bảng) hoạt động theo
STACK
$
b +
a
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 25
Trang 263.2.2 Phân tích cú pháp từ trên xuống
vào một k{ hiệu đặc biệt $
xuất (left-most derivation)
Các k{ hiệu của văn phạm;
Stack lúc khởi tạo chỉ chứa $ và k{ hiệu bắt đầu S
Khi stack rỗng (i.e chỉ còn $), quá trình phân tích kết thúc
Trang 273.2.2 Phân tích cú pháp từ trên xuống
Thuật toán phân tích: Stack (S$) và bộ đệm chứa chuỗi nhập dạng w$, con trỏ ip trỏ tới k{ hiệu đầu tiên của w$;
while (X ≠ $)
X = top (Stack) và ip trỏ đến a;
else if ( M[X,a] = X → Y1 Y2 Yk ){ // X là non-terminal ;
pop(X);
Trang 283.2.2 Phân tích cú pháp từ trên xuống
VD : Cho văn phạm sau: S aBa; B bB |
Stack input output
Trang 293.2.2 Phân tích cú pháp từ trên xuống
Trang 303.2.2 Phân tích cú pháp từ trên xuống
Trang 313.2.2 Phân tích cú pháp từ trên xuống
Với chuỗi nhập có dạng id+id:
Trang 322.2.2 Phân tích cú pháp từ trên xuống
Hàm FIRST và FOLLOW: Là các hàm xác định các tập hợp
cho phép xây dựng bảng phân tích M và phục hồi lỗi theo chiến lược panic-mode
Nếu là một xâu thì FIRST() là tập hợp các k{ hiệu kết thúc
mà nó có thể bắt đầu ở một chuỗi được dẫn xuất từ Nếu
* thì thuộc FIRST()
Nếu A là một kí hiệu chưa kết thúc thì FOLLOW(A) là tập các
kí hiệu kết thúc mà nó có thể xuất hiện ngay bên phải A trong một dẫn xuất từ S Nếu S *A thì $ thuộc FOLLOW(A)
Trang 333.2.2 Phân tích cú pháp từ trên xuống
1 Nếu X là kí hiệu kết thúc thì FIRST(X) là {X}
2 Nếu X → ε là một luật sinh thì thêm ε vào FIRST(X)
3 Nếu X → Y1Y2Y3 Yk là một luật sinh thì:
thêm tất cả các k{ hiệu kết thúc khác ε của FIRST(Y1) vào FIRST(X)
Nếu ε ∈ FIRST(Y1) thì tiếp tục thêm vào FIRST(X) tất cả các k{ hiệu kết thúc khác ε của FIRST(Y2)
Nếu ε ∈ FIRST(Y1) ∩ FIRST(Y2) thì thêm tất cả các k{ hiệu kết thúc khác ε ∈ FIRST(Y3)
Cuối cùng thêm ε vào FIRST(X) nếu ε ∈ 𝑘𝑖=1 FIRST(Yi)
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 33
Trang 353.2.2 Phân tích cú pháp từ trên xuống
hiệu chưa kết thúc)
1 Đặt $ vào FOLLOW(S) (S là kí hiệu bắt đầu)
2 Nếu A B thì mọi phần tử thuộc FIRST() ngoại trừ
đều thuộc FOLLOW(B)
3 Nếu A B hoặc A B và * thì mọi phần tử thuộc FOLLOW(A) đều thuộc FOLLOW(B)
4 áp dụng các quy tắc trên đến khi không thể thêm gì vào các tập FOLLOW
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 35
Trang 373.2.2 Phân tích cú pháp từ trên xuống
Thuật giải xây dựng Parsing table M của văn phạm G:
Trang 383.2.2 Phân tích cú pháp từ trên xuống
Áp dụng giải thuật trên ta xây dựng được Parsing table M cho văn phạm trên như sau:
Trang 393.2.2 Phân tích cú pháp từ trên xuống
Văn phạm LL(1): Văn phạm mà bảng phân tích trên mỗi ô
có không quá 1 dòng (1 luật sinh) được gọi là văn phạm LL(1)
VD: Văn phạm sau không phải là văn phạm LL(1)
Trang 403.2.2 Phân tích cú pháp từ trên xuống
mọi k{ hiệu kết thúc trong FIRST( 1) cũng có trong FIRST(2).
Trang 413.2.2 Phân tích cú pháp từ trên xuống
chỉ khi những điều kiện sau thỏa mãn đối với 2 luật phân biệt bất kz A và A
hiệu trong FOLLOW(A)
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 41
Trang 42Bài 2 Phân tích cú pháp
2.1 Vị trí của phân tích cú pháp
2.2 Một số vấn đề trong phân tích cú pháp
2.2.1 Văn phạm phi ngữ cảnh 2.2.2 Phân tích cú pháp từ trên xuống 2.2.3 Một số chiến lược phục hồi lỗi 2.2.4 Phân tích cú pháp từ dưới lên
2.3 Công cụ xây dựng SA
2.4 Bài tập thực hành
Trang 43y.tab.c C compiler a.out
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 43
Trang 44Bài 2 Phân tích cú pháp
2.1 Vị trí của phân tích cú pháp
2.2 Một số vấn đề trong phân tích cú pháp
2.2.1 Văn phạm phi ngữ cảnh 2.2.2 Phân tích cú pháp từ trên xuống 2.2.3 Một số chiến lược phục hồi lỗi 2.2.4 Phân tích cú pháp từ dưới lên 2.3 Công cụ xây dựng SA
2.4 Bài tập thực hành
Trang 452.4 Bài tập thực hành
Khó khăn chính khi dùng một bộ phân tích cú pháp dự đoán là việc viết một văn phạm cho ngôn ngữ nguồn Việc loại bỏ đệ quy trái và tạo yếu tố trái tuy dễ thực hiện nhưng chúng biến đổi văn phạm trở thành khó đọc và khó dùng cho các mục đích biên dịch
19/05/2012
©TS Hà Chí Trung, Khoa CNTT - HVKTQS 45