Tải bản đầy đủ (.docx) (12 trang)

TỪ VỰNG và PHÂN TÍCH cú PHÁP

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (866.68 KB, 12 trang )

Chương 4 :TỪ VỰNG VÀ PHÂN TÍCH CÚ PHÁP
Nội dung :
• Giới thiệu
• Phân tích từ vựng
• Phân tích cú pháp
• Phân tích cú pháp từ trên xuống
• Phân tích cú pháp từ dưới lên
I. Giới thiệu :
 Kỹ thuật phân tích từ vựng, ngữ nghĩa, cú pháp thuộc về mảng đầu tiên của trình biên
dịch
 Mọi sự phân tích cú pháp đều dựa vào CFG hoặc BNF
 Bộ phân tích cú pháp được chia làm 2 phần :
o Phần mức thấp gọi là bộ phân tích từ vựng(Scaner) là một automatch hữu hạn
dựa vào văn phạm chính qui
o Phần mức cao cao gọi là bộ phân tích cú pháp là một automatch đẩy xuống dựa
vào ngôn ngữ phi ngữ cảnh hoặc BNF
 Lý do chia bộ phân tích cú pháp thành 2 phần :
o Đơn giản – phân tích từ vựng đơn giản hơn =>việc xây dựng bộ phân tích từ
vựng đon giản hơn
o Hiệu quả :việc phân chia thành 2 khối giúp tối ưu hóa
o Tính khả chuyển :bộ phân tích từ vựng không khả chuyễn nhưng bô phân tích cú
pháp có thể khả chuyễn(đẩu ra của bộ phân tích từ vựng là các token có thể đưa
vào các máy phân tích cú pháp khác nhau )
II. Phân tích từ vựng
 Phân tích từ vựng là so sách với các mẫu(thường được mô tả bởi biểu thức chính quy)
o Ví dụ
 Tên biến có dạng (a| |Z)(0| |9|a |z)*
 Số nguyện có dạng :0+(1| |9)(0| |9)*
 Xác định chuỗi con có thuộc một nhóm(Lexemes)
o Ví dụ a1 :thuộc tên biến,98 thuộc số nguyên
 Với các chuổi con thuộc mẩu giống nhau sẽ được vào một token(phân loại)


Chương trình nguồn
Scanner(PTTV) Parser(PTCP)
 Bộ phân tích từ vựng giống như 1 hàm sẽ được gọi bởi bộ phân tích cú pháp khi cần
token kế tiếp
 Quá trình phân tích từ vựng:
o Bỏ qua các ghi chú, các tab, xuống dòng, và khoảng trống
o Lưu lại các thông tin về tập tin,dòng, cột để thông báo lỗi
o Phát hiện và báo cáo các lỗi từ vựng trong token cho người sử dụng
III. Ba cách xây dựng bộ phân tích từ vựng(Scanner)
o Dùng phần mềm pháp sinh tự động(đầu vào là một văn phạm chính quy)
o Xây dựng sơ đồ trạng thái DFA
o Xây dựng bảng thực thi dòng, cột
 Luật tìm lexeme dài nhất
o Scanner chỉ trả về token khi đọc đến ký tự kết thúc token( thường là khoàng
trắng)
o Trong một số trường hợp Scanner phải đọc nhiều hơn một ký tự để nhận biết đã
kết thúc token
o Ví dụ :trong pascal khi ta đọc được số 3 và sau đó là dấu .
 Ta tiếp tục sử lý với huy vọng là số 3.1
 Hay dừng với 3 5
 Trong một số trường hợp ta phải đọc cả chuổi nhập mới xác định được ý nghĩa của
chuổi
o Ví dụ trong Fortran
 DO 5 I = 1,25 //VÒNG lăp
 DO 5 I = 1.25 //biến=1.25
 Ta phải lưu lại tất cả các thông tin nếu không sẽ gặp các khó khăn về sau
