Tải bản đầy đủ (.pdf) (14 trang)

Nghiên cứu tổng quan về chương trình dịch

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 (425.41 KB, 14 trang )


1
Nghiên cứu tổng quan về chương trình dịch


Trần Thị Hoa

Trường Đại học Khoa học Tự nhiên
Khoa Toán – Cơ – Tin học
Luận văn ThS. ngành: Đảm bảo toán học cho máy tính và hệ thống tính toán
Mã số: 60 46 35
Người hướng dẫn: TS. Nguyễn Thị Minh Huyền
Năm bảo vệ: 2012


Abstract. Chương 1: Giới thiệu về chương trình dịch. Chương 2: Phân tích từ vựng,
cú pháp và ngữ nghĩa (ngôn ngữ và văn phạm hình thức; phân tích từ vựng; phân
tích cú pháp; phân tích ngữ nghĩa). Chương 3: Các công cụ hỗ trợ xây dựng chương
trình dịch (bộ sinh trình phân tích từ vựng FLEX, bộ sinh trình phân tích cú pháp
BISON). Chương 4: Xây dựng chương trình dịch cho ngôn ngữ Minipas.

Keywords. Ngôn ngữ lập trình; Ngôn ngữ máy tính; Chương trình dịch; Toán tin;
Hệ thống tính toán

Content

MỞ ĐẦU
Từ ngàn xưa con người muốn giao tiếp với nhau phải dùng ngôn ngữ, vậy người giao
tiếp với máy tính tất nhiên cũng phải thông qua ngôn ngữ. Con người muốn máy tính thực
hiện công việc, thì phải viết các yêu cầu đưa cho máy bằng ngôn ngữ máy có thể hiểu được.
Việc viết các yêu cầu gọi là lập trình. Ngôn ngữ dùng để lập trình được gọi là ngôn ngữ lập


trình.
Việc viết chương trình sẽ dễ dàng và tự nhiên hơn nếu ngôn ngữ lập trình gần với
cách diễn đạt của vấn đề cần giải quyết. Có nghĩa là, ngôn ngữ phải chứa đựng các cấu trúc
thuật ngữ - phần tử dùng để miêu tả vấn đề, và không phụ thuộc vào máy tính cụ thể. Những
ngôn ngữ lập trình có tính chất như trên được gọi là ngôn ngữ bậc cao. Việc phân cấp ngôn
ngữ lập trình được dựa trên cơ sở của tính độc lập với máy tính ngày càng cao của các ngôn
ngữ, bao gồm:
1 – Ngôn ngữ máy (machine language)
2 – Hợp ngữ (assembly language)
3 – Ngôn ngữ bậc cao (high level language)
Để giải quyết một vấn đề nào đó bằng tin học, lập trình viên phải tạo ra các chương
trình nguồn bằng một ngôn ngữ bậc cao – ngôn ngữ gần với ngôn ngữ nói. Nhưng máy tính

2
chỉ hiểu, chỉ chấp nhận ngôn ngữ bậc thấp, riêng của mình, đó là chuỗi các số 0 và 1, tuy
nhiên chuỗi số đó lại không gần gũi với con người chút nào.
Bởi vì máy tính chỉ có thể hiểu ngôn ngữ máy cho nên một chương trình viết trong
ngôn ngữ bậc cao cuối cùng rồi cũng được dịch sang ngôn ngữ máy. Do đó cần phải có một
công cụ để thực hiện việc chuyển đổi này, công cụ đó được gọi là chương trình dịch. Để đáp
ứng các nhu cầu về phần mềm ngày càng gia tăng cả về số lượng và chất lượng, các thiết kế
ngôn ngữ lập trình có nhiều thay đổi dẫn đến các ngôn ngữ lập trình trở nên phức tạp hơn. Vì
thế việc thiết kế chương trình dịch cũng tiếp tục thay đổi. Thiết kế và cài đặt chương trình
dịch luôn là một chủ đề nghiên cứu và phát triển thiết thực.
Do đó mục tiêu chính của đề tài là tìm hiểu về các bước để thiết kế một chương trình
dịch và xây dựng một chương trình dịch cho một ngôn ngữ cụ thể tự định nghĩa. Việc xây
dựng thành công một chương trình dịch hoàn chỉnh là rất phức tạp, tốn nhiều thời gian và cần
nhiều kiến thức.
Luận văn được trình bày thành bốn chương:
+ Chương I: Giới thiệu về chương trình dịch.
+ Chương II: Phân tích từ vựng, cú pháp và phân tích ngữ nghĩa.

+ Chương III: Các công cụ hỗ trợ xây dựng chương trình dịch.
+Chương IV: Xây dựng chương trình dịch cho ngôn ngữ Minipas.Trong quá trình
nghiên cứu tác giả khó tránh khỏi những sai sót, rất mong nhận được nhiều ý kiến đóng góp
từ các thầy giáo, cô giáo và các bạn đọc để luận văn được hoàn thiện hơn.

