16
9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 1/16 TRÌNH BIÊN DỊCH Phụ lục B Giới thiệu TP YACC 1. Mục Tiêu 2. Kiến thức cơ bản cần có để học chương này 3. Tài liệu tham khảo liên quan đến chương 4. Nội dung: 1. Mô tả TP Yacc 2. Chương trình nguồn Yacc 3. Phân tích từ vựng 4. Hoạt động của bộ phân tích cú pháp 5. Văn phạm mơ hồ 6. Xử lý lỗi 7. Thư viện Yacc 8. Những hạn chế của sự cài đặt 5. Vấn đề nghiên cứu của chương kế tiếp 1. Mô tả TP Yacc TP Yacc là một chương trình cho phép ta chuẩn bị bộ phân tích cú pháp từ sự mô tả ngôn ngữ nguồn bằng văn phạm dạng BNF. Ta chỉ cần xác định văn phạm cho ngôn ngữ đích , đưa thêm vào những đoạn mã Turbo Pascal cần thiết cho việc xử lý các cấu trúc cú pháp, và TP Yacc dịch văn phạm của ta sang mã Turbo Pascal có trong chương trình con phân tích cú pháp tương ứng tên yyparse. TP Yacc phân tích cú pháp văn phạm chương trình nguồn chứa trong yacc_file (với phần mở rộng mặc nhiên là .y) và viết chương trình phân tích cú pháp được tạo ra vào output_file (với phần mở rộng mặc nhiên là .pas); nếu output_file không được xác định thì chương trình phân tích cú pháp được viết vào yacc_file.pas. Trong suốt quá trình biên dịch nếu bất cứ lỗi nào được tìm thấy thì thông báo lỗi tương ứng được viết vào tập tin list.lst. Chương trình con phân tích cú pháp, yyparse, được khai báo như sau: Function yyparse: Integer;

Giới Thiệu Tp Yacc

Embed Size (px)

Citation preview

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 1/16

TRÌNH BIÊN DỊCH

Phụ lục B Giới thiệu TP YACC

1. Mục Tiêu2. Kiến thức cơ bản cần có để học chương này3. Tài liệu tham khảo liên quan đến chương4. Nội dung:

1. Mô tả TP Yacc 2. Chương trình nguồn Yacc 3. Phân tích từ vựng 4. Hoạt động của bộ phân tích cú pháp 5. Văn phạm mơ hồ 6. Xử lý lỗi 7. Thư viện Yacc 8. Những hạn chế của sự cài đặt

5. Vấn đề nghiên cứu của chương kế tiếp

1. Mô tả TP Yacc

TP Yacc là một chương trình cho phép ta chuẩn bị bộ phân tích cú pháp từ sự mô tả ngôn ngữnguồn bằng văn phạm dạng BNF. Ta chỉ cần xác định văn phạm cho ngôn ngữ đích , đưa thêmvào những đoạn mã Turbo Pascal cần thiết cho việc xử lý các cấu trúc cú pháp, và TP Yacc dịch văn phạm của ta sang mã Turbo Pascal có trong chương trình con phân tích cú pháp tương ứng tên yyparse.

TP Yacc phân tích cú pháp văn phạm chương trình nguồn chứa trong yacc_file (với phần mở

rộng mặc nhiên là .y) và viết chương trình phân tích cú pháp được tạo ra vào output_file (vớiphần mở rộng mặc nhiên là .pas); nếu output_file không được xác định thì chương trình phân tíchcú pháp được viết vào yacc_file.pas. Trong suốt quá trình biên dịch nếu bất cứ lỗi nào được tìmthấy thì thông báo lỗi tương ứng được viết vào tập tin list.lst.

Chương trình con phân tích cú pháp, yyparse, được khai báo như sau:

Function yyparse: Integer;

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 2/16

Giá trị trả về của chương trình yy parse biểu diễn sự thành công hay thất bại của chương trìnhphân tích cú pháp (0 = thành công, 1 = lỗi cú pháp không thể phục hồi hoặc Stack phân tích cúpháp bị tràn). Chương trình này có thể được gọi bởi chương trình chính để thực hiện phân tíchcú pháp.

Mẫu của chương trình yyparse có thể được tìm thấy trong tập tin yyparse.cod và TP Yacc rất

cần tập tin này khi xây dựng output_file. Thư viện TP Yacc (YaccLib) luôn được yêu cầu bởi chương trình sử dụng Yacc- sinh bộ

phân tích cú pháp; vì vậy ta cần phải đặt câu lệnh sử dụng tương ứng vào chương trình hay unitcó chứa chương trình phân tích cú pháp. Bên cạnh đó, YaccLib còn cung cấp một số chươngtrình điều khiển các hoạt động của bộ phân tích cú pháp. 2. Chương trình nguồn Yacc

Một chương trình TP Yacc có dạng: Các định nghĩa %%Các luật sinh %% Các thủ tục phụ trợ Ngôn ngữ TP Yacc định dạng tự do: khoảng trắng (\n,\t,\b) được bỏ qua trừ phi nó được xem

như ký hiệu ngăn cách. Các chú thích có định dạng giống /*... */ được xử lý như những khoảngtrắng. Các ký hiệu văn phạm được biểu diễn bởi các danh biểu có dạng thường gặp (bắt đầu là chữ cái, bao gồm ký hiệu _ , theo sau là chuỗi các chữ cái và số; có sự phân biệt giữa chữ hoa vàchữ thường). Từ khoá của TP Yacc luôn luôn bắt đầu bằng kí tự %. Chuỗi được biểu diễn bởi cáckí tự được đặt trong cặp dấu nháy đơn. Một số ký hiệu giống C:

