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

Mô Tả Ngôn Ngữ Lập Trình Và Viết Chương Trình Xây Dựng Cây 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 (1.14 MB, 36 trang )

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH

CHƢƠNG TRÌNH ĐÀO TẠO THẠC SĨ CNTT QUA MẠNG
---------------  ---------------

Mô Tả Ngôn Ngữ Lập Trình Và Viết Chƣơng Trình

Xây Dựng Cây Phân Tích Cú Pháp

Bộ môn

: Nguyên Lý Ngôn Ngữ LT

GVHD

: TS. Nguyễn Tuấn Đăng

Thực hiện : Nguyễn Khánh Ngọc
CH1001117

Thành phố Hồ Chí Minh - Tháng 2 Năm 2012


NHẬN XÉT CỦA GIẢNG VIÊN HƢỚNG DẪN

.......................................................................................................................
.......................................................................................................................
.......................................................................................................................
.......................................................................................................................
.......................................................................................................................
.......................................................................................................................


.......................................................................................................................
.......................................................................................................................
.......................................................................................................................
.......................................................................................................................
.......................................................................................................................


MỤC LỤC
Phần 1: Tìm hiểu văn phạm và phân tích cú pháp
I. Khái niệm ngôn ngữ lập trình ............................................................................ 1
II. Văn phạm và cú pháp ....................................................................................... 1
1. Văn phạm phi ngữ cảnh (Context-Free Grammar) ..................................... 2
a. BNF (Backus Naur normal form) ......................................................... 4
b. Dẫn xuất và ngôn ngữ .......................................................................... 5
c. Cây dẫn xuất ......................................................................................... 6
d. Sự mơ hồ (Ambiguity) ......................................................................... 9
2. Ràng buộc cú pháp theo ngữ cảnh .............................................................. 11
III. Trình Biên Dịch .............................................................................................. 12
1. Phân tích từ vựng (lexical analysis) ........................................................... 13
2. Phân tích cú pháp (syntax analysis) ............................................................ 14
3. Phân tích ngữ nghĩa (semantic analysis) .................................................... 15
4. Phát sinh dạng trung gian (Generation of intermediate forms) ................... 15
5. Tối ưu hóa mã lệnh (Code optimisation) ..................................................... 16
6. Sản sinh mã lệnh (Code generation) ........................................................... 16
IV. Ngữ nghĩa ....................................................................................................... 16
1. Trạng thái (State) ......................................................................................... 17
2. Quá trình chuyển đổi (Transition) .............................................................. 18
3. Ngữ nghĩa biểu thức (Expression semantics) ............................................. 19
4. Ngữ nghĩa lệnh (Command semantics) ...................................................... 20
5. Tính Toán (Computations) .......................................................................... 21

V. Ngữ Dụng Và Cài Đặt....................................................................................... 21


Phần 2: Xây Dựng Trình Phân Tích Cú Pháp
I. Định nghĩa văn phạm ......................................................................................... 23
II. Xây dựng trình phân tích cú pháp trong C # ..................................................... 24
1. Định nghĩa token và các phương thức làm việc trên token ........................ 24
2. Xây dựng trình phân tích cú pháp (parser) trong C # .................................. 24
3. Scanner ....................................................................................................... 26
3. Hàm Main và chương trình minh họa ......................................................... 30

Tài liệu tham khảo ........................................................................................................ 32


Phần I: Tìm hiểu văn phạm và trình phân tích cú pháp
I. Khái niệm ngôn ngữ lập trình
Một ngôn ngữ lập trình là một dạng hình thức nhân tạo mà các thuật giải có thể
được diễn đạt trên hình thức đó. Việc nghiên cứu ngôn ngữ lập trình chúng ta có thể sử
dụng tốt hơn nhiều khái niệm và những công cụ được phát trển trong thế kỷ này qua
ngôn ngữ học(lĩnh vực ngôn ngữ học nghiên cứu cả về ngôn ngữ tự nhiên và ngôn ngữ
nhân tạo). Không đi sâu vào chi tiết ngôn ngữ học, tiểu luận này đưa ra các vấn đề làm
sao đê mô tả ngôn ngữ lập trình và công cụ nào được sử dụng để xây mô tả ngôn ngữ
lập trình.
Những cấp độ mô tả
Trong việc nghiên cứu ngôn ngữ học cổ điển, Morris đã nghiên cứu về các cập độ
khác nhau để mô tả một ngôn ngữ. Ông ta đã định nghĩa 3 cấp độ chính: grammar (ngữ
pháp), semantic ( ngữ nghĩa) và pragmatics ( thực dụng ).
 Grammar ( văn phạm ) là một phần trong việc mô tả ngôn ngữ, nó trả lời câu
hỏi: cụm từ đã diễn đạt đúng chưa? Khi bảng ký tự (alphabet) của một ngôn
ngữ được định nghĩa, thì thành phần từ vựng cấu thành từ một chuỗi có trình tự

các ký hiệu của ngôn ngữ cũng được định nghĩa. Khi bảng ký tự alphabet và từ
vựng được định nghĩa, cú pháp (syntax) mô tả thứ tự của các từ cấu thành cụm
từ hợp lệ.
 Semantics ( ngữ nghĩa ) là một phần của mô tả ngôn ngữ, nó trả lời câu hỏi:
“cụm từ đúng này nghĩa là gì?”. Ngữ nghĩa để chỉ ý nghĩa của cụm từ. Đối với
ngôn ngữ tự nhiên, xử lý ngữ nghĩa rất phức tạp, trong khi đó đối với ngôn ngữ
nhân tạo thi đơn giản hơn nhiều. Trong trường hợp này ngữ nghĩa là mối quan
hệ giữa những câu đúng và ý nghĩa của chúng.
 Pragmatics (Thực dụng) là một phần của mô tả ngôn ngữ, nó tự hỏi “Chúng ta
sử dụng một câu có ý nghĩa như thế nào?”. Những câu có cũng ý nghĩa nhưng
có thể được sử dụng theo nhiều cách khác nhau tùy vào người sử dụng.
 Trong trường hợp ngôn ngữ lập trình chúng ta có thể thêm 1 cấp độ thứ 4 là cấp
độ thực thi (implementation). Giả sử chúng ta quan tâm ngôn ngữ thủ tục hàm,
nó mô tả “Làm thế nào để thực thi một câu đúng theo ngữ nghĩa của câu”.
Chúng ta xem xét ngôn ngữ tự nhiên đễ diễn tả một công thức nấu ăn. Cú pháp diễn
tả những câu đúng dùng để diễn đạt công thức nấu ăn. Ngữ nghĩa giải thích công thức
nấu ăn đó là gì. Pragmatic (thực dụng) mô tả người đầu bếp diễn dịch công thức đó
như thế nào. Và cuối cùng implementation ( thực thi) mô tả cách thực hiện các công
thức nâu ăn, chuẩn bị chén đĩa thành các món ăn theo đúng những gì ngữ nghĩa muốn
trình bày
Trang 1


