Principles of compilers
G IẢN G V I Ê N : T S . H À C H Í T R U N G
BỘ M Ô N : K H M T
K H O A C N T T , H V K T Q S
ĐT : 0 1 6 8 . 5 5 8 . 2 1 . 0 2
E M A I L : H C T 2 0 0 9 @ Y A H O O . C O M
Bà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
19/05/2012 2 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
Bà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
3.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)
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 4
3.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.
Nhiệm vụ chính của SA (Syntax Analyzer, parser): 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
3.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
token
Token Parser
Symbol table
Parse
tree
Semantic
analyzer
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 6
3.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
Bà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
19/05/2012 8 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
3.2.1. Văn phạm phi ngữ cảnh
Để định nghĩa cấu trúc của PL ta dùng CFG: Chỉ rõ các đăc điểm cú pháp của một PL;
Thiết kế văn phạm với ngôn ngữ đã cho;
Có thể chuyển đổi từ một CFG sang một bộ parser nhờ một số công cụ có sẵn (..!.).
VD: CFG sau định nghĩa các biểu thức số học đơn giản: E → E A E | (E) | -E | id
A → + | - | * | / |^
Trong đó E, A là các kí tự chưa kết thúc (E còn là kí tự bắt đầu), các kí tự còn lại là các kí tự kết thúc
Một số khái niệm liên quan: dẫn xuất trực tiếp, gián tiếp trái nhất, phải nhất.
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 9
3.2.1. Văn phạm phi ngữ cảnh
Dẫn xuất và các dạng dẫn xuất (bài 5 – L{ thuyết Automata và ngôn ngữ hình thức): Dẫn xuất trái nhất:
E -E -(E) -(E+E) -(id+E) -(id+id)
Dẫn xuất phải nhất:
E -E -(E) -(E+E) -(E+id) -(id+id)
Đặc điểm: Top-down parsing cố gắng tìm ra dẫn xuất trái nhất của
chương trình nguồn.
Bottom-up parsing cố tìm ra cây dẫn xuất phải nhất của chương trình nguồn.
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 10
3.2.1. Văn phạm phi ngữ cảnh
Parse tree là dạng biểu diễn hình học của dẫn xuất.
VD: parse tree cho biểu thức –(id+id) là:
E -E E
E -
E
E
E E
E
+
-
( )
E
E
E -
( )
E
E
id
E
E
E +
-
( )
id
E
E
E
E E +
-
( )
id
-(E) -(E+E)
-(id+E) -(id+id)
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 11
3.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.
E E+E id+E id+E*E id+id*E id+id*id
E E*E E+E*E id+E*E id+id*E id+id*id
E
id
E +
id
id
E
E
* E
E
E +
id E
E
* E
id id
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 12
13
VD: Xét văn phạm sau:
stmt if expr then stmt | if expr then stmt
else stmt | otherstmt
Với cùng một câu lệnh:
if E1 then if E2 then S1 else S2
sẽ có hai parse tree:
1:
2:
3.2.1. Văn phạm phi ngữ cảnh
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
stmt if expr then stmt else stmt E1 if expr then stmt S2
E2 S1
stmt if expr then stmt E1 if expr then stmt else stmt E2 S1 S2
3.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
else matched_stmt
| otherstmt
unmatched_stmt if expr then stmt
| if expr then matched_stmt
else unmatched_stmt
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 14
3.2.1. Văn phạm phi ngữ cảnh
Văn phạm đệ quy trái: Một văn phạm được gọi là đệ qui 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
3.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' |
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 16
3.2.1. Văn phạm phi ngữ cảnh
Loại bỏ đệ qui trái gián tiếp:
1. Sắp xếp các k{ hiệu không kết thúc theo thứ tự A1, A2, ..., An
2. Áp dụng thuật toán sau: for i:=1 to n do { for j:=1 to i -1 do {
Thay luật sinh dạng Ai Aj bởi
Ai 1 | 2 |.....| k , trong đó
Aj 1 | 2 |.....| k } Loại bỏ đệ qui trái trực tiếp trong số các luật sinh Ai
};
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 17
3.2.1. Văn phạm phi ngữ cảnh
VD: Cho văn phạm sau: S Aa | b A Ac | Sd | f
Nếu ta sắp theo thứ tự S, A, khi đó đối với S không có đệ quy trái trực tiếp, Với A: thay thế A Sd bằng A Aad | bd. Khi đó ta thu được các
luật A Ac | Aad | bd | f Sau đó khử đệ quy trực tiếp của A nhận được:
A bdA’ | fA’ | A’ cA’ | adA’ | Kết quả ta nhận được văn phạm không đệ quy trái:
S Aa | b A bdA’ | fA’
A’ cA’ | adA’ |
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 18
3.2.1. Văn phạm phi ngữ cảnh
Nếu ta sắp theo thứ tự A, S, khi đó ta khử đệ quy trái trực tiếp đối với A:
A SdA’ | fA’
A’ cA’ | Với S, thay thế S Aa bằng S SdA’a | fA’a. Khi đó ta thu
được các luật S SdA’a | fA’a | b Sau khi khử đệ quy trực tiếp của S nhận được:
S fA’aS’ | bS’
S’ dA’aS’ | Kết quả ta nhận được văn phạm không đệ quy trái:
S fA’aS’ | bS’
S’ dA’aS’ | A SdA’ | fA’
A’ cA’ |
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 19
Bà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
19/05/2012 20 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
3.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ư: SA đệ quy lùi (Recursive-Descent parsing); SA đoán trước (Predictive parsing); SA đoán trước đệ quy (recursive predictive parsing); SA đoán trước không đệ quy (non-recursive predictive
parsing); ...
Recursive-Descent Parsing: Backtracking (nếu lựa chọn luật sinh này không thỏa mãn thì
quay lui thử áp dụng luật sinh khác). Kỹ thuật tổng quát, nhưng ko được sử dụng rộng rãi; Không hiệu quả…
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
3.2.2. Phân tích cú pháp từ trên xuống
Predictive Parsing: O(n)
Không quay lui, nhưng đòi hỏi văn phạm phải được thừa số hóa trái (left-factored);
Chỉ áp dụng cho một lớp con của CFG là văn phạm LL(k) (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.
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 22
3.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: Giả sử có luật sinh
A 1 | 2 |..... | n | ( là tiền tố chung dài nhất của các luật sinh, không bắt đầu bởi )
Luật sinh trên được biến đổi thành: A A' | A' 1 | 2 |..... | n
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 23
VD:
A abB | aB | cdg | cdeB | cdfB
A aA’ | cdg | cdeB | cdfB
A’ bB | B
A aA’ | cdA’’
A’ bB | B
A’’ g | eB | fB
VD:
A ad | a | ab | abc | b
A aA’ | b
A’ d | | b | bc
A aA’ | b
A’ d | | bA’’
A’’ | c
3.2.2. Phân tích cú pháp từ trên xuống
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 24
3.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 mô hình sau:
Bộ phân tích cú pháp được điều khiển bởi Predictive parsing program
$
Z
Y
X Predictive parsing
program
Parsing table M
OUTPUT
INPUT
STACK
$ b + a
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 25
3.2.2. Phân tích cú pháp từ trên xuống
Input buffer: Dòng dữ liệu cần phân tích. Ở cuối ta thêm vào một k{ hiệu đặc biệt $.
Output: Luật sinh được áp dụng trong từng bước dẫn xuất (left-most derivation).
Stack: 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.
Parsing table Mảng hai chiều M[A, a], mỗi hàng là 1 k{ hiệu chưa kết thúc,
mỗi cột là 1 k{ hiệu kết thúc hoặc là k{ hiệu đặc biệt $ Mỗi ô chỉ chứa không quá 1 luật sinh.
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 26
3.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; if (X là k{ hiệu kết thúc hoặc $) if (X = a) pop(X) và dịch chuyển ip; else error ( ) ; //gọi chương trình phục hồi lỗi; else if ( M[X,a] = X → Y1 Y2 .... Yk ){ // X là non-terminal ; pop(X); push Yk ,Yk-1, ... ,Y1 vào Stack; Xuất ra luật sinh X → Y1 Y2 ... Yk; } else error ( ) /* Stack rỗng */ }
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 27
3.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 |
Xét quá trình phân tích chuỗi nhập Stack input output $S abba$ S aBa $aBa abba$ $aB bba$ B bB $aBb bba$ $aB ba$ B bB $aBb ba$ $aB a$ B $a a$ $ $ thành công
Outputs: S aBa B bB B bB B Derivation(left-most): SaBaabBaabbBaabba
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 28
a b $
S S aBa
B B B bB
S
B a a
B
B b
b
3.2.2. Phân tích cú pháp từ trên xuống
VD: Xét văn phạm
E E+T | T T T*F | F F (E) | id
Áp dụng loại bỏ đệ qui trái ta thu được
E TE' E' +TE' | T FT' T' *FT' | F (E) | id
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 29
3.2.2. Phân tích cú pháp từ trên xuống
Parsing table M cho văn phạm trên như sau:
Non- terminal
Input symbol
id + * ( ) $
E E TE' E TE'
E' E' +TE' E' E'
T T FT' T FT'
T' T' T' *FT' T' T'
F F id F (E)
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 30
3.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: stack input output $E id+id$ E TE’ $E’T id+id$ T FT’
$E’ T’F id+id$ F id $ E’ T’id id+id$ $ E’ T’ +id$ T’ $ E’ +id$ E’ +TE’
$ E’ T+ +id$ $ E’ T id$ T FT’
$ E’ T’ F id$ F id $ E’ T’id id$ $ E’ T’ $ T’ $ E’ $ E’
$ $ accept
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 31
2.2.2. Phân tích cú pháp từ trên xuống
Xây dựng bảng phân tích cho văn phạm LL(1):
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)
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 32
3.2.2. Phân tích cú pháp từ trên xuống
Quy tắc xác định hàm FIRST:
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 ε ∈ FIRST(Yi) 𝑘𝑖=1
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 33
34
VD: Cho văn phạm: E TE’
E’ +TE’ |
T FT’
T’ *FT’ |
F (E) | id
Ta tính được hàm FIRST: FIRST(F) = {(,id} FIRST(T’) = {*, } FIRST(T) = {(,id} FIRST() = {} FIRST(E’) = {+, } FIRST(E) = {(,id} FIRST(TE’) = {(,id} FIRST(+TE’ ) = {+} FIRST(FT’) = {(,id} FIRST(*FT’) = {*} FIRST((E)) = {(} FIRST(id) = {id}
3.2.2. Phân tích cú pháp từ trên xuống
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
3.2.2. Phân tích cú pháp từ trên xuống
Qui tắc tính các tập hợp FOLLOW (chỉ áp dụng cho k{ 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
36
VD: Cho văn phạm: E TE’
E’ +TE’ |
T FT’
T’ *FT’ |
F (E) | id
Ta tính được hàm FOLLOW:
FOLLOW(E) = { $, ) }
FOLLOW(E’) = { $, ) }
FOLLOW(T) = { +, ), $ }
FOLLOW(T’) = { +, ), $ }
FOLLOW(F) = {+, *, ), $ }
VD: Xét văn phạm E TE' E' +TE' | T FT' T' *FT' | F (E) | id Khi đó: FIRST(E) = FIRST(T) = FIRST(F)
= { (, id } FIRST(E') = {+, } FIRST(T') = {*, } FOLLOW(E) = FOLLOW(E') = { $, ) } FOLLOW(T) = FOLLOW(T') = { +, ), $ } FOLLOW(F) = {*,+, ), $ }
3.2.2. Phân tích cú pháp từ trên xuống
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
3.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:
A. Với mỗi luật sinh A của văn phạm, thực hiện bước sau:
1. Với mỗi k{ hiệu kết thúc a FIRST(), thêm A vào M[A,a]
2. Nếu FIRST() thì đưa luật sinh A vào M[A,b] với mỗi k{ hiệu kết thúc bFOLLOW(A).
3. Nếu FIRST() và $FOLLOW(A) thì đưa luật sinh A vào M[A,$].
B. Ô còn trống trong bảng tương ứng với lỗi (error).
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 37
3.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:
Non-
terminal Input symbol
id + * ( ) $
E E TE' E TE'
E' E' +TE' E' E'
T T FT' T FT'
T' T' T' *FT' T' T'
F F id F (E)
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 38
3.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). S i C t S E | a FOLLOW(S) = { $,e } E e S | FOLLOW(E) = { $,e } C b FOLLOW(C) = { t } FIRST(iCtSE) = {i} FIRST(a) = {a} FIRST(eS) = {e} FIRST() = {} FIRST(b) = {b}
a b e i t $
S S a S iCtSE
E E e S E
E
C C b
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 39
3.2.2. Phân tích cú pháp từ trên xuống
Văn phạm không phải là LL(1):
Văn phạm đệ quy trái không thể là LL(1) grammar.
A A |
mọi k{ hiệu kết thúc trong FIRST() cũng có mặt trong FIRST(A) vì rằng A .
Nếu là , mọi k{ hiệu kết thúc trong FIRST() cũng có trong FIRST(A) và FOLLOW(A).
Văn phạm chưa thừa số hóa trái, không thể là LL(1) grammar
A 1 | 2
mọi k{ hiệu kết thúc trong FIRST(1) cũng có trong FIRST(2).
Văn phạm nhập nhằng không thể là LL(1) grammar.
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 40
3.2.2. Phân tích cú pháp từ trên xuống
Tính chất của văn phạm LL(1): Văn phạm G là LL(1) khi và 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
1. Cả và không dẫn ra từ các xâu có k{ hiệu đầu giống nhau.
2. Tối đa chỉ có 1: hay có thể dẫn tới .
3. Nếu dẫn tới , thì không thể dẫn ra xâu bắt đầu bằng k{ hiệu trong FOLLOW(A).
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 41
Bà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
19/05/2012 42 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
2.3. Công cụ xây dựng SA
Công cụ phân tích cú pháp Yacc (Yet Another Compiler - Compiler):
công cụ (trong UNIX) cho phép xây dựng bộ phân tích cú pháp một cách tự động;
Yacc được tạo bởi S. C. Johnson vào những năm đầu của thập kỉ 70, sử dụng phương pháp LALR.
Yacc specification
translate.y Yacc compiler y.tab.c
y.tab.c C compiler a.out
input a.out output
19/05/2012 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS 43
Bà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
19/05/2012 44 ©TS. Hà Chí Trung, Khoa CNTT - HVKTQS
2.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