\n biểu thị dòng mới \r biểu thị phím xuống dòng \t biểu thị tab \b biểu thị phím lùi \f biểu thị đẩy trang hiện hành và bắt đầu một trang mới \NNN biểu thị ký tự số NNN ở dạng bát phân

a. Các định nghĩa

Mục này định nghĩa các ký hiệu được sử dụng trong văn phạm. Nó có thể gồm các kiểu địnhnghĩa sau:

· Ðịnh nghĩa ký hiệu chưa kết thúc bắt đầu có dạng % start ký_hiệu. Nếu định nghĩa này bịbỏ qua thì ký hiệu chưa kết thúc ở vế trái của luật sinh đầu tiên được xem như ký hiệu bắt đầucủa văn phạm.

· Các định nghĩa ký hiệu kết thúc (token) của ngôn ngữ đích dạng:% token ký_hiệu. Bất cứdanh biểu nào không được khai báo trong định nghĩa các ký hiệu kết thúc sẽ được xử lý như

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 3/16

những ký hiệu chưa kết thúc.· Ðịnh nghĩa độ ưu tiên: mỗi ký hiệu toán tử (ký hiệu kết thúc) có thể có một độ ưu tiên nào

đó nhờ vào phần định nghĩa độ ưu tiên. Một trong những dạng của định nghĩa độ ưu tiên: %left ký_hiệu%right ký_hiệu%nonassoc ký_hiệu

Dạng nầy cho phép ta khai báo mức ưu tiên của các toán tử kết hợp trái, phải, và không kết

hợp. Ðịnh nghĩa độ ưu tiên đầu tiên tương ứng với mức ưu tiên thấp nhất.

Ví dụ: %nonassoc ‘<’ ‘>’ ‘=’ GEQ LEQ NEQ /* Các toán tử quan hệ */ %left ‘+’ ‘-‘ /* Các toán tử thêm */ %left ‘*’ ‘/’ /* Các toán tử nhiều */ %right NOT UMINUS /* Toán tử nhất phân */

Danh biểu cho ký hiệu kết thúc đã xuất hiện trong định nghĩa độ ưu tiên có thể, nhưng không

cần thiết, xuất hiện trong định nghĩa ký hiệu kết thúc. · Ðịnh nghĩa kiểu: bất cứ ký hiệu văn phạm nào có thể được kết hợp với danh biểu kiểu được

sử dụng trong việc xử lí các giá trị ngữ nghĩa. Dạng <tên_kiểu> có thể được sử dụng trong địnhnghĩa ký hiệu kết thúc và độ ưu tiên để khai báo kiểu của ký hiệu kết thúc. Ví dụ :

%token <Real> NUM%left <Addop> ‘+’ ‘-‘

Ðể khai báo kiểu của ký hiệu chưa kết thúc, ta sử dụng định nghĩa kiểu dạng: %type <tên_kiểu> ký_hiệu Ví dụ:

%type <Real> exprTrong định nghĩa kiểu, những ký hiệu chưa kết thúc có thể được bỏ qua.Dạng % type

<tên_kiểu> có ích khi kiểu đưa ra chỉ được sử dụng với các chuyển đổi kiểu.· Khai báo Turbo Pascal Ta có thể đặt các đoạn mã Turbo Pascal được bao đóng trong %{và %} vào phần các định

nghĩa. Những đoạn mã nầy sẽ được đưa vào output_file như các khai báo toàn cục. b. Các luật sinh văn phạm và các hoạt động

Luật sinh văn phạm dạng tên : ký_hiệu; Vế trái của luật sinh phải là một danh biểu (biểu diễn cho một ký hiệu chưa kết thúc).Vế phải

của luật sinh có thể rỗng hoặc là một chuỗi các ký hiệu văn phạm gồm cả những chuỗi được đặttrong cặp dấu nháy đơn. Ký hiệu ; có thể được bỏ qua. Những luật sinh khác có cùng một vế trái

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 4/16

có thể được viết như sau: tên : ký_hiệu | ký_hiệu . . . ; Ví dụ: Văn phạm đơn giản cho các biểu thức số học có thể được viết:

%left ‘+’ ‘-‘%token NUM%%expr : expr ‘+’ expr | expr ‘-’ expr | expr ‘*’ expr | expr ‘/’ expr | ‘(‘ expr ’) ‘ | NUM ;

Các luật sinh văn phạm có thể chứa nhiều hoạt động, những câu lệnh Turbo Pascal được đặt

trong cặp dấu { }. Một hoạt động được thực hiện khi luật sinh tương ứng được nhận dạng. Luậtsinh có thể trả về giá trị và truy xuất giá trị được trả về bởi các luật sinh khác. Những giá trị ngữnghĩa nầy được viết như $$ (giá trị của ký hiệu chưa kết thúc bên vế trái) và $i (giá trị của kýhiệu thứ i bên vế phải). Chúng được lưu trữ trên một Stack đặc biệt được cung cấp tự động bởibộ phân tích cú pháp.

Những giá trị được liên kết với các ký hiệu kết thúc phải được thiết lập bởi bộ phận phân tích