II. Văn phạm và cú pháp
Văn phạm (grammar) của một ngôn ngữ xây dựng bảng ký tự alphabet và từ vựng.
Sau đó cú pháp (syntax) định nghĩa những chuỗi ký tự đó theo những câu hoặc cụm từ
có định dạng chuẩn.
Vào năm 1950 nhà ngôn ngữ học người Mỹ Noam Chomsky đã đưa ra một kỹ thuật
mô tả cú pháp, mô tả sử dụng những hình thức được thiết kế đặc biệt để giới hạn sự mơ
hồ trong ngôn ngữ tự nhiên. Những kỹ thuật này gọi là ngữ pháp sản sinh, chúng

không sử dụng nhiều trong việc mô tả ngôn ngữ tự nhiên ( bởi vì ngôn ngữ tự nhiên
quá phức tạp ) mà nó dùng để mô tả cú pháp của ngôn ngữ lập trình.
Ví dụ: chúng ta mô tả một ngôn ngữ đơn giản. Đó là ngôn ngữ của những chuỗi đối
xứng, được cấu thành bởi 2 ký tự là a và b. Chúng ta có bảng ký tự (alphabet) như sau
A={a,b}, bây giờ ta chọn ra các chuỗi câu thành từ các ký tự trong A, để tạo thành các
chuỗi đối xứng. Cách đơn giản nhất để thực hiện điều này, chú ý rằng có một sự đệ
quy đơn giản của chuỗi đối xứng. Chúng ta có thể phát biểu rằng a và b là chuỗi đối
xứng, nếu s là đã là một chuỗi đối xứng thì asa và bsb cũng là chuỗi đối xứng.
Các chuỗi đối xứng trên có chiều dài là số lẻ. Nhưng chiều dài các chuỗi đối xứng
cũng có thể là số chẵn, ví dụ abba. Trong trường hợp này ta thêm một sư kiện là chuỗi
rỗng (empty string) cũng là chuỗi đối xứng. Như vậy một chuỗi được gọi la đối xứng
(ví dụ: aabaa hoặc abba ), tồn tại một chuỗi các ký tự được ghép vào theo nguyên tắc
quy nạp.

1. Văn phạm phi ngữ cảnh
Văn phạm phi ngữ cảnh là ký hiệu để diễn đạt ngắn gọn, súc tích và chính xác
những định nghĩa đệ quy của các chuỗi như là các chuỗi chung ta đã thấy trong ví dụ
về chuỗi đối xứng. Một định nghĩa quy nạp của chuỗi đối xứng có thể được diễn tả
theo hình thức văn phạm như sau:
P →
P→a
P→b
P → aPa
P → bPb
Theo những luật trên P chính là chuỗi đối xứng, mũi tên → nghĩa là “có thể là”. Ba
dòng đầu tiên là trường hợp cơ bản của định nghĩa quy nạp, hai dòng cuối là các bước

Trang 2



quy nạp. Ví dụ trên cho thấy văn phạm phi ngữ cảnh là công cụ cơ bản đê mô tả ngôn
ngữ lập trình.
Văn phạm phi ngữ cảnh là một công cụ cơ bản để mô tả ngôn ngữ lập trình. Các ký
hiệu và thuật ngữ trong văn phạm phi ngữ cảnh như sau. Có một tập hữu hạn A, chúng
ta gọi là bảng chữ cái, và A* là tập tất cả các chuỗi hữu hạn trên A. Chúng ta thấy
rằng, thông qua định nghĩa này thì chuỗi rỗng cũng thuộc A* , ký hiệu là 𝜖.
Một ngôn ngữ chính thức dựa và bảng chử cái A là tập con của A*. Một văn phạm
chính thức để nhận dạng một tập con của các chuỗi nào đó dựa trên bảng ký tự đã cho.
Định nghĩa 2.1 (Context-Free Grammar):
Một văn phạm phi ngữ cảnh là một bộ tứ gồm (NT,T,R,S). Trong đó:
 NT là một tập hữu hạn các ký hiệu ( non-terminal symbols, variables, syntatic
categories)
 T là một tập hữu hạn các ký hiệu (terminal symbols)
 R là một tập hữu hạn các luật, mỗi một luật được diễn đạt theo hình thức sau
𝑽→𝝎
V (vế trái của luật) là những ký hiệu non-terminal đơn giản, 𝜔 ( vế phải của
luật ) là một chuỗi có thể là rỗng hoặc là terminal symbol hay non-terminal
symbol (𝑇 ∪ 𝑁𝑇)
 S là một phần tử của NT, phần tử khởi tạo
Qua ví dụ này, và chuỗi đối xứng ta có văn phạm biễu diễn chuỗi đối xứng là bộ tứ
gồm ({P},{a,b},R,P) với R là tập luật sau :
P→
P→a
Chúng ta thấy rằng một luật có thể có vế phải là rỗng, hoặc là ký hiệu null(chuoi64
rỗng ∈).
Ví dụ 1: Một ví dụ văn phạm đơn giản mô tả biểu thức toán học ( dựa trên các toán tử
+,*,-, cả toán tử một ngôi và hai ngôi ). Những phần tử nhỏ nhất của những biểu thức
này là những định danh đơn giản được định dạng từ những chuỗi hữu hạn của các ký
hiệu a và b.


Trang 3


Chúng ta định nghĩa văn phạm 𝑮 =

𝑬, 𝑰 , 𝒂, 𝒃, +, −, , , 𝑹, 𝑬 , với R là tập luật sau

1. E → I
2. E → E + E
3. E → E ∗ E
4. E → E − E
5. E → −E
6. E → (E)
7. I → a
8. I → b
9. I → Ia
10. I → Ib
Trong văn phạm G này có 2 ký hiệu non-terminal là E (expression) và I (identifier).
Chú ý rằng các luật là những cú pháp diễn tả những định nghĩa đệ quy như thế nào.
Trong trường hợp này chúng ta đang xử lý 2 định nghĩa. Định nghĩa thứ nhất lả
E(expression), sử dụng ký hiệu non-terminal cơ bản được đinh nghĩa một cách quy nạp
sử dụng các định nghĩa đệ quy.
a. BNF:
Trong ngữ cảnh ngôn ngữ lập trình, văn phạm phi ngữ cảnh được sủ dụng lần đầu
tiên trong việc định nghĩa ngôn ngữ Algol60. Trong bài báo cáo giới thiệu về Algol60,
văn phạm định nghĩa ngôn ngữ được mô tả bằng ký hiệu khác với các ví dụ mà chúng
ta đã xét ở trên, nó giảm đi tập ký tự, bỏ đi ký hiệu mũi tên ( -> ), những dấu ngoặc ( {
, } ), chữ viết hoa ... văn phạm phi ngữ cảnh này có tên là “Backus Naur normal form”
(BNF), đây là tên của 2 thành viên của tổ chức Algol (John Backus là người đã chỉ đạo
dự án Fortran, và đã viết trình biên dịch cho Fortran, và Peter Naur). Trong BNF:

Một dẫn xuất của chuỗi ab*( a + b )
𝑬 ⟹𝟑 𝑬 ∗ 𝑬
⟹𝟏 𝑰 ∗ 𝑬
⟹𝟏𝟎 𝑰𝒃 ∗ 𝑬
⟹𝟕 𝒂𝒃 ∗ 𝑬
Trang 4


⟹𝟔 𝒂𝒃 ∗ (𝑬)
⟹𝟐 𝒂𝒃 ∗ (𝑬 + 𝑬)
⟹𝟏 𝒂𝒃 ∗ (𝑰 + 𝑬)
⟹𝟕 𝒂𝒃 ∗ (𝑰 + 𝑬)
⟹𝟏 𝒂𝒃 ∗ (𝒂 + 𝑰)
⟹𝟖 𝒂𝒃 ∗ (𝒂 + 𝒃)
Mũi tên “→” được thay thế bằng “::=”
Ký hiệu non-terminal được viết giưa những dấu ngoặc đơn góc ( ví dụ < 𝐸𝑥𝑝 >)
Những luật có vế trái giống nhau được nhóm thành khối đơn giản sử dụng ký hiệu
“|” để cách biệt các luật. Ví dụ
< 𝐸 >::=< 𝐼 > | < 𝐸 > +< 𝐸 > | < 𝐸 >∗< 𝐸 > | < 𝐸 > −< 𝐸 > |−< 𝐸 > |(< 𝐸 >)

b. Dẫn xuất và ngôn ngữ:
Một văn phạm định nghĩa một tập các chuỗi. Chúng ta thấy rằng chuỗi ab*(a+b)
hợp lệ với văn phạm ở ví dụ trên. Chúng ta bắt đầu với ký hiệu khởi tạo là E, và từ E ta
sử dụng luật (3) ta có 𝐸 ⟹3 𝐸 ∗ 𝐸. Bây giờ ta xét vế phải của luật, ta có được 𝐸 ∗ 𝐸,
mà 𝐸 ∗ 𝐸 ⟹1 𝐼 ∗ 𝐸. Chúng ta có thể tiếp tục khai triển I và E đến khi nào đạt được
chuỗi dẫn xuất ab*(a+b).
Định nghĩa 2.2:
Giả sử có một văn phạm 𝑮 = 𝑵𝑻, 𝑻, 𝑹, 𝑺 , và đã gán 2 chuỗi
𝑣 𝑣à 𝜔 𝑙ầ𝑦 𝑡ừ 𝑡ậ𝑝 𝑁𝑇 ∪ 𝑇, chúng ta nói rằng 𝜔 được dẫn xuất trực tiếp từ 𝑣, nếu 𝜔 đạt
được từ 𝑣, trong trường hợp này chúng ta có thể viết là 𝑣 ⇒ 𝜔.

Chúng ta nói rằng 𝜔 được dẫn xuất từ 𝑣, và chúng ta viết 𝑣 ⇒∗ 𝜔, nếu có tồn tại
một chuỗi hữu hạn(có thể là chuỗi rỗng) của các dẫn xuất trực tiếp 𝑣 ⟹ 𝜔0 ⟹ 𝜔1 ⟹
𝜔2 ⟹ ⋯ ⟹ 𝜔 .
Sử dụng các ký hiệu và quy tắc trên, chúng ta có thể viết như sau
𝑬 ∗ 𝑬 ⇒∗ 𝒂𝒃 ∗ (𝒂 + 𝑰)
Định nghĩa 2.3 (Generated Language)
Ngôn ngữ được sản sinh bởi văn phạm 𝑮 = 𝑵𝑻, 𝑻, 𝑹, 𝑺 là một tập
𝓛 𝑮 = 𝝎 ∈ 𝑻∗ 𝑺 ⇒∗ 𝝎}
Trang 5


c. Cây dẫn xuất:
Dẫn xuất của một chuỗi là quá trình xử lý tuần tự, có những bước phải được thực
thi theo thứ tự chính xác. Ví dụ trong văn phạm trên ⇒10 phải thực thi sau ⇒3 bởi vì
luật (10) viết lại ký hiệu I ( ký hiệu non-terminal), không tồn tại trong chuổi khởi tạo.
Hai dẫn xuất của chuỗi ab*(a+b) xây dựng lại cấu trúc của chuỗi theo cách giống
nhau

Hình 1: Cây dẫn xuất của chuỗi ab*(a+b)

Định nghĩa 2.4
Cho văn phạm 𝑮 = 𝑵𝑻, 𝑻, 𝑹, 𝑺 , một cây dẫn xuất (cây phân tích cú pháp) là một
cây có thứ tự, trong đó:
Mỗi một nút được gắn nhãn bằng một ký hiệu thuộc tập 𝑁𝑇 ∪ 𝑇 ∪ {𝜖}
Gốc được dán nhãn là S
Mỗi một nút trong của cây được gán nhãn là một ký hiệu thuộc tập NT
Nếu một nút chính có nhãn 𝐴 ∈ 𝑁𝑇 và con của nó là 𝑚1 , 𝑚2,…, 𝑚𝑘 được gán nhãn
lần lượt là 𝑋1 , 𝑋2,…, 𝑋𝑘 với 𝑋𝑖 ∈ 𝑁𝑇 ∪ 𝑇, (𝑖 ∈ 1, 𝑘 , và 𝐴 → 𝑋1 … 𝑋𝐾 ) là một luật của
R


Trang 6


Nếu một nút được gắn nhãn là 𝜖, thì nút đó là nốt con duy nhất. Nếu A là cha của
nó thì 𝐴 → 𝜖 là một luật của R
Cây dẫn xuất có thể xây dựng từ các dẫn xuất. Nó bắt đầu từ gốc và thêm vào một
mức con liên quan đến luật sử dụng trong dân xuất. Cây dẫn xuất là một trong những
kỹ thuật quan trọng nhất trong việc phân tích cú pháp ngôn ngữ lập trình.
Cây: Khái niệm cây là một khái niệm quan trọng của ngành khoa học máy tính, được
sử dụng nhiều trong các ngôn ngữ chung ( như là cây phả hệ ). Một cây là một cấu trúc
thông tin được định nghĩa theo nhiều cách khác nhau và nó tồn tại trong những lĩnh
vực khác nhau. Chúng ta chỉ quan tâm đên thứ cây thứ tự, và cây có gốc. Một cây thứ
tự hay cây có gốc là một tập hữu hạn các nút, nếu cây đó không rỗng thì sẽ có một nút
gọi là nút gốc, nếu tồn tại các nút con của nút gốc 𝑆1 , 𝑆2 , … , 𝑆𝑛 , 𝑛 ≥ 0, mỗi 𝑆𝑖 , 𝑖 ∈
[1, 𝑁] là một cây.
Cây cho phép chúng ta nhóm các nút ở cùng mức lại với nhau, tại mức 0, chúng ta
có nút gốc, tại mức 1 chúng ta có các nút gốc của các cây 𝑆1 , 𝑆2 , … , 𝑆𝑛 .
Một cây cũng là trường hợp đặc biệt của đồ thị: một cây thứ tự (cây có gốc) là một
cặp 𝑇 = 𝑁, 𝐴 , với N là một hữu hạn các nút và A là một các cung nối giữa 2 nút:
 Số lượng cung bằng hoặc ít hơn 1 cung so với tổng số nút
 T được gọi là liên thông nếu từ 1 nút có thể đi đến tất cả các nút khác (thông
qua các cung)
 Một nút r được gọi là nút gốc thì nút gốc đó có mức 0, nếu một nút n tại mức i,