IV. Thiết kế sơ đồ truyền
 Xây dựng bộ phân tích từ vựng để nhận dạng tên trong chương trình như tên
biến,chương trình con, từ dành riêng, chuổi số nguyên
 Một đường truyền đơn giản là từ một trạng thái ở bước I sẽ có đường truyền đến tất cả

các trạng thái ở bước i+1 =>sơ đồ rất lớn
 Phải tích hợp các trạng thái để đơn gian sơ đồ truyền
o Các ký tự hoa, thường :lớp ký tự
o Các số nguyên :lớp số
o Từ dành riêng : nhận dạng chung với lớp ký tự
 Từ trạng thái đầu chỉ có hai đường truyền đến lớp ký tự và lớp số
 Các hàm con được dùng để xử lý token
o getChar :lấy ký tự kế tiếp trong dữ liệu nhập đưa vào biến toàn cục nextChar
o addChar :lấy ký tự từ biến nextChar đưa vào biến toàn cục là lexeme đề tạo
thành token
o lookup :xác định từ trong lexeme là từ dành riêng
V. Phân tích cú pháp
 Nhiệm vụ
o Tìm tất cả các lỗi cú pháp , đưa ra các thông báo lỗi
o Xây dựng cây phân tích cú pháp(lưu vết ) cho chương trình
 Có hai kỹ thuật phân tích
o Top-down :xây dựng cây phân tích cú pháp bắt đầu từ gốc
o Bottom up :xây dựng cây phân tích cú pháp bắt đầu từ lá
 Bô phân tích cú pháp thường nhìn trước một token trong chuổi các token
trong đầu ra của scanner
 Các quy ước
o Ký hiệu kết thúc :dùng các chữ thường đầu tiên trong bảng aphab
(a,b,c…),
o Ký hiệu không kết thúc :dùng chữ hoa đầu tiên(A,B,C…)
o Chuổi ký tự kết thúc :các ký tự thường cuối cùng trong bảng
aphab(x,y,z)
o Chuỗi chứa ký tự không kết thúc (α,β )
1. Phân tích Top-down
o Cho dạng câu xAα, chọn luật sinh có vế trái là A(là ký tự không

kết thúc trái nhất) để tạo dẫn xuất kế tiếp
o Thuật toán được dùng
o –Recursive descent :Đệ quy xuống
o –LL parsers :bảng điều khiển thực thi
2. Phân tích Buttom-up
o Cho trước một dạng câu phải α,xác định chuổi con nào của α là vế
phải của một luật sinh nào đó->thay thế chuỗi con bằng vế phải
của luật sinh
o Ví dụ αβ£ và luật sinh A->β thì chuổi sẽ trở thành αA£
o Thuật toán được dùng là LR(đọc từ trái qua phải)
Ví dụ : cho bộ luật sinh sau:
id_list  id id_list_tail
id_list_tail  , id id_list_tail
id_list_tail  ;
o Ví dụ : cho bộ luật sinh
(1)E E+T
(2)E T
(3)TT*F
(4)T F
(5)F(E)
(6)F ID
(7)F N
o Cho biểu thức 1+(2+3)*4+5
o Dùng dẫn xuất phải
(1) E E+T->(4) E E+F->(7) E E+5->(1) E E+T+5->(3) E E+T*F+5->(7)
EE+T*4+5->(4) E E+F*4+5->(5) E E+(E)*4+5->(1) EE+(E+T)*4+5->(4) EE+
(E+F)*4+5->(7) E E+(E+3)*4+5->(2) E E+(T+3)*4+5->(4) EE+(F+3)*4+5 ->(7)
EE+(2+3)*4+5 ->(2) E T+(2+3)*4+5 ->(4) E F+(2+3)*4+5 ->(7)
E1+(2+3)*4+5
o Vẽ lại luật sinh lùi lại ta được phân tích cú pháp từ dưới lên