Chƣơng 1 - GIỚI THIỆU VỀ CHƢƠNG TRÌNH DỊCH
Chương này trình bày kiến thức tổng quan về chương trình dịch, được trích từ tài liệu
tham khảo [2, 4, 5].
1.1. Chương trình dịch
Chương trình dịch, còn gọi là phần mềm biên dịch, là một chương trình máy tính làm
công việc dịch một chuỗi các câu lệnh được viết bằng một ngôn ngữ lập trình (ngôn ngữ
nguồn hay mã nguồn), thành một chương trình tương đương nhưng ở dưới dạng một ngôn
ngữ mới (gọi là ngôn ngữ đích hay mã đích) và thường là ngôn ngữ ở cấp thấp hơn, như ngôn
ngữ máy.
1.2. Các bước thiết kế chương trình dịch
Chương trình nguồn trong ngôn ngữ lập trình chính là chuỗi các ký tự. Chương trình
dịch có nhiệm vụ chuyển chuỗi ký tự này sang chuỗi ký tự khác. Quá trình này bao gồm các
quá trình nhỏ hơn và được đặt tên như sau:
1.2.1. Phân tích từ vựng
Là công việc đọc chương trình nguồn từ trái sang phải (hay được gọi là quá trình quét
nguyên liệu) để tách ra thành các thẻ từ (token). Nói cách khác, quá trình phân tích từ vựng là
quá trình dịch mà đầu nhập của nó là chuỗi các ký tự, tượng trưng cho chương trình nguồn,
đầu ra là các token. Dạng đầu ra này lại là đầu nhập của quá trình phân tích cú pháp về sau.
1.2.2. Tổ chức bảng ký hiệu
Bảng ký hiệu là một cấu trúc dữ liệu mà mỗi phần tử là một mẫu tin dùng để lưu trữ
một token được bộ phân tích từ vựng nhận biết và các thông tin của token đó, bao gồm các

3
trường lưu giữ ký hiệu và các thuộc tính của nó. Cấu trúc này cho phép chúng ta tìm ra nhanh
chóng mẫu tin của mỗi token và cũng có thể lưu trữ và truy xuất token một cách nhanh

chóng.
1.2.3. Phân tích cú pháp
Các token được xuất ra từ quá trình phân tích từ vựng có dạng (loại token, thuộc tính),
sẽ là chuỗi nhập vào của bộ phân tích cú pháp. Trong quá trình phân tích cú pháp, các token
sẽ được kiểm tra xem có thể được biểu diễn bằng cấu trúc cú pháp của ngôn ngữ lập trình cho
trước hay không?
1.2.4. Phân tích ngữ nghĩa
Bộ phân tích ngữ nghĩa sẽ kiểm tra lỗi ngữ nghĩa của chương trình nguồn và thu nhận
các thông tin về kiểu cho giai đoạn sau. Giai đoạn này sử dụng cây cú pháp được xác định
trong giai đoạn phân tích cú pháp với mỗi nút trên cây cú pháp kết hợp với một tập thuộc tính
để xác định toán tử và toán hạng của các biểu thức và câu lệnh.
1.2.5. Sinh mã trung gian
Sau giai đoạn phân tích cú pháp và phân tích ngữ nghĩa, một số chương trình dịch sẽ
tạo ra một dạng biểu diễn trung gian của chương trình nguồn.
1.2.6. Tối ưu mã
Giai đoạn tối ưu mã cố gắng cải thiện mã trung gian bằng cách thu giảm một số bước
trong mã trung gian để có thể có mã máy thực hiện nhanh hơn.
1.2.7. Sinh mã đích
Giai đoạn cuối của chương trình dịch là sinh mã đích. Mã đích có thể là mã máy hay
mã hợp ngữ. Các vị trí vùng nhớ được chọn lựa cho mỗi biến được chương trình sử dụng. Sau
đó, các chỉ thị trung gian sẽ được dịch lần lượt thành chuỗi các chỉ thị mã máy.
1.2.8. Phát hiện và thông báo lỗi
Mỗi giai đoạn của quá trình dịch đều có thể gặp lỗi. Tuy nhiên sau khi phát hiện ra
lỗi, mỗi giai đoạn phải có cách xử lý lỗi để có thể tiếp tục dịch chương trình, và như thế cho
phép phát hiện thêm nhiều lỗi khác trong chương trình nguồn. Một chương trình dịch cứ phải
dừng lại khi phát hiện lỗi sẽ không được cho là hữu ích.