và tồn tại cung (𝑛, 𝑚) ∈ 𝐴 và nút m có mức I +1
 Cho một nút, n, những nút m mà có cung (𝑛, 𝑚) ∈ 𝐴 được gọi là con cùa n
𝑬 ⟹𝟐 𝑬 + 𝑬
⟹𝟑 𝑬 ∗ 𝑬 + 𝐄
⟹𝟏 𝑰 ∗ 𝑬 + 𝐄
⟹𝟕 𝒂 ∗ 𝑬 + 𝐄
⟹𝟏 𝒂 ∗ 𝑰 + 𝐄

⟹𝟖 𝒂 ∗ 𝒃 + 𝐄
⟹𝟏 𝒂 ∗ 𝒃 + 𝑰
⟹𝟕 𝒂 ∗ 𝒃 + 𝒂

Trang 7


Hình 2: cây dẫn xuất của chuỗi a*b+a

Hình 3: cây dẫn xuất khác của chuỗi a*b+a

Hình 2, chúng ta thấy rằng biểu thức con a*b là con trái của cây. Điều này cho t hấy
chuỗi a*b+a phải được thông dịch là “a nhân b trước rồi lấy kết quả đó cộng với a”,

Trang 8


d. Sự mơ hồ (Ambiguity): chúng ta hãy xem xét ví dụ sau
𝑬 ⟹𝟑 𝑬 + 𝑬
⟹𝟏 𝑰 ∗ 𝑬
⟹𝟕 a ∗ 𝑬
⟹𝟐 𝒂 ∗ 𝑬 + E
⟹𝟏 𝒂 ∗ 𝑰 + E
⟹𝟖 𝒂 ∗ 𝒃 + E
⟹𝟏 𝒂 ∗ 𝒃 + 𝑰
⟹𝟕 𝒂 ∗ 𝒃 + 𝒂
Nếu ta xây dựng cây dẫn xuất, chúng ta sẽ được cây sau

So sánh với Hình 2, ta thấy 2 cây có cấu trúc khác nhau nhưng cùng cho ra chết quả
là chuồi a*b+a. Như vậy văn phạm chúng ta định nghĩa trên đã gây ra sự lầm lẫn, có

thể tạo ra 2 cây khác nhau cùng biểu diễn cho cùng 1 chuỗi giống nhau
Định nghĩa 2.5:
 Cho 𝑇 = (𝑁, 𝐴) là một cây thứ tự, khác rỗng, có gốc là r. Kết quả của quá trình
duyệt cây từ trái sang phải là một mảng các nút đến đucợ bởi cách giải thuật đệ
quy như sau:
 Nếu r không có con, kết quả của quá trình duyệt cây là r
Trang 9


 Nếu r có k con, 𝑚1 , 𝑚2 , . . , 𝑚𝑘 , 𝑐ℎ𝑜 𝑇1 , 𝑇2 , . . , 𝑇𝑘 là cây con của T với 𝑇𝑖 𝑐ó 𝑚𝑖 là
nút gốc của nó, kết quả của quá trình duyệt cây là các nút sẽ được duyệt theo
thứ tự từ trái sang phải, 𝑇1 đế𝑛 𝑇𝑘 .
Định nghĩa 2.6
Chúng ta nói rằng một chuỗi các ký tự có cây dẫn xuất là T nếu nó là kết quả của
phép duyệt cây theo thứ tự trái sang phải. Và ta có đinh nghĩa sau
Định nghĩa 2.7 (Ambiguity)
Một văn phạm G gọi là mơ hồ nếu nó tồn tại ít nhất một chuỗi của tập 𝓛 𝑮 , mà
chuỗi này có nhiều hơn một cây dẫn xuất.
Một văn phạm mơ hồ là vô dụng khi mô tả ngôn ngữ lập trình bởi vì nó không thể
được sử dụng để biên dịch một chương trình thành một dạng duy nhất. Những văn
phạm mơ hồ này có thể được chuyển đổi về thành văn phạm rõ ràng bằng một số kỹ
thuật.
Ví dụ:

Chúng ta có văn phạm thông dịch cấu trúc của biểu thức theo khái niệm của độ ưu
tiên của các toán tử trong toán học. Toán tử 1 ngôi (“-“) có độ ưu tiên cao nhất, sau đó
là *, và sau đó là toán tử +, - (có độ ưu tiên như nhau). Văn phạm sẽ phân tích, sau đó
một mảng các toán tử cùng cấp độ ưu tiên sẽ kết hợp với nhau bên phải. Ví dụ a+b+a
sẽ được viết là a+(b+a). Khử sự mơ hồ bằng cách tăng độ phức tạp của chuỗi.
Ví dụ sau cho thấy định nghĩa câu lệnh if trong văn phạm của ngôn ngữ

java(nonterminal được in nghiêng, trong khi ký hiệu terminal trong ví dụ này là if, else
và những dấu ngoặc đơn).
if (expression1) if (expression2) command1;
else command2;
Java và hầu hết các ngôn ngữ lập trình khác cho phép câu lệnh điều kiện if có thế
có hoặc không có lệnh else theo sau.Văn phạm sau là văn phạm rõ ràng

Trang 10


Statement ::= . . . | IfThenStatement | IfThenElseStatement |
StatementWithoutTrailingSubstatement
StatementWithoutTrailingSubstatement ::= . . . | Block | EmptyStatement |
ReturnStatement
StatementNoShortIf ::= . . . | StatementWithoutTrailingSubstatement |
IfThenElseStatementNoShortIf
IfThenStatement ::= if ( Expression ) Statement
IfThenElseStatement ::=
if ( Expression ) StatementNoShortIf else Statement
IfThenElseStatementNoShortIf ::=
if ( Expression ) StatementNoShortIf else StatementNoShortIf