từ vựng. Hoạt động dạng $$ := $1 thường không được viết ra vì nó là hoạt động mặc nhiên đượcchấp nhận bởi TP Yacc khi luật sinh không có hoạt động cụ thể.

Mặc nhiên, kiểu giá trị ngữ nghĩa được cung cấp bởi Yacc là số nguyên. Ta có thể đặt khai

báo sau vào phaăn caùc ñònh nghóa ñeơ thay ñoơi kieơu giaù trò maịc nhieđn:%{type YYSType = Real;%}

Tuy nhiên, nếu có nhiều kiểu giá trị khác nhau, ta nên sử dụng những định nghĩa kiểu như đã

nói tới trong phần các định nghĩa. Khi định nghĩa kiểu như vậy được đưa ra, TP Yacc xử lý tất cảcác chi tiết cần thiết của định nghĩa YYSType và còn cung cấp các kiểm tra kiểu hợp lí để tìmnhững lỗi về kiểu trong văn phạm.

Ví dụ: Ta có thể khai báo các ký hiệu NUM và expr trong ví dụ trên có kiểu Real và sau đó sửdụng những giá trị nầy để tính toán một biểu thức khi nó được phân tích cú pháp:

%left ‘+’ ‘-‘ %left ‘*’ ‘/’ %token <Real> NUM

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 5/16

%type <Real> expr %% expr : expr ‘+’ expr { $$ := $1+$3 ; } | expr ‘-’ expr { $$ := $1- $3 ; } | expr ‘*’ expr { $$ := $1* $3 ;} | expr ‘/’ expr { $$ := $1 / $3 ;} | ‘(‘ expr ‘)‘ { $$ := $2 ; } | NUM ; Hoạt động không những xuất hiện ở cuối mà còn xuất hiện ở giữa luật sinh, nó có ích khi

thực hiện một xử lý nào đó trước khi luật sinh được phân tích cú pháp đầy đủ. Những hoạt độngbên trong một luật sinh như vậy được xử lý như các ký hiệu chưa kết thúc đặc biệt. Chúng đượcliên kết với một vế phải rỗng. Vì vậy, một luật sinh có dạng

x : y { action; } z. Ðược xử lý như sau:

x : y $ act z. $ act : { action : }.

Những hoạt động bên trong một luật sinh còn có thể truy xuất tới các giá trị ở vế trái của hoạt

động và trả về giá trị bằng phép gán cho $$. Sau đó, giá trị được trả về bởi hoạt động như vậycòn có thể được truy xuất bởi các hoạt động khác bằng cách sử dụng ký pháp $i.

Ví dụ: x : y { $$ : = 2 * $1 ; } z ( $$ : = $2 + $3 ; }

Ðôi khi, nó còn có thể truy xuất những giá trị được đặt trong các luật sinh lân cận bằng cách

sử dụng ký pháp $i. Với i=0, $0 tham chiếu giá trị đầu tiên “bên vế trái” của luật sinh hiệnhành, $-1 tới giá trị thứ hai v ...v... Trong trường hợp nầy giá trị được tham chiếu tuỳ thuộc vàonội dung thực tế của Stack phân tích cú pháp, vì vậy ta phải chắc chắn rằng những giá trị đượcyêu cầu luôn ở những nơi mà ta mong đợi chúng.

Có một số tình huống mà TP Yacc không dễ dàng xác định được kiểu của các giá trị ( khi

bộ phân tích kiểu được sử dụng). Ðặc biệt là đối với những giá trị trong các luật sinh lân cận vàgiá trị $$ trong hoạt động của một luật sinh. Trong những trường hợp như thế, ta có thể sử dụngchuyển đổi kiểu để xác định cụ thể kiểu của giá trị. Ðịnh dạng cho chuyển đổi kiểu như vậy là$<tên_kiểu>$ cho giá trị bên vế trái và $<tên_kiểu>i cho giá trị bên vế phải. c. Các thủ tục phụ trợ

Mục nầy, một lựa chọn, có thể chứa bất cứ đoạn mã TP nào (chẳng hạn như các chương trình

con hoặc chương trình chính) 3. Phân tích từ vựng

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 6/16

Bất cứ bộ phân tích cú pháp nào được sinh ra bởi Yacc cũng cần tới chương trình con phântích từ vựng có tên yylex biểu diễn sự phân tích từ vựng cho bộ phân tích cú pháp. Chương trìnhnầy, được viết bởi người lập trình hoặc được tạo ra bằng cách sử dụng Lex, có khai báo:

Function yylex : integer; Bộ phân tích cú pháp lặp lại việc gọi chương trình con yylex để phân tích chuỗi nhập thành

các token và các phần tử từ vựng riêng trong chuỗi nhập. Với bất cứ một ký tự chuỗi nào,chương trình con yylex phải trả về mã ký tự tương ứng. Ðối với các ký hiệu khác, những ký hiệukết thúc của ngôn ngữ nhập, bộ phân tích từ vựng phải trả về các mã số nguyên tương ứng.Những công việc nầy được tự động thực hiện bởi TP Yacc theo thứ tự mà các định nghĩa tokenxuất hiện trong phần định nghĩa của văn phạm nguồn. Bộ phân tích từ vựng có thể truy xuất cácgiá trị nầy thông qua các hằng số nguyên tương ứng được khai báo bởi TP Yacc trong tập tinxuất.

Ví dụ: Nếu %token NUM là định nghĩa đầu tiên trong văn phạm Yacc, thì TP Yacc sẽ tạo ra khaibáo hằng số tương ứng