3. Phân tích cú pháp đệ quy xuống :
o Là một chương trình con duyệt qua tất cả các ký tự không kết thúc trong ngôn ngữ,
thay thế ký tự không kết thúc= ký tự kết thúc bắt đầu từ ký hiệu bắt đầu
o BNF là lý tưởng cho là cơ sở cho một phân tích cú pháp đệ quy gốc, bởi vì EBNF
giảm thiểu số lượng ký tự không kết thúc
o Cho một ngôn ngữ với các luật sinh sau :
<expr>  <term> {(+ | –) <term>}
<term> <factor> {(* | /) <factor>}
<factor>  id | ( <expr> )
Có ba chương trình con expr,term,factor.chương trình con expr sẽ thực hiện đầu
tiên
o Giả sử ta đang phân tích từ vựng có tên là lex, token kế tiếp có tên là NextToken,
các xử lý
 Duyệt tất cả các ký tự kết thúc trong vế phải của luật sinh, nếu tìm thấy
NextToken thì tiếp tục, nếu không báo lỗi
 Duyệt tất cả các ký tự không kết thúc trong vế phải, gọi chương trình con
liên quan đến ký hiệu không kết thúc này
o Ví dụ hàm expr() phân tích chuỗi trong ngôn ngữ có luật sinh
<expr>  <term> {(+ | -) <term>}
void expr() {
/* Parse the first term */
term();
/* As long as the next token is + or -,
call lex() to get the next token, and
parse the next term */
while (nextToken == PLUS_CODE ||
nextToken == MINUS_CODE) {
lex();
term();
}

}
o Một ký tự không kết thúc có nhiều hơn một một vế phải đòi hỏi một quá trình phân
tích để xác định vế phải được chọn
-việc lựa chọn vế phải dựa trên cơ sở là so sánh ký tự tiếp theo của Token kế tiếp
Ví dụ
A->aBC|CD
C->bEF
Nếu NextToken=a sẽ chọn luật sinh A->aBC
Nếu NextToken=b sẽ chọn luật sinh A->CD và C->bEF
NextToken=d sẽ báo lỗi
Ví dụ :
Function factor()
/* Parses strings in the language generated
by the rule:
<factor> -> id | (<expr>) */
void factor() {
/* Determine which RHS */
if (nextToken == ID_CODE)
/* For the RHS id, just call lex */
lex();
/* If the RHS is (<expr>) – call lex() to pass
over the left parenthesis, call expr(), and
check for the right parenthesis */
else
if (nextToken == LEFT_PAREN_CODE) {
lex();
expr();
if (nextToken == RIGHT_PAREN_CODE)
lex();
else

error();
}
else error(); /* Neither RHS matches */
4. Văn phạm (LL Grammand):
o Nếu một ngữ pháp là đệ quy trái , nó không thể là cơ sở cho một phân tích cú
pháp từ trên xuống
 Có thể sửa đổi để loại bỏ đệ quy trái
 Ví dụ cho luật sinh A->A+B
 Một chương trình con cho nonterminal A ngay lập tức
cuộc gọi riêng của mình để phân tích các biểu tượng đầu tiên trong RHS của
nó(đệ quy vô hạn)
o Các cặp tách rời
 FIRST(α)={a|α=>*aβ}: FIRST(α):là ký tự kết thúc đầu tiên trong chuỗi α
 Trong một tập luật sinh :
• A->α
• A->β
• Chỉ đúng khi FIRST(α)∩FIRST(β)=θ
 Ví dụ
• Ví dụ 1: A  aB | aAb
o FIRST(aB)=a
o FIRST(aAb)=a
o FIRST(aB) ∩FIRST(aAb)=a# θ =>luật sinh sai
• Ví dụ 2 : A  aB | bAb | c với
FIRST(aB)=a,FIRST(bAb)=b,FIRST(c)=c =>luật sinh đúng
5. Thừa tố trái :dùng để giải quyết cặp tách rời
o ví dụ cho luật sinh sau:
 <variable>  identifier | identifier [<expression>]
 có thể được viết thành
<variable>  identifier <new>
<new> ε| [<expression>]

Hoặc
<variable>  identifier [[<expression>]]([]:ký hiệu mở rộng
6. Phân tích từ dưới lên
o Quá trình phân tích từ dưới lên :đảo ngược của quá trình dẫn xuất phải
o Bắt đầu từ câu đi ngược lại về gốc
o Trong mỗi bước sẽ tìm luật sinh có vế phải thuộc câu, thay thế vế phải bằng vế trái
o Ví dụ cho bộ luật sinh
 EE + T | T
 T  T * F | F
 F  (E) | id
o Cho chuỗi : E + T * id ta phân tích như sau :
 F->id =>id thay bằng F ta có E+T*F
 T->T*F : thay T*F=T ta co E+T
 E->E+T :=>E
 Nếu chọn thay thế E+T bằng E :E*id không về đầu được :sai
7. Các Định Nghĩa
o β là một handle của một dạng câu phải ¥ nếu và chỉ nếu :
 S =>rm* αAw =>rm*αβw (=¥)(có một luật sinh mà A được thay thế = β
trong một bước)
o β là một phrase của một dạng câu phải ¥ nếu và chỉ nếu :
 S =>* αAw =>+αβw (=¥)(dẫn xuất qua nhiều bước)
o β là một simple phrase của một dạng câu phải ¥ nếu và chỉ nếu :
 S =>* αAw =>αβw (=¥)(dẫn xuất một bước, một trong các simple phrase là
handle)
o Ví dụ cho bộ luật sinh
 EE + T | T
 T  T * F | F
 F  (E) | id
 Biểu thức E+T*id được phân tích thành:
 Các phrase của biểu thức E+T*id là :E+T*id,T*id,id(E+T không phải là một

phrase vì không được dẫn ra từ một ký hiệu không kết thúc)
 Chỉ có một simple phrase là id
 Handle của một dạng câu phải là simple phrase trái nhất
o Ví dụ 2 :
o Ví dụ cho bộ luật sinh
 EE + T | T
 T  T * F | F
 F  (E) | id
 Biểu thức E+T*id được phân tích thành(dùng dẫn xuất phải):
 Bước 1 :Ta có ba simple phase là id1,id2,id3(từ trái qua phải) id1 là handle
và thay thế id1= F Ta có F+id*id
 Bước 2 :ta có 3 simple phase là F,id1,id2, thay F bằng T ta có T+id*id
 Bước 3:ta có 3 simple phase là T,id1,id2, thay T bằng E, ta có E+id*id
 Bước 4 :ta có id2,id3 là simple phase, thay id2= F :E+F.ID, Thay F=T,
E+T*id,id3 thay th bằng F,T*F thay T,E+T thay bằng E là gốc
8. Thuật toán rút gọn,chuyển dời(Shift-Reduce Algorithms)
 Rút gọn :là thao tác thay đổi handle trên đỉnh của ngăn xếp bằng 1 vế trái
phù hơp
• Ví dụ
 Shift : là thao tác di chuyển token vào đầu ngăn xếp
9. Ưu điểm LR parsers
 Làm việc với hầu hết mọi văn phạm, dùng để mô tả các ngôn ngữ lập trình
 Có thể phát hiện lỗi nhanh chóng
 Các văn phạm được nhận dạng bởi LR thì bao gồm cả những văn phạm
được nhận dạng bởi LL
10. Cấu trúc bộ phân tích LR
Cấu hình LR Parser :
 Dùng một Stack để lưu trữ ký hiệu trạng thái S
i
và ký hiệu văn phạm X

i
S0X1S1…XmSm<-đỉnh của Stack
 Bảng phân tích (parsing Table) gồm 2 phần :
• Action :là phần có Ký hiệu trạng thái như nhãn của dòng và ký hiệu
kết thúc như nhãn của cột

×