Chƣơng 2 - PHÂN TÍCH TỪ VỰNG , CÚ PHÁP VÀ NGỮ NGHĨA
Như Chương 1 đã trình bày, quá trình xây dựng một chương trình dịch gồm tám
bước. Trong chương này sẽ đề cập chuyên sâu các bước phân tích từ vựng, phân tích cú pháp

và phân tích ngữ nghĩa. Trước khi đi vào tìm hiểu ba bước trên là nhắc lại kiến thức về ngôn
ngữ và văn phạm được tham khảo từ [1].
2.1. Ngôn ngữ và văn phạm hình thức
2.1.1. Bảng chữ cái
Là một tập hữu hạn các ký hiệu, tập này thường được ký hiệu bằng

.
2.1.2. Chuỗi (từ)

4
Cho

là bảng chữ cái, một chuỗi (hay một từ)
w
trên

là một dãy hữu hạn các ký
hiệu thuộc

được xếp liền kề nhau. Độ dài chuỗi
w
là số các ký hiệu hợp thành
w
và được
ký hiệu là
w
. Chuỗi rỗng ký hiệu là

, là chuỗi có độ dài bằng không.
Tập tất cả các chuỗi trên


kể cả chuỗi rỗng được ký hiệu là
*

.
Tập tất cả các chuỗi trên

không kể chuỗi rỗng được ký hiệu là


.
2.1.3. Ngôn ngữ
Ta gọi ngôn ngữ là một tập hợp các chuỗi trên một bảng chữ cái

nào đó. Chẳng hạn


 

là các ngôn ngữ trên mọi bộ chữ

. Tập tất cả các chuỗi trên một bảng chữ cái

ký hiệu là
*

cũng là một ngôn ngữ. Mỗi ngôn ngữ trên bảng chữ cái

là một tập con
của

*