2. Ràng buộc cú pháp theo ngữ cảnh
Tính chính xác về cú pháp của một cụm từ trong một ngôn ngữ lập trình đôi khi
phụ thuộc vào bối cảnh sử dụng cụm từ đó. ví dụ, việc gán I = R+3, giả sử rằng các
luật trong văn phạm được sử dụng để thừa nhận sự dẫn xuất chính xác của chuỗi này,
điều đó có thể được, mặc dù, nó không chính xác tại thời điểm chính xác trong các
chương trình mà tại đó nó xảy ra. Ví dụ, nếu ngôn ngữ đòi hỏi việc khai báo các biến
số , nó là cần thiết cho các chương trình có chứa việc khai báo của I và R trước khi
gán. Chương trình sẽ không chấp nhận việc gán nếu kiểu của biểu t hức R + 3 là không

tương thích với biến I.
Những chuỗi đúng với văn phạm và có thể hợp lệ chỉ trong một ngữ cảnh nào đó.
Có nhiều ví dụ về ràng buộc cú pháp theo ngữ cảnh:
 Một định danh phải được khai báo trước khi sử dụng (Pascal, Java)
 Số lượng tham số truyền vào hàm phải bằng với những tham số chính thức (C,
Pascal, Java …)
 Trong trường hợp phép gán, kiểu của biểu thức phải tương thích với kiểu của
biến được gán (C, Pascal, Java, …)
 Việc gán giá trị cho biến điều khiển trong vòng lặp for là không hợp lệ
trong(Pascal)
 Trước khi sử dụng biến, biến đó phải được gán trị. (Java)
 Một phương thức có thể được định nghĩa lại bởi một phương thức cùng tên.
Trang 11


Đây là những ràng buộc cú pháp. Những ràng buộc này không thể được mô tả
bằng văn phạm phi ngữ cảnh. Như vậy sử dụng văn phạm nên tránh những mô tả cú
pháp có ngữ cảnh, những ràng buộc ngữ cảnh này có thể diễn đạt bằng ngôn ngữ tự
nhiên hoặc sử dụng các ký thuật hình thức như là những hệ thống chuyển đổi.
Thuật ngữ Ràng buộc ngữ nghĩa tĩnh (static semantic constraint) được sử dụng
trong ngôn ngữ lập trình để chỉ những hạn chế theo ngữ cảnh xuất hiện trong các khía
cạnh cú pháp của một ngôn ngữ.Từ chuyên môn là "cú pháp" có nghĩa là "có thể mô tả
sử dụng một văn phạm phi ngữ cảnh", "ngữ nghĩa tĩnh" có nghĩa là "có thể mô tả
những ràng buộc theo ngữ cảnh có thể kiểm tra được trên một cơ sở tĩnh bằng cách sử
dụng các văn bản chương trình", trong khi “ngữ nghĩa động (dynamic semantic)" (hay
đơn giản là "ngữ nghĩa-semantic") đề cập đến tất cả mọi thứ điều đó xảy ra khi một
chương trình được thực hiện.
Sự khác biệt giữa cú pháp phi ngữ cảnh và cú pháp phụ thuộc ngữ cảnh là ở ý
nghĩa của văn phạm phi ngữ cảnh của bối cảnh. Sự khác biệt giữa cú pháp và ngữ
nghĩa là không phải lúc nào cũng rõ ràng.Một số trường hợp rõ ràng, ví dụ, chúng ta có