const NUM = 257;trong tập tin xuất (TP Yacc tự động gán số cho token bắt đầu từ 257 vì từ 1 cho tới 255 được

dành cho các ký tự, 0 biểu thị cuối tập tin, và 256 được dành cho token lỗi đặc biệt Sau đó, địnhnghĩa nầy có thể được sử dụng, chẳng hạn trong chương trình TP Lex có:

[ 0.9 ]+ Return (NUM); Ta còn có thể gán số cụ thể cho token ngay trong văn phạm theo dạng%token tên_token số_nguyên_không_âm.

Ví dụ: %token NUM 299 Bên cạnh giá trị trả về của yylex, bộ chương trình phân tích từ vựng còn có thể trả về nhữnggiá trị ngữ nghĩa cho những token được nhập dạng. Giá trị nầy được gán vào một biến có tên“yylval” và sau đó có thể được truy xuất trong các hoạt động thông qua ký pháp $i. Biến yylvalcó kiểu yystype (kiểu giá trị ngữ nghĩa mặc nhiên là số nguyên) ; khai báo của nó còn được tìmthấy trong tập tin yyparse.cod. Ví dụ: Ðể gán giá trị nguyên cho token NUM trong ví dụ ở trên ta có thể viết: [0-9]+ begin val (yytext, yylval, code); return(NUM); end;

Nếu bộ phân tích cú pháp sử dụng các token nhiều kiểu khác nhau (thông qua định nghĩa%token <tên_kiểu>), thì biến yylval sẽ không có kiểu nguyên mà thay vào đó là một kiểu mẩutin tương ứng có thể chứa tất cả các kiểu giá trị khác nhau được khai báo trong văn phạm TPYacc. Trong trường hợp nầy, bộ phân tích từ vựng phải gán một giá trị ngữ nghĩa cho thành phầnmẩu tin tương ứng tên yy<tên_kiểu> Ví dụ: Nếu token NUM khai báo có kiểu số thực: %token <Real> NUM thì giá trị của tokenNUM phải được gán cho yylval. yyReal.

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 7/16

4. Hoạt động của bộ phân tích cú pháp

TP Yacc sử dụng kỹ thuật LALR (1) để xây dựng bộ phân tích cú pháp từ dưới lên không

quay lui, hiệu quả và đơn giản cho văn phạm nguồn. Kỹ thuật phân tích cú pháp LALR rất hiệuquả khi xây dựng bộ phân tích cú pháp được sinh ra bởi TP Yacc từ một văn phạm nhỏ. Ðể xemxét giải thuật phân tích cú pháp LALR làm việc như thế nào, chúng ta hãy cùng xem xét phiênbản được đơn giản hoá của văn phạm biểu thức số học sau:

%token NUM%left ‘+’ %left ‘*’%%expr : expr ‘+’ expr | expr ‘*’ expr | ‘(‘ expr ‘)‘

| NUM ; Khi chạy với lựa chọn /v trên văn phạm nầy, TP Yacc sinh ra mô tả phân tích cú pháp được

liệt kê như sau:State 0:$accept : _ expr $end‘ ( ‘ shift 2NUM shift 3. errorexpr goto 1State 1:$accept : expr _ $endexpr : expr _ ‘+’ exprexpr : expr _ ‘*’ expr$end accept‘*’ shift 4‘+’ shift 5. errorState 2:expr : ‘(‘ _ expr ‘)’‘(‘ shift 2NUM shift 3. errorexpr goto 6State 3:expr : NUM _ (4). reduce 4State 4:expr : expr ‘*’_ expr

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 8/16

‘(‘ shift 2NUM shift 3. errorexpr goto 7State 5:expr : expr ‘+’_ expr‘(‘ shift 2NUM shift 3. errorexpr goto 8State 6:expr : ‘(‘ expr ‘)’expr : expr ‘+’ exprexpr : expr ‘*’ expr‘) ‘ shift 9‘*’ shift 4‘+’ shift 5. errorState 7:expr : expr ‘*’ expr _ (2)expr : expr ‘+’ exprexpr : expr ‘*’ expr. reduce 2State 8:expr : expr ‘*’ expr _ (1)expr : expr ‘+’ exprexpr : expr ‘*’ expr‘* ‘ shift 4$end reduce 1‘)’ reduce 1‘+’ reduce 1. errorState 9:expr : ‘(‘ expr ‘)’ _ (3). reduce 3 Mỗi trạng thái của bộ phân tích cú pháp tương ứng với tiền tố cụ thể của chuỗi nhập vừa được

phân tích. Mô tả bộ phân tích cú pháp liệt kê các luật sinh văn phạm được phân tích trong mỗitrạng thái, và chỉ rõ phần của mỗi luật sinh vừa được phân tích cú pháp bằng ký hiệu gạch dưới.Ả trạng thái 0, trạng thái bắt đầu của bộ phân tích cú pháp, luật sinh được phân tích cú pháp là:$accept : expr $end Ðây không phải là luật sinh văn phạm thực mà là luật sinh bắt đầu được tựđộng thêm vào bởi TP Yacc.

Nhìn chung, nó có dạng: $accept : X $endvới X là ký hiệu chưa kết thúc bắt đầu của văn phạm, $end là token giả biểu thị cho cuối tập

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 9/16

tin (chuỗi) nhập (ký hiệu $end được sử dụng bởi bộ phân tích cú pháp để xác định nó phân tích thành công chuỗi nhập)

Mô tả của luật sinh bắt đầu ở trạng thái 0: $accept : _ expr $end. Ký hiệu gạch dưới, đặt trước

ký hiệu expr, chỉ thị rằng chúng ta đang ở phần bắt đầu phân tích cú pháp và sẵn sàng phân tíchcú pháp một biểu thức (ký hiệu chưa kết thúc expr)

Bộ phân tích cú pháp sử dụng một Stack để lưu trữ các trạng thái đã đi qua trong quá trình

phân tích cú pháp. Có hai loại hoạt động cơ bản trong mỗi trạng thái: · Dịch chuyển (Shift): đọc một ký hiệu nhập và đẩy trạng thái kế tiếp tương ứng vào đỉnhStack.· Thu giảm (Reduce): lấy một số các trạng thái ra khỏi Stack (tương ứng với số ký hiệu ở bênphải của luật sinh được sử dụng để thu giảm) và đưa vào Stack kết quả trong mục goto củatrạng thái chưa được bao phủ để tìm sự dịch chuyển tương ứng với ký hiệu ở vế trái của luậtsinh thu giảm. Tại mỗi bước phân tích, bộ phân tích cú pháp dựa vào trạng thái ở trên đỉnh của Stack và ký

hiệu đầu đọc hiện hành, ký hiệu kế tiếp trong chuỗi nhập, để thực hiện hoạt động phân tích cúpháp dịch chuyển hay thu giảm. Bộ phân tích cú pháp dừng lại ngay khi nó đạt tới trạng thái 1 vàđọc ký hiệu cuối cùng, được chỉ định bằng hoạt động “accept”.

Ðôi khi, bộ phân tích cú pháp còn thực hiện một hoạt động mà không quan tâm tới ký hiệu

đầu đọc hiện hành. Chẳng hạn ở trạng thái 3 chỉ có một hoạt động là sự thu giảm bởi luật sinhthứ 4: reduce 4. Hoạt động mặc nhiên của một trạng thái còn có thể là “error” ám chỉ lỗi phântích cú pháp của chuỗi nhập. Trong trường hợp lỗi như vậy, bộ phân tích cú pháp sẽ bắt đầu phụchồi lỗi cú pháp như được miêu tả trong mục “xử lý lỗi”.

Ví dụ: Chuỗi nhập 2 + 5 * 3 được gởi cho bộ phân tích cú pháp có dạng:

NUM + NUM * NUM Bảng sau mô tả từng bước các hoạt động tương ứng của bộ phân tích cú pháp.

Trạng thái Stack Ký hiệu đầu đọc Hoạt động------------ ------------- -------------------- -----------------------------------------0 NUM Chuyển sang trạng thái 33 0 Thu giảm bởi luật sinh 4: lấy một trạng

thái ra khỏi Stack, sau đó đi tới trạngthái 1 từ trạng thái 0 trên ký hiệu expr.

3 0 + Chuyển sang trạng thái 55 1 0 NUM Chuyển sang trạng thái 33 5 1 0 Thu giảm bởi luật sinh 4: lấy một trạng

thái ra khỏi Stack, sau đó đi tới trạngthái 8 từ trạng thái 5 trên ký hiệu expr.

8 5 1 0 * Chuyển sang trạng thái 44 8 5 1 0 NUM Chuyển sang trạng thái 3

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 10/16

3 4 8 5 1 0 Thu giảm bởi luật sinh 4: lấy một trạngthái ra khỏi Stack, sau đó đi tới trạngthái 7 từ trạng thái 4 trên ký hiệu expr.

7 4 8 5 1 0 Thu giảm bởi luật sinh 2: lấy ba tr?ngthâi ra kh?i Stack, sau dó di t?i tr?ngthâi 8 t? tr?ng thâi 5 trín ký hi?u expr.

8 5 1 0 $end Thu giảm bởi luật sinh 1: lấy ba trạngthái ra khỏi Stack, sau đó đi tới trạngthái 1 từ trạng thái 0 trên ký hiệu expr.

1 0 $end Chấp nhận.

Nếu chuỗi nhập bị lỗi cú pháp, bộ phân tích cú pháp luôn thực hiện hoạt động tương ứng vớilỗi. Bộ phân tích cú pháp LALR sẽ không bao giờ dịch chuyển khi gặp một ký hiệu không đúngvà như vậy nó luôn tìm thấy các lỗi cú pháp (nếu có) trong suốt quá trình chuỗi nhập từ trái sangphải. 5. Văn phạm mơ hồ

Có rất nhiều tình huống mà TP Yacc không tạo ra được bộ phân tích cú pháp hợp lệ cho ngônngữ nhập được đưa ra. Bộ phân tích cú pháp LALR (1) bị hạn chế khi nó phải dựa vào đầu đọcmột ký hiệu để quyết định hoạt động cú pháp. Nếu một văn phạm là mơ hồ, hoặc không đượcphân tích cú pháp rõ ràng bằng cách sử dụng đầu đọc một ký hiệu, TP Yacc sẽ tạo ra bảng phântích cú pháp có nhiều đụng độ. Có hai kiểu đụng độ là: dịch chuyển / thu giảm và thu giảm/thugiảm.

Khi một văn phạm sinh ra những đụng độ phân tích cú pháp, TP Yacc in ra số đụng độ đẩy /

thu giảm và thu giảm/ thu giảm mà nó bắt gặp khi xây dựng bộ phân tích cú pháp. Ðể giải quyếtsự đụng độ phân tích cú pháp, TP Yacc sử dụng các luật loại bỏ sự mơ hồ được xây dựng nhưsau:

- Trong đụng độ dịch chuyển/ thu giảm, TP Yacc chọn hoạt động đẩy.- Trong đụng độ thu giảm/ thu giảm, TP Yacc sẽ thu giảm theo luật sinh văn phạm đầu tiên. Luật loại bỏ sự mơ hồ dịch chuyển/ thu giảm giải quyết chính xác kiểu mơ hồ của các câu

lệnh else thường phát sinh trong các cú pháp của những câu lệnh điều kiện có ở nhiều ngôn ngữlập trình:

%token IF THEN ELSE %% stmt : IF expr THEN stmt | IF expr THEN stmt ELSE stmt ; Văn phạm nầy mơ hồ vì với cấu trúc lồng nhau: IF expr1 THEN IF expr2 THEN stmt1 ELSE stmt2Có thể được phân tích cú pháp theo hai cách:

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 11/16

IF expr1 THEN (IF expr2 THEN stmt1 ELSE stmt2)hoặc là: IF expr1 THEN (IF expr2 THEN stmt1 ) ELSE stmt2 Ở cách đầu tiên, ELSE sẽ thuộc vào câu lệnh IF chưa được so trùng cuối cùng. Phần lớn các

ngôn ngữ lập trình đều lựa chọn cách nầy khi biên dịch. Ðây cũng chính là cách mà TP Yacc sẽphân tích cú pháp cấu trúc được đưa ra.

Luật loại bỏ sự mơ hồ thu giảm/ thu giảm được sử dụng để giải quyết những đụng độ phát

sinh khi có nhiều hơn một luật sinh văn phạm phù hợp với cấu trúc được đưa ra. Sự mơ hồ nhưvậy thường được tạo ra bởi các “cấu trúc lựa chọn đặc biệt” có đưa ra độ ưu tiên.

Trong cả hai trường hợp được đề cập ở trên, sự mơ hồ còn có thể được loại bỏ bằng cách viết

lại văn phạm tương ứng (mặc dù điều nầy làm cho văn phạm khó đọc và phức tạp hơn). Ðâykhông phải là cách luôn được lựa chọn.

Các lỗi thiết kế văn phạm sẽ làm cho văn phạm trở nên mơ hồ. Vì vậy, khi TP Yacc đưa ra bất

cứ đụng độ phân tích cú pháp nào khi xây dựng bộ phân tích cú pháp, ta nên dùng lựa chọn /v đểtạo ra mô tả bộ cú pháp (tập tin .lst) và kiểm tra xem TP Yacc giải quyết những đụng độ chínhxác chưa.

Ta thường cân nhắc khi dùng văn phạm của biểu thức ở dạng mơ hồ vì ở dạng nầy ta có thể

biểu diễn ngôn ngữ một cách súc tích hơn. Chẳng hạn, văn phạm không mơ hồ cho các biểu thứcsố học đơn giản:

%token NUM%%expr : term | expr ‘+’ term ;term : factor | term ‘*’ factor ;factor : ‘(‘ expr ‘)‘ | NUM ;

Văn phạm nầy đưa ra ký hiệu ‘*’ có độ ưu tiên hơn ký hiệu ‘+’ và cả hai ký hiệu toán tự nầy

có sự kết hợp trái. Văn phạm mơ hồ có sử dụng các định nghĩa độ ưu tiên sau có cùng hiệu quảnhư văn phạm không mơ hồ ở trên.

%token NUM%left ‘+’%left ‘*’%%expr : expr ‘+’ expr

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 12/16

| expr ‘*’ expr | ‘(‘ expr ‘)‘ | NUM ;

Nếu không có định nghĩa độ ưu tiên, văn phạm mơ hồ nầy tạo ra một số đụng độ di chuyển/

thu giảm. Các định nghĩa độ ưu tiên được sử dụng để giải quyết sự chính xác những đụng độ nầy(các sự đụng độ được giải quyết bằng cách sử dụng độ ưu tiên sẽ không được thông báo bởi TPYacc).

Mỗi định nghĩa độ ưu tiên đưa ra một mức ưu tiên mới và xác định toán tử tương ứng nào có

liên kết trái, liên kết phải hoặc không liên kết. Ðịnh nghĩa độ ưu tiên đầu tiên có mức ưu tiênthấp nhất.

TP Yacc sử dụng thông tin độ ưu tiên để giải quyết đụng độ dịch chuyển/ thu giảm như sau:

mỗi ký hiệu kết thúc kết hợp với độ một ưu tiên thông qua định nghĩa độ ưu tiên, độ ưu tiên củamỗi luật sinh văn phạm bằng với độ ưu tiên của ký hiệu kết thúc phải nhất của nó (sự lựa chọnmặc nhiên nầy có thể được viết chồng bằng cách sử dụng %prec). Ðể giải quyết đụng độ dịchchuyển/ thu giảm bằng cách sử dụng độ ưu tiên, cả ký hiệu lẫn luật sinh liên quan phải được gáncác độ ưu tiên. Sau đó, TP Yacc lựa chọn hoạt động phân tích cú pháp như sau:

· Nếu ký hiệu có độ ưu tiên cao hơn luật sinh: dịch chuyển· Nếu luật sinh có độ ưu tiên cao hơn ký hiệu: thu giảm· Nếu ký hiệu và luật sinh có cùng độ ưu tiên, sự kết hợp của ký hiệu xác định hoạt độngphân tích cú pháp:

1. Nếu ký hiệu có liên kết trái:thu giảm.2. Nếu ký hiệu có liên kết phải: dịch chuyển.3. Nếu ký hiệu không liên kết: lỗi.

Ðể biết được cách thức TP Yacc hoạt động như thế nào chúng ta cần xem xét văn phạm biểu

thức số học mơ hồ (không có độ ưu tiên) sau:%token NUM%%expr : expr ‘+’ expr | expr ‘*’ expr | ‘(‘ expr ‘)‘ | NUM ;

Văn phạm nầy sinh ra bốn đụng độ dịch chuyển/ thu giảm. Trạng thái 8 được mô tả:

State 8:

*** conflicts: shift 4, reduce 1 on ‘*’

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 13/16

shift 5, reduce 1 on ‘+’ expr : expr ‘+’ expr _ (1) expr : expr ‘+’ expr expr : expr ‘*’ expr ‘*’ shift 4 ‘+’ shift 5 $end reduce 1 ‘)’ reduce 1 . error Ở trạng thái nầy, ta phân tích thành công biểu thức cộng (luật sinh 1). Khi ký hiệu kế tiếp là +

hay *, ta có sự lựa chọn giữa thu giảm và dịch chuyển ký hiệu. Bằng cách sử dụng luật sinh loạibỏ sự mơ hồ dịch chuyển/ thu giảm mặc nhiên, TP Yacc giải quyết những đụng độ nầy theo hoạtđộng dịch chuyển.

Nếu ta thêm vào các định nghĩa độ ưu tiên cho văn phạm trên %left ‘+’ %left ‘*’ Như vậy, * có độ ưu tiên cao hơn + và cả hai toán tử có sự kết hợp trái. Ký hiệu kết thúc phải

nhất trong luật sinh 1 là +. Do đó, đụng độ đầu tiên sẽ được giải quyết theo hướng dịch chuyển(* có độ ưu tiên cao hơn +), trong khi đụng độ thứ hai được giải quyết theo hướng thu giảm (+ kết hợp trái).

Các đụng độ tương tự phát sinh trong trạng thái 7:

State 7:

*** conflicts:shift 4, reduce 2 on ‘*’shift 5, reduce 2 on ‘+’ expr : expr ‘+’ expr _ (2) expr : expr ‘+’ exprexpr : expr ‘*’ expr‘*’ shift 4‘+’ shift 5$end reduce 2‘)’ reduce 2. error

Vì vậy, ta phân tích thành công một biểu thức * mà nó có thể được theo sau bởi các toán tử +

hoặc * khác. Do * kết hợp trái và có độ ưu tiên cao hơn + nên cả hai đụng độ sẽ được giải quyếttheo hướng thu giảm.

Dĩ nhiên, ta còn có thể có các toán tử khác có cùng một độ ưu tiên, ví dụ như trong văn phạm

biểu thức toán học sau:

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 14/16

%token NUM%left ‘+’ ‘-‘%left ‘*’ ‘/’%%expr : expr ‘+’ expr

| expr ‘-’ expr | expr ‘*’ expr | expr ‘/’ expr | ‘(‘ expr ‘)‘ | NUM ;

đặt tất cả các toán tử “cộng” vào mức ưu tiên thứ nhất và tất cả các toán tử “nhân” vào mức ưutiên thứ hai. Tất cả các toán tử kết hợp trái, chẳng hạn 5+3-2 sẽ được phân tích cú pháp như sau(5+3) -2.

Một cách mặc nhiên, TP Yacc sẽ gán cho mỗi luật sinh độ ưu tiên của ký hiệu kết thúc phải

nhất của nó. Sự quyết định nầy có trong phần lớn các trường hợp. Ðôi khi, nó có thể viết chồngsự lựa chọn mặc nhiên nầy bằng cách gán cụ thể một độ ưu tiên cho một luật sinh. Ðiều nầy cóthể được làm bằng cách đặt dạng %prec ký_hiệu vào cuối luật sinh tương ứng nhằm gán cho luậtsinh độ ưu tiên bằng độ ưu tiên của ký_hiệu. Ví dụ: Ðể mở rộng văn phạm biểu thức với toán tử lấy số đối và gán cho nó độ ưu tiên cao nhất, ta có thể viết:

%token NUM%left ‘+’ ‘-‘%left ‘*’ ‘/’%right UMINUS%%expr : expr ‘+’ expr | expr ‘-’ expr | expr ‘*’ expr | expr ‘/’ expr | ‘-‘ expr %prec UMINUS

| ‘(‘ expr ‘)‘ | NUM ;

Chú ý rằng token UMINUS không phải là một ký hiệu nhập thực sự. Và nếu chúng ta bỏ qua

%prec UMINUS, cả hai toán tử lấy số đối (UMINUS) và toán tử trừ (-) có cùng một độ ưu tiênvì chúng cùng được biểu diễn bởi một ký hiệu nhập. 6. Xử lý lỗi

Xử lý lỗi cú pháp là một công việc khó khăn trong thiết kế bộ phân tích cú pháp thân thiệnvới người sử dụng. Thông thường, ta không muốn có một bộ phân tích cú pháp dừng khi gặp kýhiệu nhập bị lỗi đầu tiên. Thay vào đó, bộ phân tích cú pháp nên phục hồi lỗi cú pháp nghĩa là nó

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 15/16

cố gắng tìm được một vị trí trong chuỗi nhập nơi nó có thể tiếp tục phân tích cú pháp. TP Yacc cung cấp một kỹ thuật tổng quát để cài đặt bộ phân tích cú pháp với sự phục hồi lỗi.

Token error được định nghĩa trước đó có thể được sử dụng trong các luật sinh của văn phạm đểtìm những vị trí mà các lỗi cú pháp có thể xuất hiện. Khi bộ phân tích cú pháp chạy trên một hoạtđộng tương ứng với lỗi, nó in ra một thông báo lỗi và bắt đầu sự phục hồi lỗi bằng cách lấy cáctrạng thái ra khỏi Stack cho tới khi gặp một trạng thái mà từ đó có hoạt động dịch chuyển trêntoken lỗi. Nếu không có một trạng thái như vậy được tìm thấy, bộ phân tích cú pháp dừng với giátrị trả về là 1 để chỉ rằng lỗi cú pháp không thể phục hồi. Ngược lại, bộ phân tích cú pháp sẽ thựchiện hoạt động dịch chuyển trên token lỗi và bắt đầu lại việc phân tích cú pháp trong một chế độlỗi đặc biệt.

Trong khi ở chế độ lỗi, bộ phân tích cú pháp âm thầm bỏ qua các ký hiệu cho tới khi nó có thể

thực hiện hoạt động đẩy một cách hợp lệ. Ðể ngăn chặn một dòng liên tục các thông báo lỗi, bộphân tích cú pháp trả về chế độ thi hành thông thường chỉ sau khi nó đã xem va ìdịch chuyển 3ký hiệu nhập một cách hợp lệ. Bất cứ một lỗi nào được tìm thấy sau ký hiệu dịch chuyển đầutiên bắt đầu lại sự phục hồi lỗi, nhưng không có thông báo lỗi nào được in ra. Trong thư viện TPYacc, yyerror có thể được sử dụng để đặt lại bộ phân tích cú pháp vào chế độ hoạt động bìnhthường.

Ví dụ: Luật sinh stmt : error ‘;’ { yyerrok;} và một lỗi cú pháp xuất hiện trong khi một câulệnh (ký hiệu chưa kết thúc stmt) đang được phân tích cú pháp. Khi đó bộ phân tích cú pháp in rathông báo lỗi và lấy các trạng thái ra khỏi Stack cho đến khi nó có thể dịch chuyển một token lỗicủa luật sinh lỗi.

Trong chế độ lỗi, sự xử lý sẽ bỏ qua các ký hiệu cho đến khi nó tìm thấy ký hiệu ; sau đó thu

giảm bằng một luật sinh lỗi. Việc gọi tới chương trình con yyerrok giúp bộ phân tích cú pháp biếtrằng chúng ta phục hồi lỗi từ lỗi và nó nên xử lý (thực hiện) với chế độ phân tích cú pháp thôngthường. Kế hoạch phục hồi lỗi theo phương thức hoảng sợ nầy làm việc rất tốt khi câu lệnh luônluôn kết thúc bởi dấu ;. 7. Thư viện Yacc

Thư viện TP Yacc (YaccLib) cung cấp một số khai báo toàn cục được sử dụng trong chươngtrình phân tích cú pháp yyparse, và một số biến cùng các chương trình con tiện ích có thể đuợcdùng để điều khiển các hoạt động của bộ phân tích cú pháp và cài đặt sự phục hồi lỗi. Ta có thểsửa đổi YaccLib (và/ hoặc mẫu trong tập tin yyparse.cod) để tạo ra một TP Yacc phù hợp vớinhững ứng dụng khác. 8. Những hạn chế của sự cài đặt

Giống như TP Lex, các kích thước của bảng bên trong và bộ nhớ chính có sẵn giới hạn tính

phức tạp của văn phạm nguồn mà TP Yacc có thể xử lý. Hiện tại ta không thể thay đổi được cáckích thước của bảng bên trong (trừ phi ta sửa đổi chương trình nguồn của TP Yacc) hoặc tạo sựsử dụng bộ nhớ mở rộng. Tuy nhiên các kích thước của bảng lớn nhất được cung cấp bởi TP

9/28/2014 Trình biên dịch >> Phụ lục B - Giới thiệu TP YACC

http://websrv1.ctu.edu.vn/coursewares/cntt/tbdich/phu_luc/phuluc_b.htm 16/16

Yacc là đủ lớn để có thể xử lý những văn phạm rất phức tạp (ví dụ như văn phạm Pascal). Cácsự giới hạn hiện tại là 600 trạng thái, 2400 mục LR(0), 2400 phép dịch chuyển và goto, và 1200phép thu giảm. Mặc nhiên, kích thước của Stack được sử dụng trong các bộ phân tích cú pháp làyymaxdepth = 1024, như được khai báo trong YaccLib. Những kích thước nầy là đủ cho bất cứmột ứng dụng trung bình nào. Tuy nhiên, ta có thể thay đổi kích thước thước của Stack bằng việcthêm khai báo tương ứng vào phần định nghĩa văn phạm Yacc (hoặc thay đổi giá trị trongYaccLib). Các luật sinh văn phạm đệ quy phải có thể cần một không gian Stack lớn, vì vậy tanên sử dụng các luật sinh đệ quy trái ở những nơi có thể.

TRÌNH BIÊN DỊCH