.
2.1.4. Văn phạm hình thức
Định nghĩa văn phạm: Một văn phạm
),,,( SPNG 
là một bộ bốn, trong đó:

N
: là tập hữu hạn các ký hiệu chưa kết thúc hay các biến,


: là tập hữu hạn các ký hiệu kết thúc,

P
: là tập luật sinh của văn phạm,

NS 
: là ký hiệu bắt đầu của văn phạm.
Ngôn ngữ sinh bởi văn phạm: Với văn phạm
G
có ký hiệu bắt đầu
S
. Ta dùng
quan hệ


để định nghĩa
)(GL
là ngôn ngữ được sinh ra bởi

G
. Chuỗi trong
)(GL
có thể
chỉ chứa một ký hiệu kết thúc của
G
. Chuỗi các ký hiệu kết thúc
w
thuộc
)(GL
nếu và chỉ
nếu
wS
*

, chuỗi
w
được gọi là một câu của
G
.
2.1.5. Phân loại văn phạm
Dựa vào dạng của các luật sinh trong
P
để chia ra thành các lớp văn phạm sau:
1. Văn phạm chính quy
2. Văn phạm phi ngữ cảnh
3. Văn phạm cảm ngữ cảnh
4. Văn phạm tổng quát
Trong luận văn, sẽ chỉ đề cập đến hai lớp văn phạm là văn phạm chính quy được sử
dụng trong bước phân tích từ vựng và văn phạm phi ngữ cảnh được sử dụng trong bước phân

tích cú pháp.
2.1.5.1. Văn phạm chính quy
Một văn phạm
),,,( SPNG 
được gọi là tuyến tính phải nếu tất cả các luật sinh có
dạng:
xBX 
hoặc
xX 
, trong đó:
NBX ,

*
x
.
Một văn phạm
),,,( SPNG 
được gọi là tuyến tính trái nếu tất cả các luật sinh có
dạng:
BxX 
hoặc
xX 
, trong đó:
NBX ,

*
x
.
Một văn phạm được gọi là văn phạm chính quy nếu nó là văn phạm hoặc tuyến tính
trái hoặc tuyến tính phải.

2.1.5.2. Văn phạm phi ngữ cảnh

5
Văn phạm
),,,( SPNG 
được gọi là văn phạm phi ngữ cảnh nếu tất cả các luật sinh
trong tập
P
có dạng:
xA
, trong đó
NA

*
)(  Nx
.
2.2. Phân tích từ vựng
2.2.1. Vai trò của bộ phân tích từ vựng
Phân tích từ vựng là giai đoạn đầu tiên của mọi chương trình dịch. Nhiệm vụ chủ yếu
của nó là đọc chuỗi ký tự nhập vào rồi nhóm các ký tự thành các thẻ từ hay được gọi là token.
2.3. Phân tích cú pháp
2.3.1. Vai trò của bộ phân tích cú pháp
Bộ phân tích cú pháp nhận chuỗi các token được xuất ra từ bộ phân tích từ vựng và
xác nhận rằng chuỗi này có thể được sinh ra từ văn phạm của ngôn ngữ nguồn hay không
bằng cách tạo ra cây cú pháp cho chuỗi.
Mỗi ngôn ngữ lập trình đều có các quy tắc diễn tả cấu trúc cú pháp của các chương
trình định dạng đúng. Các cấu trúc cú pháp này được mô tả bởi một văn phạm phi ngữ cảnh.
Các chiến lƣợc phân tích cú pháp
Có hai chiến lược để thực hiện việc phân tích cú pháp:
 Chiến lược phân tích cú pháp từ trên xuống (top – down),

 Chiến lược phân tích cú pháp từ dưới lên (bottom – up).
2.3.1.1. Chiến lƣợc phân tích từ trên xuống
Cho một văn phạm phi ngữ cảnh
),,,( SPNG 
và một câu cần phân tích
w
. Ta
xuất phát từ điểm khởi đầu, nghĩa là từ
S
, áp dụng các suy dẫn trái, tiến từ trái qua phải thử
tạo ra câu đưa vào phân tích
w
.
Một trong số các thuật toán sử dụng chiến lược phân tích từ trên xuống là thuật toán
phân tích cú pháp Earley
1
.
2.3.1.1.1. Giới thiệu thuật toán Earley
Earley là một thuật toán thuộc loại phân tích cú pháp từ trên xuống và xây dựng các
dẫn xuất trái nhất của chuỗi ký tự nhập. Khi sử dụng thuật toán Earley chúng ta không phải
đưa văn phạm về một dạng chuẩn nào cả.
2.3.1.1.2. Thuật toán phân tích cú pháp Earley
Input: Văn phạm phi ngữ cảnh
),,,( SPNG 
, chuỗi
n
aaaw
21

thuộc

*


Output: Danh sách các tập Earley:
n
III , ,,
10
.
Thuật toán:
 Đầu tiên chúng ta xây dựng tập
0
I
như sau:
(1) Nếu

S
là một luật sinh trong
P
thì ta cho
 
0,

S
vào trong
0
I
, sau đó thực
hiện bước (2) và (3) cho đến khi nào không thể thêm mục mới vào trong
0
I

được nữa.

1


6
(2) Nếu
 
0,

B
thuộc
0
I
(chú ý:

có thể là

) thì đưa vào trong tập
0
I
mục
 
0,

 BA
cho tất cả các mục có dạng
 
0,


BA 
có trong
0
I
.
(3) Nếu
 
0,

BA 
là một mục trong tập
0
I
thì ta đưa vào
0
I
các mục
 
0,

B

cho tất cả các luật sinh có dạng

B
trong
P
.
 Bây giờ chúng ta xây dựng tập
j

I
sau khi đã có các tập
110
, ,,
j
III

(4) Bước quét (Scan): Với mỗi mục trong
1j
I
có dạng
 
iaB ,


(với
j
aa 
) thì
cho mục
 
iaB ,


vào trong
j
I
. Thực hiện bước (5) và (6) cho đến khi không
còn mục mới được thêm vào.
(5) Bước hoàn thành (Complete): Nếu

 
iA ,

là một mục trong
j
I
, kiểm tra xem
trong tập
i
I
các mục có dạng
 
kAB ,


, với mỗi mục tìm được như vậy ta cho
vào trong
j
I

mục
 
kAB ,


.
(6) Bước dự báo (Predict): Nếu
 
iBA ,



là một mục trong
j
I
, tìm trong
P
tất cả
các luật sinh có dạng

B
thì ta thêm mục
 
jB ,


vào
j
I
.
 Kết thúc thuật toán khi
nj 
.
2.3.1.1.3. Độ phức tạp thời gian theo chiều dài chuỗi nhập
Thuật toán có độ phức tạp là 0(
3
n
).
2.3.1.2. Chiến lƣợc phân tích dƣới lên
Quá trình ngược lại với phân tích từ trên xuống, xuất phát từ chính câu cần phân tích
w

, bằng cách áp dụng thu gọn các suy dẫn phải, tiến hành từ trái qua phải để đi tới ký hiệu
đầu của văn phạm.
Một trong số các thuật toán sử dụng chiến lược phân tích từ trên xuống là thuật toán
phân tích cú pháp CYK
2
. Đây là một thuật toán phân tích cú pháp trên văn phạm phi ngữ
cảnh tổng quát. Thuật toán mang tên của ba người tìm ra nó, đó là J. Cocke, D. H Younger và
T. Kasami.
2.3.1.2.1. Ý tƣởng thuật toán
Ý tưởng chính của thuật toán như sau:
 Giả sử có một văn phạm phi ngữ cảnh
),,,( SPNG 
ở dạng chuẩn
Chomsky
3
và một chuỗi nhập
n
aaaw
21

.

2



7
 Thuật toán CYK sẽ đi xây dựng một bảng phân tích cú pháp
ij


(có hình một
tam giác), mỗi phần tử
ij

với
ni 1

11  inj
có các giá trị là một tập
con của
N
.
 Một kí hiệu không kết thúc A thuộc
ij

nếu và chỉ nếu
11
*



jiii
aaaA
.
 Chuỗi nhập
w
thuộc ngôn ngữ
)(GL
nếu
n

tS
1

.
2.3.1.2.2. Thuật toán phân tích cú pháp CYK
Thuật toán CYK
(1) FOR
1:i
TO
n
DO
(2)
1i

:= {
A
|
aA 
là một luật sinh và
a
là ký hiệu thứ
i
trong
x
}
(3) FOR
2:j
TO
n
DO

(4) FOR
1:i
TO
1 jn
DO
BEGIN
(5)
ij

=


(6) FOR
1:k
TO
1j
DO
(7)
ij

:=
ij



{
BCAA |
là một luật sinh,
B




ik


C



kjki 

,
}
END
2.4. Phân tích ngữ nghĩa
Khi viết một chương trình bằng một ngôn ngữ lập trình nào đó, ngoài việc quan tâm
đến cấu trúc cú pháp của chương trình, ta còn phải chú ý đến ý nghĩa của chương trình. Tức
là chương trình dịch phải kiểm tra về ngữ nghĩa hay xử lý ngữ nghĩa của chương trình nguồn.
Để biểu diễn ngữ nghĩa, ta bổ sung thông tin ngữ nghĩa trực tiếp vào văn phạm và biểu
diễn bằng lược đồ dịch.
2.4.1. Định nghĩa ngữ nghĩa trực tiếp trong văn phạm
Để bổ sung ngữ nghĩa vào văn phạm ta dùng một văn phạm phi ngữ cảnh, trong đó
mỗi ký hiệu văn phạm kết hợp với một tập các thuộc tính. Mỗi luật sinh kết hợp với một tập
các luật ngữ nghĩa. Việc đánh giá các luật ngữ nghĩa được sử dụng để thực hiện một công
việc nào đó như tạo ra mã trung gian, lưu thông tin vào bảng ký hiệu, xuất các thông báo lỗi.
Thuộc tính của văn phạm là phần dữ liệu được liên kết với những ký hiệu kết thúc
hoặc ký hiệu không kết thúc. Thuộc tính có thể lưu bất cứ thông tin nào như số, chuỗi, con
trỏ, hoặc một cấu trúc nào đó do người dùng tự định nghĩa.
2.4.2. Lƣợc đồ dịch
Là một văn phạm phi ngữ cảnh trong đó các thuộc tính được kết hợp với các ký hiệu

văn phạm và các hành vi ngữ nghĩa nằm trong cặp dấu { } được chèn vào bên phải của luật
sinh.

8
Chƣơng 3 - CÁC CÔNG CỤ HỖ TRỢ XÂY DỰNG CHƢƠNG TRÌNH DỊCH

3.1. Giới thiệu
Trên thực tế, đã có rất nhiều công cụ có khả năng sinh ra bộ phân tích từ vựng và bộ
phân tích cú pháp. Một trong những bộ cổ điển nhất là lex và yacc – được phát minh tại Bell
Lab trong thập niên 1970.
 Yacc [6] (Yet Another Compiler Compiler) – công trình của Stephen
C. Johnson được ra đời sớm hơn, có nhiệm vụ sinh ra trình phân tích cú pháp.
 Trong khi đó Mike Lesk và Eric Schmidt đã thiết kế và phát triển Lex
[6]– bộ sinh trình phân tích từ vựng – để hỗ trợ yacc trong việc xác định các token từ chuỗi
nhập.
Flex
4
và Bison
5
chính là phiên bản cải tiến của lex và yacc, có khả năng phân tích trên
bộ văn phạm rộng hơn, quản lý bộ nhớ tốt hơn và được sử dụng trên nhiều nền tảng.

3.2. Bộ sinh trình phân tích từ vựng Flex
3.2.1. Cấu trúc
Flex nhận đầu vào là một tệp bao gồm các đặc tả của các token. Cấu trúc của một
chương trình được viết bằng ngôn ngữ Flex gồm ba phần:
Phần khai báo
%%
Phần quy tắc dịch
%%

Các hàm hỗ trợ
3.2.2. Quy trình vận hành
Việc tạo ra bộ phân tích từ vựng được thực hiện trong ba bước. Bước đầu là tạo ra
chương trình flex.l trong ngôn ngữ Flex. Sau đó chương trình flex.l sẽ được chương trình
dịch Flex xử lý tạo sản phẩm đầu ra là flex-yy.c, được xây dựng từ các biểu thức chính quy
của flex.l cùng các thủ tục chuẩn. Flex dùng bảng để nhận dạng trị từ vựng. Các hành vi có
liên quan đến các biểu thức chính quy trong flex.l là các chương trình con trong ngôn ngữ C
và chúng được chuyển thẳng sang chương trình flex-yy.c. Cuối cùng lex-yy.c sẽ được chương
trình dịch C dịch và sinh ra chương trình đối tượng a.out. Nó chính là bộ phân tích từ vựng,
có khả năng chuyển các dòng nhập thành các token của ngôn ngữ, được xác định bởi các biểu
thức chính quy, đã được đặc tả trong ngôn ngữ Flex.

4

5


9
3.3. Bộ sinh trình phân tích cú pháp Bison
3.3.1. Cấu trúc
Tương tự như Flex, Bison nhận đầu vào là một tệp bao gồm các đặc tả của một ngôn
ngữ. Từ đó, Bison biên dịch ra bộ phân tích cú pháp bằng mã C để chạy cùng với chương
trình. Cấu trúc của tệp đặc tả ngôn ngữ gồm ba phần:
Phần khai báo
% %
Phần luật dịch
%%
Các thủ tục
3.3.2. Quy trình vận hành
Một chương trình dịch có thể được xây dựng nhờ Bison bằng phương thức được

minh họa trong hình 3.2 trên. Trước tiên, cần chuẩn bị một tập tin, chẳng hạn là translate.y,
chứa một đặc tả Bison của chương trình dịch. Lệnh bison translate.y sẽ biến đổi tập tin
translate.y thành một chương trình C có tên là y.tab.C. Bằng cách dịch y.tab.C cùng với thư
viện ly nhờ lệnh cc y.tab.C - ly chúng ta thu được một chương trình đối tượng a.out thực
hiện quá trình dịch được đặc tả bởi chương trình Bison ban đầu. Nếu cần thêm các thủ tục
khác, chúng có thể được biên dịch hoặc được tải vào y.tab.C giống như mọi chương trình C
khác.

Chƣơng 4 - XÂY DỰNG CHƢƠNG TRÌNH DỊCH CHO NGÔN NGỮ MINIPAS
Trong chương này, luận văn sẽ định nghĩa một ngôn ngữ tựa Pascal có tên gọi là
Minipas và sau đó sử dụng các công cụ đã được giới thiệu trong chương ba để xây dựng bộ
phân tích từ vựng và bộ phân tích cú pháp cho ngôn ngữ Minipas.
4.1. Yêu cầu
Minipas được xây dựng dựa trên ngôn ngữ Pascal. Mặc dù còn đơn giản hơn Pascal
rất nhiều nhưng Minipas đáp ứng được các yêu cầu sau:
- Đơn giản, gọn nhẹ, dễ học.
- Đủ dùng để diễn tả một số thuật toán đơn giản cho người mới làm quen với ngôn
ngữ lập trình.
4.2. Ngôn ngữ Minipas
4.2.1. Giới thiệu sơ lƣợc
Ngôn ngữ xây dựng được đặt tên là Minipas có một số đặc điểm:
- Có năm kiểu dữ liệu đơn giản: nguyên (integer), thực (double), logic (bool), kí tự
(char), chuỗi ký tự (string). Hỗ trợ các phép toán số học - logic cơ bản trên ba kiểu đầu tiên.
Kiểu char chỉ hỗ trợ phép gán và so sánh.
- Có kiểu cấu trúc là kiểu mảng một chiều với chỉ số nguyên, kiểu phần tử là kiểu đơn
giản.
- Có ba cấu trúc điều khiển: tuần tự, rẽ nhánh (if… then… else) và vòng lặp
(for…to…do, while do).

10

- Có kiểu chương trình con là hàm. Chương trình con có thể có tối đa là ba tham số.
- Có hai lệnh nhập dữ liệu từ bàn phím và xuất dữ liệu ra màn hình.
- Cho phép hai dạng chú thích: chú thích khối và chú thích trên dòng.
- Ngôn ngữ Minipas có phân biệt chữ hoa và chữ thường.
Ngôn ngữ Minipas như vậy là tương đối đủ cho người mới bắt đầu làm quen với việc
học lập trình. Một số chi tiết phức tạp của ngôn ngữ Pascal (con trỏ, kiểu dữ liệu cấu trúc,
unit, đồ hoạ, tham biến ) đã được lược bỏ giúp Minipas đơn giản hơn.
4.3. Xây dựng chƣơng trình dịch cho Minipas
4.3.1. Xây dựng trình phân tích từ vựng cho Minipas
Bảng sau liệt kê danh sách các token của ngôn ngữ Minipas và biểu thức chính quy
xác định các token đó:
Token
Biểu thức chính quy
CHAR
\'.\'
STRING
\".*\"
DIGIT
[0-9]+|\-[0-9]+
DOUBLE
[0-9]+\.[0-9]*|\-[0-9]+\.[0-9]*
BOOLEAN
true | false
IDENTIFIER
[a-zA-Z_][a-zA-Z0-9_]*
BEGIN
Begin
END
End
LET

Var
CONST
Const
READ
Read
WRITE
Write
WRITELINE
Writeline
IF
If
THEN
Then
ELSE
Else
FOR
For
TO
To
DO
Do
ENDFOR
Endfor
WHILE
while
ENDWHILE
Endwhile
NUMBER_VAL
{DIGIT}
NUMBERD_VAL

{DOUBLE}
CHR_VAL
{CHAR}
STR_VAL
{STRING}
FUNCTION
Function
RETURN
Return
ENDFUNCTION
endfunction
WAIT
wait

11
ARRAY_I
"array integer"
ARRAY_B
"array bol"
ARRAY_C
"array char"
ARRAY_D
"array double"
ARRAY_S
"array string"
ASSGNOP
":="
comment
"//"
comment

"/*"
whitespace
[ \t\n]+
Bảng 4.1. Biểu thức chính quy đặc tả token
4.3.2. Xây dựng trình phân tích cú pháp cho Minipas
Văn phạm phi ngữ cảnh sinh ngôn ngữ Minipas:
// Luật sinh sinh chƣơng trình
program

var declarations
constant
const_declarations
func_decls
BEGIN
commands
END ‘.’
// Các luật sinh khai báo identifier
var



| LET
declarations



| declarations declaration
declaration

INTEGER id_seq_int IDENTIFIER ‘;’

| CHAR id_seq_chr IDENTIFIER ‘;’
| DOUBLE id_seq_dou IDENTIFIER ‘;’
| STRING id_seq_str IDENTIFIER ‘;’
| BOOLEAN id_seq_bol IDENTIFIER ‘;’
| ARRAY_I IDENTIFIER '[' NUMBER_VAL ']'‘;’
| ARRAY_D IDENTIFIER '[' NUMBER_VAL ']'‘;’
| ARRAY_C IDENTIFIER '[' NUMBER_VAL ']'‘;’
| ARRAY_B IDENTIFIER '[' NUMBER_VAL ']'‘;’
id_seq_int



| id_seq_int IDENTIFIER‘,’
id_seq_chr



| id_seq_chr IDENTIFIER‘,’
id_seq_dou



| id_seq_dou IDENTIFIER’,’
id_seq_bol



| id_seq_bol IDENTIFIER‘,’
id_seq_str




| id_seq_str IDENTIFIER‘,’
// Các luật sinh khai báo hằng
constant



| CONST
const_declarations



| const_declarations const_declaration
const_declaration

INTEGER IDENTIFIER ASSGNOP NUMBER_VAL‘;’
| CHAR IDENTIFIER ASSGNOP CHR_VAL ‘;’

12
| DOUBLE IDENTIFIER ASSGNOP NUMBERD_VAL ‘;’
| STRING IDENTIFIER ASSGNOP STR_VAL ‘;’
| BOOLEAN IDENTIFIER ASSGNOP NUMBERB_VAL‘;’
// Các luật sinh khai báo hàm
func_decls



| func_decl
func_decl


FUNCTION IDENTIFIER '(' func_var_decls ')'
var
func_declarations
IN
commands
ENDFUNCTION ‘;’
func_var_decls



| func_var_decls func_var_decl
func_var_decl

var_seq INTEGER IDENTIFIER
| var_seq CHAR IDENTIFIER
| var_seq DOUBLE IDENTIFIER
| var_seq TRING IDENTIFIER
| var_seq BOOLEAN IDENTIFIER
var_seq



| var_seq INTEGER IDENTIFIER ‘,’
| var_seq CHAR IDENTIFIER ‘,’
| var_seq DOUBLE IDENTIFIER ‘,’
| var_seq STRING IDENTIFIER ‘,’
| var_seq BOOLEAN IDENTIFIER ‘,’
func_declarations




| func_declarations func_declaration
func_declaration

INTEGER fun_id_seq_int IDENTIFIER ‘;’
| CHAR fun_id_seq_chr IDENTIFIER ‘;’
| DOUBLE fun_id_seq_dou IDENTIFIER ‘;’
| STRING fun_id_seq_str IDENTIFIER ‘;’
| BOOLEAN fun_id_seq_bol IDENTIFIER ‘;’
| ARRAY_I IDENTIFIER '[' NUMBER_VAL ']' ‘;’
| ARRAY_D IDENTIFIER '[' NUMBER_VAL ']' ‘;’
| ARRAY_C IDENTIFIER '[' NUMBER_VAL ']' ‘;’
| ARRAY_B IDENTIFIER '[' NUMBER_VAL ']' ‘;’
fun_id_seq_int



| fun_id_seq_int IDENTIFIER ‘,’
fun_id_seq_chr



| fun_id_seq_chr IDENTIFIER ‘,’
fun_id_seq_dou



| fun_id_seq_dou IDENTIFIER ‘,’
fun_id_seq_str




| fun_id_seq_str IDENTIFIER ‘,’
fun_id_seq_bol



| fun_id_seq_bol IDENTIFIER ‘,’
// Các luật sinh câu lệnh
commands



| commands command ‘;’
command

READ IDENTIFIER read_exp
| READ IDENTIFIER '[' index ']' read_array_exp
| WRITE IDENTIFIER
| WRITE STR_VAL | WRITE exp

13
| WRITELINE | RETURN exp
| IDENTIFIER ASSGNOP exp
| IDENTIFIER '[' index ']' ASSGNOP exp | WAIT
| IF exp THEN commands else_exp ENDIF
| WHILE exp DO commands ENDWHILE
|FOR IDENTIFIER ASSGNOP exp TO exp DO commands ENDFOR
read_exp



| read_exp ‘,’ IDENTIFIER
read_array_exp


| read_array_exp ‘,’ IDENTIFIER
else_exp


| ELSE commands
// Luật sinh biểu thức
exp

NUMBER_VAL | NUMBERD_VAL | STR_VAL | CHR_VAL
| NUMBERB_VAL | IDENTIFIER | IDENTIFIER '(' values ')'
| exp '<' exp | exp '=' exp
| exp '!''=' exp | exp '>''=' exp
| exp '<''=' exp | exp '>' exp
| exp '+' exp | exp '-' exp
| exp '*' exp | exp '/' exp
| exp '&' exp | exp '|' exp
| exp '%' exp | '!' exp
| arr_exp | '(' exp ')'
arr_exp

IDENTIFIER '[' index ']'
values



| exp value_seq
value_seq



| value_seq ',' exp
index

NUMBER_VAL | IDENTIFIER
4.3.3. Xử lý ngữ nghĩa cho ngôn ngữ Minipas
Khi bộ phân tích cú pháp nhận dạng ra một luật sinh (khai báo, biểu thức, câu lệnh )
thì nó sẽ gọi đến một chương trình con xử lý ngữ nghĩa tương ứng nằm ở phía bên phải luật
sinh đó.

KẾT LUẬN
Sau quá trình nghiên cứu, luận văn đã đạt được những kết quả như sau:
Tìm hiểu được tổng quan về chương trình dịch gồm các bước để thiết kế một chương
trình dịch. Đi sâu vào tìm hiểu ba bước chính là phân tích từ vựng, phân tích cú pháp và phân
tích ngữ nghĩa.
Tìm hiểu về hai thuật toán để phân tích cú pháp là thuật toán Earley và thuật toán
CYK.
Tìm hiểu về các công cụ để xây dựng chương trình dịch là công cụ xây dựng trình
phân tích từ vựng Flex và công cụ xây dựng trình phân tích cú pháp Bison.
Sử dụng các công cụ để viết được một chương trình dịch ở mức độ vừa phải cho một
ngôn ngữ tựa Pascal là Minipas. Chương trình dịch có thể sử dụng làm công cụ lập trình ở
mức đơn giản cho người mới làm quen với ngôn ngữ lập trình.
Hướng phát triển tiếp theo của công cụ là:

14
Cải tiến ngôn ngữ: thêm các hàm chuẩn xử lí các kiểu dữ liệu cơ bản. Thêm các phép

toán cho kiểu kí tự và mảng kí tự. Hỗ trợ tham biến cho chương trình con. Cho phép sử dụng
mảng nhiều chiều và kiểu dữ liệu tự định nghĩa.
Tìm hiểu tiếp về các giai đoạn sau của quá trình thiết kế chương trình dịch như tối ưu
mã.

References
[1] Nguyễn Văn Ba (2002), Ngôn ngữ hình thức, Nhà xuất bản Khoa học và kỹ thuật.
[2] Trần Đức Quang (biên dịch, 2000), Trình biên dịch – Nguyên lý, kỹ thuật và công cụ -
Tập 1, Nhà xuất bản Thống kê.
[3] Thái Thuần Thạch (2000), Xây dựng bộ công cụ thực hiện một số thuật toán trong lý
thuyết ngôn ngữ hình thức và automat, Luận văn tốt nghiệp, Đại học Bách khoa Đà
Nẵng.
[4] Phan Thị Tươi (2009), Giáo trình Trình biên dịch, Nhà xuất bản Đại học Quốc Gia
thành phố Hồ Chí Minh.
[5] Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman (2002), Compilers: Principles,
Techniques and Tools, Addison – Wesley Publishing Company.
[6] John R.Levine, Tony Mason & Doug Brown (1992), Lex and Yacc, O’Reilly &
Associates, Inc.


×