một ngôn ngữ mà định nghĩa của nó nói rằng, khi có một phép chia cho 0 xảy ra trong
quá trình thực thi, trình biên dịch phải báo cáo lỗi tường minh.
Điều này rõ ràng là một ràng buộc ngữ nghĩa động. Chúng ta giả định, hiện nay,
định nghĩa của một ngôn ngữ khác được quy định như sau:
Một chương trình là sai cú pháp nếu phép chia cho 0 xảy ra.
int A, B;
read(A);
B = 10/A;
Chương trình trên lỗi về mặt cú pháp không chính xác trong ngôn ngữ giả thuyết
này bởi vì có tồn tại các lệnh thực thi (lệnh read gán giá trị A bằng 0) gây ra phép chia
cho số không. Ràng buộc mà chúng ta đã nêu ở trên thuộc về ràng buộc ngữ nghĩa tĩnh
hoặc động? Rõ ràng là nó đề cập đến một sự kiện động.
III. Trình biên dịch (Compilers)
Trình biên dịch thực hiện các công việc sau:
1. Phân tích từ vựng (lexical analysis)
Mục đích của phân tích từ vựng là để đọc các biểu tượng (ký tự) hình thành các
chương trình một cách tuần tự từ đầu vào và nhóm các biểu tượng này thành các nhóm
có ý nghĩa logic, chúng ta gọi là token (tương tự như từ vựng trong từ điển ngôn ngữ tự
Trang 12


nhiên. Ví dụ bộ phân tích từ vựng của Java hay C, khi biểu diễn biểu thức x = 1 +
foo++ ; sẽ có 7 token: định danh x, toán tử gán =, số 1, toán tử +, định dnah foo, và
toán tử tăng 1 ++, và cuối cùng là dấu ;.
Những token đặc biệt quan trọng là các từ dành riêng của ngôn ngữ (chẳng hạn như
for, if, else …), các toán tử, ngoặc đơn mở và đóng (chẳng hạn như { và } trong C hoặc
Java, và những những từ “begin”, “end” trong Pascal). Phân tích từ vựng là một quá
trình đơn giản, nó quét văn bản đầu vào của chương trình nguồn từ trái sang phải, nhận
ra các token.


Hình 4: Cấu trúc của trình biên dịch

Cú pháp trừu tượng và cụ thể
Văn phạm của một ngôn ngữ lập trình định nghĩa ngôn ngữ là một tập hợp các
chuỗi. Tập hợp các chuỗi này tương ứng với tập hợp của các cây dẫn xuất của chúng.
Những cây này dễ hiểu hơn các chuỗi.
Trang 13


if A=0 then X := 0 else X := 1
hoặc trong chuỗi Java
if (A==0) X = 0; else X=1;
Như chúng ta đã biết, cây dẫn xuất hữu ích bởi vì nó thể hiện cấu trúc kinh điển của
chuỗi. Không phải tất cả các cây dẫn xuất đều tương ứng với các chương trình hợp lệ.
Chúng ta biết rằng phân tích ngữ nghĩa tĩnh có nhiệm vụ lựa chọn những cây đáp ứng
các ràng buộc theo ngữ cảnh của ngôn ngữ. Tập hợp các cây kết quả từ quá trình này
tạo nên cú pháp trừu tượng của ngôn ngữ.
không giống như trường hợp của các từ vựng của ngôn ngữ tự nhiên, từ vựng cho
các ngôn ngữ lập trình có thể được hình thành từ một tập hợp vô hạn các từ và có thể
là một danh sách đơn giản, vì vậy được sử dụng trong một từ điển thông thường là
không đủ (ví dụ, về khả năng xác định định danh như dãy các ký tự có độ dài tùy ý bắt
đầu với một ký tự đặc biệt)
2. Phân tích cú pháp
Khi đã xây dựng xong danh sách các token, bộ phân tích cú pháp tìm cách xây
dựng một cây dẫn xuất cho danh sách này. Đây là một cây dẫn xuất trong văn phạm
của ngôn ngữ. Mỗi nút lá của cây này phải tương ứng với một token trong danh sách
token đã xây dựng. Hơn nữa, các nút lá này, đọc từ trái sang phải sẽ hình thành một
cụm từ chính xác (hoặc một chuỗi các ký hiệu terminal) trong ngôn ngữ. Chúng ta đã
biết rằng cây dẫn xuất này mô tả cấu trúc logic của chương trình sẽ được sử dụng bởi
các giai đoạn kế tiếp của quá trình biên dịch.

Cũng có thể xảy ra trường hợp bộ phân tích cú pháp không thể xây dựng được cây
dẫn xuất. Điều này xảy ra khi các chuỗi đầu vào là không đúng với văn phạm của ngôn
ngữ.
Trong trường hợp này, bộ phân tích cú pháp báo cáo các lỗi đã gặp và quá trình
biên dịch sẽ bỏ qua. Trong thực tế, phân tích từ vựng và cú pháp được thực hiện xen kẽ
(đặc biệt là hai giai đoạn không tuần tự nhưng bộ phân tích tạo ra một token cho từng
lời gọi của bộ phân tích cú pháp.
Văn phạm phổ biến (Regular Grammars)
Sự khác nhau giữa phân tích từ vựng và phân tích cú pháp có thể được xác định
chính xác bằng cách sử dụng một phân loại chính thức của văn phạm. Nếu văn phạm
có tất cả các luật có dạng 𝐴 → 𝑏𝐵 (hoặc theo hình thức 𝐴 → 𝐵𝑏), khi đó A và B là ký
hiệu non-terminal (B cũng có thể là rỗng hoặc trùng với A) và b là một ký hiệu

Trang 14


terminal đơn, văn phạm được cho là văn phạm phổ biến. Trong ví dụ 1, văn phạm dựa
trên ký hiệu non-terminal I là văn phạm thông thường.
Ý nghĩa của văn phạm bình thường là rất hạn chế.Đặc biệt, sử dụng một văn phạm
bình thường, nó không phải là có thể mô tả được các đặc tính tùy ý. Kết quả là, nó
không phải là có thể bày được sự cân bằng của các cấu trúc cú pháp như dấu ngoặc khi
sử dụng một văn phạm thông thường.
Về mặt kỹ thuật, phân tích từ vựng là giai đoạn đầu tiên của quá trình dịch, nó
kiểm tra các chuỗi đầu vào có thể được chia ra thành các token, mỗi token được mô tả
bởi một văn phạm thông thường.
Khi đã xây dựng xong danh sách các token, phân tích cú pháp diễn ra bằng cách sử
dụng một văn phạm phi ngữ cảnh đúng, văn phạm phi ngữ cảnh đó sử dụng các token
mà bộ phân tích từ vựng đã sản sinh trước đó như những ký hiệu terminal của nó.
3. Phân tích ngữ nghĩa (Semantic analysis)
Cây dẫn xuất (cây mô tả sự đúng đắn về mặt cú pháp của chuỗi đầu vào) phải được

kiểm tra các ràng buộc về ngữ cảnh của ngôn ngữ. Đó là các khai báo, kiểu dữ liệu, số
lượng tham số của hàm … Khi kiểm tra xong các ràng buộc này, cây dẫn xuất sẽ được
thêm vào những thông tin ràng buộc và sẽ sản sinh ra cấu trúc mới. Ví dụ, mỗi token
tương ứng với một biến định danh sẽ liên hệ với kiểu của nó, nơi khai báo và những
thông tin khác như phạm vi của biến. Để tránh sự trung lấp về những thông tin này,
thông tin sẽ được xây dựng thành cấu trúc bên ngoài cây dẫn xuất. Cấu này gọi là bảng
ký hiệu (symbol table), bảng ký hiệu này có vai trò quan trọng trong giai đoạn phát
sinh mã trung gian .
4. Phát sinh dạng trung gian (Generation of intermediate forms)
Quá trình duyệt cây dẫn xuất thích hợp sẽ tạo khởi đầu cho giai đoạn sản sinh mã.
Nó chưa thể để tạo ra mã trong ngôn ngữ đối tượng, có nhiều thứ cân tối ưu hóa và
chúng độc lập với ngôn ngữ đối tượng cụ thể. Hơn nữa, một trình biên dịch thường
được dùng để tạo ra mã cho một loạt các ngôn ngữ đối tượng (ví dụ, mã máy cho
những kiến trúc khác nhau). Nó rất hữu ích, do đó, tập trung tất cả các lựa chọn liên
quan đến một ngôn ngữ cụ thể trong một giai đoạn và để phát sinh mã sang một hình
thức trung gian, hình thức đó được thiết kế độc lập với cả mã nguồn và những ngôn
ngữ đối tượng.
5. Tối ưu hóa mã lệnh (Code optimisation)
Mã lệnh thu được từ các giai đoạn trước bằng cách liên tục duyệt qua cây dẫn xuất
là khá kém hiệu quả. Có những thứ cần tối ưu hóa phải được thực hiện trước khi tạo
mã đối tượng. Một số công việc có thể được thực hiện để tối ưu hóa là:
Trang 15


 Loại bỏ các mã thừa. Đó là, loại bỏ các đoạn mã mà không bao giờ có thể được
thực hiện vì quá trình thực thi không b ao giờ tiến đến mã lệnh đó
 Một số lời gọi hàm (thủ tục) có thể được thay thế bằng mã lệnh của các hàm
liên quan, giúp cho thực hiện nhanh hơn.Cũng có thể tối ưu hóa quá trình này
 Tìm thừa số của biểu thức con. Một số chương trình tính toán giá trị giống nhau
nhiều hơn 1 lần. Khi trình biên dịch phát hiện, giá trị của những biểu thức con

chung sẽ được lưu trữ lại, nó chỉ đucợ tính toán 1 lần.
 Tối ưu hóa vòng lặp. Khi trong vòng lặp có tính toán giá trị của một biểu thức
con nào đó lặp đi lặp lại, thì nên lưu trữ lại giá trị đó.
6. Sản sinh mã lệnh (Code generation)
Bắt đầu với hình thức trung gian đã tối ưu hóa, mã đối tượng cuối cùng được tạo ra.
Giai đoạn cuối cùng của tối ưu hóa phụ thuộc vào đặc điểm cụ thể của ngôn ngữ đối
tượng. Trong một trình biên dịch tạo ra mã máy, một phần quan trọng của giai đoạn
cuối cùng là đăng ký chuyển giao (quyết định để biến nào nên được lưu trữ trong bộ xử
lý nào). Đây là một sự lựa chọn của tầm quan trọng rất lớn về hiệu quả của chương
trình cuối cùng
IV. Ngữ nghĩa (semantic)
Các mô tả về ngữ nghĩa của ngôn ngữ lập trình có phần phức tạp hơn so với mô tả
cú pháp của nó. Sự phức tạp này là vấn đề kỹ thuật, phải có sự cân đối giữa hai vấn đề
đối lập: tính chính xác và sự linh hoạt.
Một trong những khó khăn của định nghĩa ngữ nghĩa là việc tìm kiếm các giải pháp
dung hòa giữa tính chính xác và tính linh hoạt, làm sao đê loại bỏ sự mơ hồ mà vẫn cài
đặt dễ dàng. Điều này đòi hỏi phải sử dụng các phương pháp chính thức để mô tả ngữ
nghĩa. Những phương pháp kiểu này đã tồn tại trong một thời gian dài trong các ngôn
ngữ nhân tạo của logic toán học và đã được điều chỉnh bởi các nhà khoa học máy tính
cho mục đích riêng của họ.Tuy nhiên, một số hiện tượng ngữ nghĩa làm cho mô tả
chính thức phức tạp và không dễ dàng sử dụng. Đó lý do mà phần lớn các định nghĩa
ngôn ngữ lập trình chính thức sử dụng ngôn ngữ tự nhiên để mô tả ngữ nghĩa. Nhưng
thực tế là các phương pháp chính thức cho ngữ nghĩa rất thường được sử dụng trong
các giai đoạn chuẩn bị thiết kế của một ngôn ngữ lập trình, hoặc để mô tả một số các
đặc điểm riêng của nó, là tối quan trọng để tránh sự mơ hồ với chi phí thấp.
Phương pháp chính thức cho ngữ nghĩa phân chia thành hai loại chính: ngữ nghĩa
biểu hiện và hoạt động. Ngữ nghĩa biểu hiện là sự ghép những ngôn ngữ lập trình của
các kỹ thuật được phát triển cho ngữ nghĩa của ngôn ngữ toán học Logico. Ý nghĩa của
một chương trình được đưa quy định bởi một hàm diễn đạt cách xử lý đầu vào / đầu ra
của chương trình. Phạm vi của hàm phù hợp với cấu trúc toán học, chẳng hạn như môi

Trang 16


trường và bộ nhớ (lưu trữ). Kỹ thuật toán học (liên tục, các điểm cố định …) cho phép
điều trị thích hợp của các hiện tượng như vòng lặp và đệ quy.
Trong phương pháp ngữ nghĩa hoạt động, không có thực thể bên ngoài (ví dụ: hàm)
liên hệ với các cấu trúc ngôn ngữ. Sử dụng phương pháp thích hợp, ngữ nghĩa hoạt
động quy định cụ thể các hành vi của máy tính trừu tượng. Nghĩa là, nó định nghĩa một
cách chính thức trình thông dịch, tạo tham chiếu đến một hình thức trừu tượng ở mức
độ thấp hơn nhiều. Các kỹ thuật khác nhau hoạt động khác nhau trong về hình thức,
một số ngữ nghĩa sử dụng automata chính thức, một số khác sử dụng hệ thống quy tắc
Logic toán học và một số khác sử dụng hệ thống chuyển đổi sang đặc tả cụ thể việc
chuyển đổi trạng thái gây ra bởi một chương trình
Num ::= 1 | 2 | 3 | ...
Var ::= X1 | X2 | X3 | ...
AExp ::= Num | Var | (AExp+ AExp) | (AExp −AExp)
BExp ::= tt | ff | (AExp == AExp) |¬BExp | (BExp ∧ BExp)
Com ::= skip | Var := AExp | Com;Com |
if BExp then Com else Com | while BExp do Com
Đoạn chương trình trên cho thấy ngữ pháp của một ngôn ngữ đơn giản. Chúng ta có
một ngữ pháp với tập luật vô hạn cho Num và Var. Các dấu ngoặc đơn sử dụng trogn
các phép toán 2 ngôi loại bỏ các vấn đề có thể sự mơ hồ.
Ký hiệu n để biểu thị một Num tùy ý (số không đổi); sử dụng X, biểu thị một Var
tùy ý (biến). a là AExp tùy ý (số học biểu thức). b để biểu thị một BExp tùy ý
(boolean, và tt và ff hiện các giá trị đúng và sai, tương ứng), c là Comm tùy ý(các
lệnh). khi cần thiết, subscript để phân biệt giữa các đối tượng của loại cú pháp tương tự
(ví dụ, chúng ta sẽ viết a1, a2, … , cho AExps).
1.Trạng thái (State)
Ngữ nghĩa của một câu lệnh trong ngôn ngữ của chúng ta sử dụng một mô hình bộ
nhớ đơn giản lưu trữ các giá trị của Var.Trong mô hình này, State (trạng thái) là một

chuỗi hữu hạn các cặp hình thức (X, n) mà chúng ta có thể đọc là "trong trạng thái hiện
tại, biến X có n giá trị" (trong ví dụ này, giá trị sẽ luôn luôn là một số nguyên). Cho
câu lệnh c,trạng thái tham chiếu của nó được xác định bởi một chuỗi các cặp mà bao
gồm tất cả var được đặt tên trong c. Chúng ta biểu diễn trạng thái tùy ý là σ hoặc τ.
Chúng ta cần phải xác định một số hành động trên các trạng thái: sửa đổi của trạng
thái hiện có và thu hồi giá trị của một biến trong trạng thái hiện tại. Cho một trạng thái
Trang 17


σ, một Var X và một giá trị v, chúng tôi viết σ [X ← v] để biểu diễn một trạng thái
mới, trạng đó là giống như σ nhưng khác từ nó bằng cách kết hợp X với giá trị v(và do
đó mất đi mối liên trước đối với X). Với một trạng thái σ, và một biến X, chúng ta viết
σ (X) cho các giá trị σ liên hệ với X, giá trị này là không xác định nếu X không xuất
hiện trong các miền của σ (σ do đó là một hàm một phần).
Ví dụ: Giả sử σ = [(X, 3), (Y, 5), chúng ta có σ [X ← 7] = [(X, 7), (Y, 5)]. Chúng ta
cũng có σ (Y) = 5 và σ [X← 7] (X) = 7; σ (W) là không xác định
2. Quá trình chuyển đổi (Transition)
Ngữ nghĩa hoạt động có cấu trúc có thể được xem như một cách hiệu quả để xác
định các chức năng của một máy tính trừu tượng mà không đi vào bất kỳ chi tiết về
việc cài đặt của nó. Chức năng này được thể hiện trong các bước tính toán cơ bản của
máy trừu tượng. Cách chính thức mà trong đó ngữ nghĩa hoạt động có cấu trúc xác
định ý nghĩa của một chương trình, c, ở trong một quá trình chuyển đổi thể hiện một
bước chuyển đổi (của trạng thái and/ or của chương trình) gây ra bởi việc thực hiện của
lệnh. Hình thức đơn giản nhất của quá trình chuyển đổi là:
< 𝑐, 𝜎 >→ 𝜏
Trong đó c là một lệnh, σ là trạng thái bắt đầu và 𝜏 là trạng thái terminal. Những ký
hiệu này nghĩa là nếu chúng ta bắt đầu thực hiện lệnh c trong trạng thái σ, quá trình
thực thi sẽ chấm dứt (trong một bước duy nhất) với trạng thái 𝜏.Ví dụ, quá trình
chuyển đổi định nghĩa các lệnh skip là:
< 𝒔𝒌𝒊𝒑, 𝜎 >→ 𝜏

Chúng ta có một lệnh không làm gì cả. Bắt đầu từ trạng thái bất kỳ, σ, lệnh skip
không làm gì cả, trạng thái σ không thay đổi.Trong những trường hợp phức tạp, trạng
thái cuối cùng sẽ đạt được không phải trong một bước lớn duy nhất, mà bằng nhiều
bước nhỏ mà dần dần biến đổi trạng thái (bắt đầu với σ); lệnh, c, dần dần thực hiện dần
dần cho đến khi toàn bộ đã được "tiêu thụ". Các bước này ít được thể hiện bởi quá
trình chuyển đổi hình thức:
< 𝑐, 𝜎 >→< 𝑐′, 𝜎′ >
Ví dụ, một trong những quá trình chuyển đổi định nghĩa các lệnh có điều kiện sẽ được:
< 𝒊𝒇 𝒕𝒕 𝒕𝒉𝒆𝒏 𝑐1 𝒆𝒍𝒔𝒆 𝑐2 , 𝜎 >→< 𝑐1 , 𝜎 >
Điều này có nghĩa rằng nếu điều kiện boolean là đúng, các lệnh trong nhánh sau đó
phải được thực hiện..Quá trình chuyển đổi có điều kiện mang hình thức của một quy
tắc, thể hiện như sau:
Trang 18


< 𝑐1 , 𝜎1 >→< 𝑐1′ , 𝜎1′ > < 𝑐2 , 𝜎2 >→< 𝑐2′ , 𝜎2′ >
< 𝑐, 𝜎 >→< 𝑐′, 𝜎′ >
Chúng ta đọc quy tắc này theo cách sau. Nếu lệnh, 𝑐1 , bắt đầu từ trạng thái 𝜎1 , có
thể thực hiện một bước tính toán có thể biến đổi thành lệnh 𝑐1′ trong trạng thái 𝜎1′ , và
nếu lệnh 𝑐2 , bắt đầu từ trạng thái 𝜎2 , có thể thực hiện một bước tính toán và chuyển đổi
chính nó thành lệnh 𝑐2′ , trong trạng thái 𝜎2′ , sau đó lệnh c, bắt đầu từ trang thái σ có thể
thực hiện một bước tính toán và biến đổi thành lệnh 𝑐′ ở trạng thái 𝜎′. Nó rõ ràng là
một quy tắc cụ thể sẽ thể hiện một số mối quan hệ có ý nghĩa giữa c, c1 và c2 (và các
trạng thái tương ứng của chúng). Nói chung, c1 và c2 sẽ là lệnh con của c

3. Ngữ nghĩa biểu thức (Expression semantics)
Ví dụ trên cho thấy các quy tắc ngữ nghĩa của biểu thức số học. Ba quy tắc đầu tiên
là quy tắc termial (có nghĩa là, việc tính toán ở bên phải mũi tên trong một hình thức
mà không có quá trình chuyển đổi được áp dụng). Chúng xác định ngữ nghĩa của một
biến, bổ sung trong trường hợp trong đó cả hai của summands là hằng số, trừ trường

hợp trong đó cả hai đối số của nó là hằng số và kết quả là một số tự nhiên. Lưu ý rằng
không có ngữ nghĩa cho biểu thức như 5 - 7. Nhóm thứ hai của bốn quy tắc là các quy
tắc có điều kiện. Cặp đầu tiên xác định ngữ nghĩa của sum và diễn đạt là để tính giá trị
của sum, đầu tiên nó đánh giá hai đối số của nó. Lưu ý rằng ngữ nghĩa không đặc tả
thứ tự khi đánh giá các đối số cộng vào, phép trừ được xử lý tương tự.
Hình 5 cho thấy ngữ nghĩa của các biểu thức hợp lý và thông qua những ý tưởng
tương tự như đối với biểu thức số học. Lưu ý rằng trong con số này, bv biểu thị một giá
trị boolean (tt hoặc ff).

Trang 19


Hình 5: Ngữ nghĩa của biểu thức Bool

4. Ngữ nghĩa lệnh (Command semantics)
Có thể thấy rằng trạng thái σ luôn luôn không thay đổi trong quá trình đánh giá của
một biểu thức và nó được sử dụng để đạt được giá trị của một biến như thế nào. Điều
này thay đổi ngữ nghĩa của các lệnh như trong hình 2.14. Lưu ý, các quy tắc trong hình
cơ bản của hai loại: đối với mỗi lệnh, thể hiện các bước tính toán thực tế cho lệnh đó
(điều này giữ cho các quy tắc (c1), (c2), (c4), (c6), (C7) và (c9)), phục vụ việc tính
toán của một biểu thức con. Mô tả ngữ nghĩa của ngôn ngữ của chúng ta bây giờ là
hoàn tất.

Trang 20


5. Tính toán (Computations)
Tính toán là một chuỗi các quá trình chuyển đổi mà không thể được mở rộng bởi
quá trình chuyển đổi khác. Hơn nữa, mỗi chuyển đổi trong tính toán phải được mô tả
bởi một số quy tắc.

Ví dụ, xem xét đoạn chương trình c sau:

X := 1; while ¬(X == 0) do X := (X −1)
Giả sử chúng ta có một trạng thái bao gồm tất cả các biến đã đề cập trong chương
trình, ví dụ, σ = [(X, 6)]. Chúng ta có thể tính toán các tính toán c σ như sau. Để viết
tắt các ký hiệu, chúng ta viết c để biểu thị các lệnh lặp đi lặp lại trong khi ¬ (X ==0)
làm X: = (X - 1). Không khó để thấy rằng việc tính toán tạo ra bởi c sau đây:

V. Ngữ Dụng Và Cài Đặt
1. Ngữ dụng (Pragmatics)
Nếu cho một mô tả chính xác cú pháp và ngữ nghĩa của ngôn ngữ lập trình, không
đúng với tính thực dụng của ngôn ngữ. Tính thực dụng của một ngôn ngữ câu trả lời
câu hỏi "Mục đích của việc này là những gì xây dựng". Rõ ràng, do đó, tính thực dụng
của một ngôn ngữ lập trình không phải là thiết lập một lần và cho tất cả trong định
nghĩa của nó (định nghĩa của cú pháp và ngữ nghĩa của nó). Ngược lại, nó phát triển
với việc sử dụng của ngôn ngữ. Tất cả các đề xuất về phong cách lập trình là một phần
của tính thực dụng. Ví dụ, có nguyên tắc nhảy (gotos) cần tránh sử dụng. Việc lựa
Trang 21


×