1. Trang chủ
  2. » Công Nghệ Thông Tin

Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề

80 9 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 80
Dung lượng 900,42 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 giúp bạn nắm được các khái niệm cơ bản của ngôn ngữ lập trình chung, hiểu được các thành phần của một ngôn ngữ lập trình, biết phân biệt các đặc trưng khác nhau của các ngôn ngữ lập trình. Mời các bạn tham khảo!

Trang 1

Bài 3 TÊN BÀI:HÀM THỦ TỤC

MÃ BÀI:: ITPRG3-06.3Giới thiệu

Khái niệm chương trình con (sub-program hay sub-routine) ra đời từ rất sớm vàonhững năm 1950 Mà sau đó chương trình con dạng hàm hay thủ tục đã được sử dụng rộngrãi trong các ngôn ngữ lập trình, đặc biệt là các ngôn ngữ lập trình mệnh lệnh Cho đến ngàynay, khi mà các ngôn ngữ lập trình rất pgong phú đa dạng thì khái niệm này vẫn tồn dướinhiều hình thức khác nhau

Mục tiêu thực hiện

- Hiểu rõ cơ chế thực hiện của chương trình con dạng hàm và thủ tục

- Phân biệt và sử dụng đúng các dạng tham số

- Nắm cấu trúc chuẩn của một chương trình con

- Hiểu được tính ưu việt của các chương trình con

- Nắm được cách xây dựng và sử dụng chương trình con trong ngôn ngữ lập trìnhPascal

- Nắm được khái niệm đệ quy

Nội dung chính

Trình bày hai khái niệm hàm và thủ tục Nêu bật ưu điểm của hàm và thủ tục Trình bày cáchxây dựng hàm và thủ tục trong ngôn ngữ lập trình Pascal

Khái niệm chương trình con

Khái niệm chương trình con (sub-program hay sub-routine) được ra đời từ rất sớm vàonhững năm 1950, khi mà ngôn ngữ để lập trình mới chỉ là ngôn ngữ máy Do việc, viếtchương trình bằng các bit nhị phân là rất phức tạp, khó khăn, người ta đã nghĩ đến việc xâydựng sẵn các đoạn chương trình thường hay sử dụng Các đoạn chương trình này chính làtiền thân cho khái niệm chương trình con

Chương trình con thực ra là những đoạn chương trình (dãy các câu lệnh) thườngđược hay sử dụng lặp đi lặp lại trong khi lập trình Để giảm bớt thời gian lập trình, người taxây dựng sẵn các thư viện chứa các chương trình con mà sau đó các chương trình con này

có thể được sử dụng nhiều lần

Ví dụ, tính cos hay sin là các công việc thường hay gặp trong toán học Thế thì thay vìmỗi lần cần đến ta phải thực hiện tính toán, ta có thể xây dựng sẵn các chương trình concho phép thực hiện công việc tính toán này và sau đó chỉ việc sử dụng

Trong thực tế, trong hầu hết tất cả các ngôn ngữ lập trình các công việc thường đượclặp đi lặp lại như thế này đều được xây dựng sẵn thành các chương trình con chứa trongcác thư viện dành cho người sử dụng Ngoài ra trong quá trình lập trình, người lập trình cóthể tự xây dựng cho mình các chương trình con được sử dụng nhiều lần trong một chươngtrình

Khái niệm chương trình con có hầu hết trong các ngôn ngữ lập trình, mà có thể tên gọicủa nó bị thay đổi đi chút ít, như: hàm, thủ tục, thao tác, phương thức, Đặc biệt trong các

Trang 2

ngôn ngữ lập trình mệnh lệnh (như Pascal) thì chương trình con được chia làm hai loại: hàm(function) và thủ tục (procedure).

Trong bài học này chúng ta sẽ tìm hiểu về hai loại chương trình con này thông qua ngôn ngữlập trình Pascal, là một ngôn ngữ mang tính sư phạm cao và thể hiện rất rõ hai khái niệmnày

Xây dựng hàm và thủ tục

Trước hết hàm hay thủ tục đều là những đoạn chương trình thường được sử dụng lặp

đi lặp lại Thế sự khác nhau giữa hai khái niệm này là gì?

Hàm sau khi thực hiện xong công việc thì tra về một giá trị thông qua tên hàm, trongkhi thủ tục không trả về giá trị nào cả

Ví dụ, hàm binhphương tính giá trị bình phương của một số nguyên sẽ trả về giá trị đóqua tên hàm Trong khi thủ tục xuatmanhinh thực hiện việc in ra màn hình một kết quả tínhtoán nào đó thì nó không trả về một giá trị nào cả

Trong ngôn ngữ Pascal, các chương trình con phải được khai báo và viết bên trênthân chương trình, sau đó được sử dụng trong thân chương trình

Cú pháp tổng quát để viết một hàm trong Pascal như sau:

Function tên_hàm (khai báo các tham số hình thức) : kiểu_trả_về_của_hàm;

(* Các khai báo hằng, biến cục bộ *)

Begin

(*thân hàm*) tên_hàm := biểu_thức; (* gán giá trị trả về *) End;

Khi khai báo một hàm, nếu hàm đó có sử dụng các hằng hay biến cục bộ thì phải khaibáo sau khi khai báo hàm Ở đây chúng ta thấy xuất hiện khái niệm biến cục bộ (localvariable) là các biến được khai báo bên trong một hàm (hay thủ tục) Trong thân hàm luônphải có phép gán giá trị trả về cho tên hàm

Dưới đây là một ví dụ khác, chương trình có chứa hàm tính giá trị lớn nhất của hai sốthực Hàm được sử dụng trong thân chương trình để tính giá trị lớn nhất của các biểu thứca+b và a-b

Program vi_du_max;

Var

Trang 3

a, b, s : real;

(*Khai báo hàm max2so*)

Function max2so(x, y : real) : real;

Var

r : real; (* khai báo biến cục bộ *)Begin

if x > y then r := xelse r := y;

Procedure tên_thủ_tục (khai báo các tham số hình thức);

(* Các khai báo hằng, biến cục bộ*)

1 Begin (*thân thủ tục*) End;

Bây giờ chúng ta viết lại chương trình tính giá trị lớn nhất hai số thực sử dụng chương trình con là thủ tục như sau:

Program vi_du_max;

Var

a, b : real;

(*Khai báo thủ tục max2so*)

Procedure max2so(x, y : real);

Var

r : real; (* khai báo biến cục bộ *)Begin

if x > y then r := xelse r := y;

Writeln(‘Max = ’, r:5:1);

End;

Trang 4

(*Thân chương trình chính*)

Begin

a := 11.45

b := -42.7max2so(a+b, a-b); (* gọi chương trình thủ tục *)End

Trong ngôn ngữ Pascal, còn cho phép viết các chương trình con bên trong thân một chươngtrình con khác Chẳng hạn, chúng ta xem xét ví dụ thủ tục M sau:

Trong ví dụ này, bên trong thân của thủ tục M chứa hai chương trình con khác là hàmM1 và thủ tục M2 Sau đó, trong thân của thủ tục M sử dụng hai chương trình con này.Lưu ý là không phải ngôn ngữ lập trình nào cũng cho phép khai báo các chương trìnhcon bên trong chương trình con khác, chẳng hạn như ngôn ngữ C không cho phép điều này

Cơ chế hoạt động của chương trình con

Liên quan đến chương trình con (hàm và thủ tục ở trên), chúng ta có một số khái niệm sau:

- Biến cục bộ: là biến được khai báo và chỉ sử dụng bên trong thân một chương trìnhcon, là biến r trong ví dụ trên

- Biến toàn cục: là biến được khai báo ở đầu chương trình và có thể được sử dụngbất cứ đâu trong chương trình, là các biến a và b trong ví dụ trên

Trang 5

- Tham số hình thức (hay còn được gọi là đối): là các biến được khai báo sau tên củachương trình con (chúng ta sẽ được giới thiệu chi tiết hơn về tham số hình thứctrong các phần tiếp theo), là các tham số x và y trong ví dụ trên.

- Tham số thực: là các giá trị truyền cho các tham số hình thức tương ứng khi gọi cácchương trình con Chẳng hạn, trong ví dụ trên là các giá trị của biểu thức a+b và a-b

Cơ chế hoạt động của một chương trình con là như sau: chương trình được batứ đầu từ câulệnh đầu tiên và kết thúc khi thực hiện xong câu lệnh cuối cùng trong thân chương trình, nếuchương trình gặp một lời gọi chương trình con (thủ tục hay hàm) thì máy sẽ thực hiện:

- cấp phát bộ nhớ cho các biến cục bộ của chương trình con,

- truyền giá trị của các tham số thực cho các tham số hình thức tương ứng,

- thực hiện lần lượt các câu lệnh trong thân chương trình con,

- giải phóng các biến cục bộ và trở về nơi gọi nó, nếu chương trình con là hàm thì khitrở về mang theo một giá trị

Quay trở lại chương trình chứa thủ tục max2so trên, hoạt động của nó là như sau:

- gán giá trị 11.45 cho biến a và –42.7 cho biến b,

- gặp lời gọi thủ tục max2so, thực hiện thủ tục max2so:

o cấp phát bộ nhớ cho biến cục bộ r và các tham số hình thức x và y,

o giá trị của biểu thức a+b và a-b được truyền cho các tham số hình thức x vày,

o thực hiện các câu lệnh trong thân thủ tục để tính giá trị lớn nhất chứa trongbiến r,

o gọi thủ tục Writeln để in ra kết quả,

o giải phóng các biến cục bộ r và tham số hình thức x, y,

o máy thoát ra khỏi thủ tục để trở về chương trình chính,

- kết thúc chương trình chính

Biến toàn cục và biến cục bộ

Ở trên chúng ta đã nhắc đến hai khái niệm biến cục bộ và biến toàn cục, trong phầnnày chúng ta sẽ xem xét một cách chi tiết hơn

Biến toàn cục (global variable) là những biến được khai báo ở đầu chương trình,chúng tồn tại trong suốt thời gian làm việc của chương trình Biến toàn cục được sử dụngbất kì đâu ở trong chuơnưg trình, nghĩa là trong thân chương trình chính hoặc trong các thânchương trình con

Biến cục bộ (local variable) là biến được khai báo ở đầu một chương trình con Biếncục bộ được cấp phát bộ nhớ khi chương trình con được gọi tới và bị giải phóng khỏi bộ nhớkhi máy ra khỏi chương trình con Biến cục bộ chỉ được sử dụng bên trong thân của chươngtrình con khai báo nó cũng như các chương trình con khác nằm bên trong thân của chươngtrình con khai báo nó

Để phân biệt rỏ sự khác nhau của biến cục bộ và biến toàn cục, chúng ta quan sát ví

dụ sau:

Trang 6

Hoạt động của chương trình này là như sau:

- bắt đầu chương trình chính, biến x được gán giá trị 10,

Trang 7

- in x ra màn hình,

- gọi thủ tục M, thực hiện các câu lệnh trong thân thủ tục M,

o gán biến a bằng 1 và biến b bằng 5,

o in ra màn hình giá trị các biến a và b,

o gọi thủ tục M1, thực hiện các câu lệnh trong thân thủ tục M1,

 biến toàn cục x được tăng lên một đơn vị,

 gán biến cục bộ n bằng giá trị biểu thức a+b,

- in ra giá trị của biến cục bộ x và kết thúc chương trình

Kết quả của chương trình trên là:

Cơ chế truyền tham số

Ở trong các phần trên, chúng ta đã được giới thiệu cách xây dựng các chương trìnhcon Sau đó, chúng ta có thể sử dụng (lời gọi chương trình con) chương trình con Mỗi khi

sử dụng chương trình con, thông thường đều phải truyền dữ liệu cho nó Có các cách truyền

dữ liệu cho chương trình con khác nhau sau:

- truyền tham số dạng biến toàn cục,

- truyền tham số dạng tham trị,

- truyền tham số dạng tham biến

D Truyền tham số dạng biến toàn cục

Do phạm vi sử dụng của biến toàn cục là bất kỳ mọi nơi trong chương trình nen ta cóthể sử dụng chúng đẻ truyền dữ liệu cho các chương trình con cũng như nhận kết quả tính

được từ các chương trình con

Trang 8

Ví dụ chương trình giải phương trình bậc hai (ax2 + bx + c = 0) dưới đây truyền tham

số bằng biến toàn cục Trong ví dụ này, để giảm bớt phức tạp, chúng ta không xét đến các

trường hợp suy biến của phương trình bậc 2.Program Phuong_trinh_bac_2;

sử dụng biến toàn cục như thế này rất khó để kiểm soát giá trị của chúng nên điều nàythường dẫn đến sai sót

Do những nhược điểm như vây, nên người ta khuyến khích người lập trình không sửdụng phương pháp truyền tham số bằng biến toàn cục Phương pháp dưới đây sẽ khắcphục nhược điểm trên

Trang 9

E Truyền tham số dạng tham trị

Chúng ta cần nhắc lại rằng, đối với chương trình con có hai loại tham số Tham sốhình thức là các biến khai báo sau tên chương trình con, tham số thực là các giá trị hay biếntruyền cho các tham số hình thức tương ứng khi gọi chương trình con

Tham số hình thức được chia làm hai dạng: tham trị và tham biến Trước hết chúng ta

Function ham (x, y : real; a, b : real) : real;

Procedure thutuc (x : real; a, b, c : real);

Khi có lời gọi chương trình con, các tham số thực sẽ được truyền cho các tham số hìnhthức Các tham số thực phải là một biểu thức cùng kiểu với tham số hình thức tương ứng.Chẳng hạn, nếu tham số hình thức có kiểu nguyên thì tham số thực phải là một biểu thứckiểu nguyên

Bây giờ chúng ta viết lại chương trình giải phương trình bậc 2 sử dụng tham số dạng thamtrị như sau:

r := sqrt(delta);

x1 := (-b-r)/(2*a);

x2 := (-b+r)/(2*a);

if (delta = 0) then Writeln(‘PT có nghiệm kép: ’, x1:5:2);

if (delta > 0) then Writeln(‘PT có hai nghiệm: x1 = ’, x1:5:2, ‘x2 = ’, x2:5:2);

Trang 10

- truyền giá trị của các tham số thực cho các tham số dạng tham trị tương ứng, cácgiá trị x, y, z, được truyền vào tương ứng cho a, b, c,

- thực hiện các câu lệnh trong chương trình con,

- kết thúc chương trình con, máy sẽ giải phóng các biến cục bộ và các tham số hìnhthức, như thế các giá trị đặt trong các biến cục bộ và các tham số hình thức khôngthể đưa về để sử dụng trong một chương trình khác

Nhận xét: các tham số hình thức dạng tham trị chỉ được sử dụng trong chương trình conkhai báo chúng

F Truyền tham số dạng tham biến

Trong ví dụ trên, các nghiệm của phương trình được in ra ngay trong thủ tục Tuynhiên, nếu chúng ta muốn chương trình phải trả về nghiệm của phương trình và việc in sẽđược thực hiện trong chương trình chính thì cách sử dụng tham số dạng tham trị không giảiquyết được Trong trường hợp này, chúng ta sử dụng tham số dạng tham biến, tức là giá trịcủa tham số vẫn được sử dụng sau khi ra khỏi chương trình con

Các tham số dạng tham biến được khai báo sau tên chương trình con giữa hai dấu

ngoặc theo mẫu sau (với từ khóa Var):

Var danh_sách_tham_số : kiểu; Var danh_sách_tham_số : kiểu;

Ví dụ:

Function (x,y : real; Var a : real; Var p,q : real) : real;

Khi có lời gọi chương trình con, các tham số thực sẽ được truyền cho các tham sốhình thức Các tham số thực phải là một biến hay phần tử mảng có cùng kiểu với tham sốhình thức tương ứng Chẳng hạn, nếu tham số hình thức có kiểu nguyên thì tham số thựcphải là một biến kiểu nguyên

Chúng ta viết lại chương trình giải phương trình bậc 2, trong đó thủ tục gptb2 nhận 3tham số dạng tham trị là a, b, c, trả về ba giá trị bởi tham biến là delta, x1, x2

Trang 11

- cấp phát bộ nhớ cho các biến cục bộ và các tham số dạng tham trị và tham biến,

- truyền giá trị của tham số thực cho các tham số dạng tham trị tương ứng,

- truyền địa chỉ của các biến tham số thực cho các tham số dạng tham biến,

- thực hiện các câu lệnh trong thâm chương trình con

Như thế, đối với các tham số dạng tham biến, thay vì truyền giá trị của tham số thực thì phảitruyền địa chỉ của biến tham số thực Vì vậy, mọi sự thay đổi giá trị của tham biến trongchương trình con sẽ kéo theo sự thay đổi của biến tham số thực Trong ví dụ trên, mọi thayđổi giá trị trên các biến d, n1, n2 trong chuơng trình con cũng sẽ có hiệu lực sau khi đã thoát

ra khỏi chương trình con

Đệ quy

Một chương trình con được gọi là đệ quy (recursivity) nếu trong thân chương trình con

đó có lời gọi đến chính nó Nhiều ngôn ngữ lập trình cho phép xây dựng các chương trìnhcon đệ quy

Chúng ta lấy ví dụ tính giai thừa của một số nguyên n Giai thừa n được định nghĩanhư sau:

n! = 1.2.3 (n-1).n

hoặc

1 nếu n = 0n! =

n.(n-1)!nếu n1

Trang 12

Trong cách định nghĩa sau, cách tính n! phụ thuộc vào (n-1)! Với định nghĩa nàychúng ta xây dựng hàm đệ quy tính n! bằng ngôn ngữ Pascal như sau:

Function giai_thua1(n : longint) : longint;

Như thế, đối với một chương trình con đệ quy thì sẽ cần rất nhiều bộ nhớ cho các biến cục

bộ Thậm chí nếu chương trình con đệ quy thực hiện lời gọi đệ quy không dừng thì sẽ dẫn đến tình trạng tràn bộ nhớ Chẳng hạn, nếu người sử dụng gọi hàm giai_thua1 trên như sau:

số n và hai biến cục bộ i, gt kiểu longint

Một ví dụ thứ hai minh họa chương trình con đệ quy Ước số chung lớn nhất của hai

số nguyên a và b được xác định theo công thức:

- nếu x = y thì usc(x, y) = x

- nếu x > y thì usc(x, y) = usc(x-y, y)

- nếu x < y thì usc(x, y) = usc(x, y-x)

Hàm đệ quy usc được viết như sau:

Trang 13

Function usc(a, b : int) : int;

Begin

if x = y then usc := x;

else if x > y then usc := usc(x – y, y);

else usc := usc(x, y - x);

End;

Nhận xét: Phương pháp đệ quy cho phép viết chương trình ngắn gọn đơn giản, nhưng lại không hiệu quả về mặt sử dụng tài nguyên bộ nhớ

Tính ưu việt của chương trình con

Hầu hết tất cả các ngôn ngữ lập trình đều sử dụng khái niệm chương trình con.Chương trình con chỉ định nghĩa một lần nhưng sao đó được sử dụng nhiều lần Việc viếtchương trình sử dụng chương trình con chúng ta nhận thấy có các ưu điểm sau:

- giảm bớt số dòng lệnh của một chương trình,

- giảm thời gian lập trình,

- giảm độ phức tạp của chương trình,

- chương trình được tổ chức theo dạng tập hợp các chương trình con, nên dễquản lý hơn,

- dễ sữa đổi chương trình khi cần thiết,

- dễ kiểm tra lỗi

Bài tập

1 Hai khái niệm hàm và thủ tục khác nhau chổ nào?

2 Tại sao không nên sử dụng biến toàn cục?

3 Viết thủ tục giải phương trình trùng phương ax4 + bx2 + c = 0

4 Viết hàm tính giá trị lớn nhất (nhỏ nhất) của một dãy số

5 Viết hàm hay thủ tục giải hệ phương trình bậc nhất:

Trang 14

BÀI 4 ĐẶC TRƯNG CÚ PHÁP VÀ NGỮ NGHĨA CHƯƠNG TRÌNH

Mã bài:ITPRG3-06.4

Giới thiệu

Bài học sẽ trình bày tổng quan các vấn đề liên quan đến ngôn ngữ lập trình Chẳnghạn, một ngôn ngữ lập trình được xây dựng như thế nào, làm sao để máy tính có thể hiểuđược một chương trình nào đó, … Như thế, việc hiểu được bản chất của ngôn ngữ lập trình

sẽ giúp cho người lập trình viết các chương trình hữu hiệu hơn

Mục tiêu thực hiện

- Hiểu được cú pháp của các ngôn ngữ

- Nắm các đặc trưng mang tính ngữ nghĩa của chương trình

- Nắm các tiền đề cho sự phát triển của chương trình qua ngữ pháp và ngữ nghĩa

- Viết chương trình có khả năng thân thiện hơn

Nội dung chính

Trình bày ngắn gọn cách định nghĩa, xây dựng một ngôn ngữ lập trình, cách phân tích mộtchương trình, các thành phần cần thiết để phân tích một chương trình

Khái niệm ngôn ngữ

Một ngôn ngữ dù là ngôn ngữ tự nhiên như tiếng Việt hay là ngôn ngữ lập trình nhưPascal, cũng đều có thể xem là một tập hợp các câu có cấu trúc quy định nào đó Cấu trúccâu được quy định ra sao thì đó là vấn đề cách biểu diễn ngôn ngữ Chúng ta có thể nhậnxét thấy rằng, một câu của ngôn ngữ, dù là câu tiếng Việt “bạn đi học” hay cả một văb bảnchương trình từ chữ “Program” cho đến dấu chấm “.” kết thúc chương trình, thì cũng đềuchẳng qua là một dãy các xâu/từ có sẵn như “bạn”, “đi”, “học”, hay “Program”, … được liệt

kê trong một bảng chữ nào đó, mà ta có thể xem là các kí hiệu cơ bản của ngôn ngữ

Từ nhận xét trên đây, chúng ta đi đến một số khái niệm hình thức về ngôn ngữ như dưới đây

Bảng chữ (alphabet) là một tập hợp các kí hiệu Ví dụ:

{a, b, c, , z} : bảng chữ cái Latin{0,1, 2, , 9} : bảng chữ số thập phân{0,1} : bảng chữ số nhị phânXâu (string) là một dãy hữu hạn các kí hiệu từ bảng chữ cái

Sau đây là một ví dụ về các khía cạnh cú pháp và ngữ nghĩa trong ngôn ngữ lập trình.Chúng ta có các biểu thức sau:

Trang 15

Ðể xác định cú pháp của một ngôn ngữ, người ta dùng văn phạm phi ngữ cảnh CFG

(Context Free Grammar)

Văn phạm phi ngữ cảnh bao gồm bốn thành phần:

1 Một tập hợp các token , gọi là các ký hiệu kết thúc (terminal symbols)

Ví dụ: Các từ khóa, các chuỗi, dấu ngoặc đơn,

2 Một tập hợp các ký hiệu chưa kết thúc (nonterminal symbols), còn gọi là các biến (variables)

Ví dụ: Câu lệnh, biểu thức,

3 Một tập hợp các luật sinh (productions) trong đó mỗi luật sinh bao gồm một ký hiệu chưa kết thúc - gọi là vế trái, một mũi tên và một chuỗi các token và / hoặc các ký hiệu chưa kết thúc gọi là vế phải

4 Một trong các ký hiệu chưa kết thúc được dùng làm ký hiệu bắt đầu của văn phạm Chúng ta qui ước:

- Mô tả văn phạm bằng cách liệt kê các luật sinh

- Luật sinh chứa ký hiệu bắt đầu sẽ được liệt kê đầu tiên

- Nếu có nhiều luật sinh có cùng vế trái thì nhóm lại thành một luật sinh duy nhất, trong đó các vế phải cách nhau bởi ký hiệu “ | “ đọc là “hoặc”

Ví dụ 4.1: Xem biểu thức là một danh sách của các số phân biệt nhau bởi dấu + và dấu - Ta

có, văn phạm với các luật sinh sau sẽ xác định cú pháp của biểu thức

list  list + digit

list  list – digit

list  digit

digit  0 | 1 | 2 | | 9

Như vậy văn phạm phi ngữ cảnh ở đây là:

Tập hợp các ký hiệu kết thúc: 0, 1, 2, , 9, +,

Tập hợp các ký hiệu chưa kết thúc: list, digit

- Các luật sinh đã nêu trên

- Ký hiệu chưa kết thúc bắt đầu: list

Trang 16

9 - 5 + 2 là một list vì 9 - 5 là một list và 2 là một digit.

Ví dụ 4.3:

Một list là một chuỗi các lệnh, phân cách bởi dấu ; của khối begin - end trong Pascal Một

danh sách rỗng các lệnh có thể có giữa begin và end

Chúng ta xây dựng văn phạm bởi các luật sinh sau:

block  begin opt_stmts end

opt_stmts  stmt_list | 

stmt_list  stmt_list ; stmt | stmt

Trong đó opt_stmts (optional statements) là một danh sách các lệnh hoặc không có lệnh nào( ).

Luật sinh cho stmt_list giống như luật sinh cho list trong ví dụ 2.1, bằng cách thay thế +, - bởi

; và stmt thay cho digit

H Cây phân tích cú pháp (parsing tree)

Cây phân tích cú pháp minh họa ký hiệu ban đầu của một văn phạm dẫn đến một chuỗi trong ngôn ngữ

Nếu ký hiệu chưa kết thúc A có luật sinh A XYZ thì cây phân tích cú pháp có thể có một nút trong có nhãn A và có 3 nút con có nhãn tương ứng từ trái qua phải là X, Y, Z

Hình 4.1 Cây phân tích cú pháp nhãn A

Một cách hình thức, cho một văn phạm phi ngữ cảnh thì cây phân tích cú pháp là mộtcây có các tính chất sau đây:

1 Nút gốc có nhãn là ký hiệu bắt đầu

2 Mỗi một lá có nhãn là một ký hiệu kết thúc hoặc một 

3 Mỗi nút trong có nhãn là một ký hiệu chưa kết thúc

4 Nếu A là một ký hiệu chưa kết thúc được dùng làm nhãn cho một nút trong nào đó và X1 Xn là nhãn của các con của nó theo thứ tự từ trái sang phải thì A X1X2 Xn là một luật sinh Ở đây X1, , Xn có thể là ký hiệu kết thúc hoặc chưa kết thúc Ðặc biệt, nếu A  thì nút có nhãn A có thể có một con có nhãn 

string string + string | string - string | 0 | 1 | | 9

Với văn phạm này thì chuỗi biểu thức 9 - 5 + 2 có đến hai cây phân tích cú pháp như

Trang 17

sau :

Hình 4.2 Hai cây phân tích cú pháp

Tương tự với cách đặt dấu ngoặc vào biểu thức như sau :

(9 - 5) + 2 9 - ( 5 + 2)

Bởi vì một chuỗi với nhiều cây phân tích cú pháp thường sẽ có nhiều nghĩa, do đó khi biên dịch các chương trình ứng dụng, chúng ta cần thiết kế các văn phạm không có sự nhập nhằng hoặc cần bổ sung thêm các qui tắc cần thiết để giải quyết sự nhập nhằng cho văn phạm

Ví dụ 4.5 : Trong ngôn ngữ C, biểu thức a = b = c tương đương a = ( b = c) vì chuỗi a =

b = c với toán tử kết hợp phải được sinh ra bởi văn phạm:

right letter = right | letter

letter a | b | | z

Ta có cây phân tích cú pháp có dạng như sau (chú ý hướng của cây

nghiêng về bên phải trong khi cây cho các phép toán có kết hợp trái

thường nghiêng về trái):

Trang 18

Thứ tự ưu tiên của các toán tử

Xét biểu thức 9 + 5 * 2 Có 2 cách để diễn giải biểu thức này, đó là 9 + (5 * 2) hoặc ( 9 + 5) *

2 Tính kết hợp của phép + và * không giải quyết được sự mơ hồ này, vì vậy cần phải quy định một thứ tự ưu tiên giữa các loại toán tử khác nhau

Thông thường trong toán học, các toán tử * và / có độ ưu tiên cao hơn + và -

factor digit | (expr)

Phép nhân và chia có thứ tự ưu tiên cao hơn đồng thời chúng kết hợp trái nên luật sinh cho term tương tự như cho list :

term term  * factor | term / factor | factor

Tương tự, ta có luật sinh cho expr :

expr expr + term | expr - term | term

Vậy, cuối cùng ta thu được văn phạm cho biểu thức như sau :

expr expr + term | expr - term | term

term term  * factor | term / factor | factor

factor digit | (expr)

Như vậy: Văn phạm này xem biểu thức như là một danh sách các term được phân cách

nhau bởi dấu + hoặc - Term là một list các factor phân cách nhau bởi * hoặc / Chú ý rằng

bất kỳ một biểu thức nào trong ngoặc đều là factor, vì thế với các dấu ngoặc chúng ta có thể xây dựng các biểu thức lồng sâu nhiều cấp tuỳ ý

Cú pháp các câu lệnh

Từ khóa (keyword) cho phép chúng ta nhận ra câu lệnh trong hầu hết các ngôn ngữ Ví

dụ trong Pascal, hầu hết các lệnh đều bắt đầu bởi một từ khóa ngoại trừ lệnh gán Một số lệnh Pascal được định nghĩa bởi văn phạm (nhập nhằng) sau, trong đó id chỉ một danh biểu (tên biến)

stmt  id := expr

Trang 19

| if expr then stmt

| if expr then stmt else stmt

| while expr do stmt

| begin opt_stmts end

Ký hiệu chưa kết thúc opt_stmts sinh ra một danh sách có thể rỗng các lệnh, phân cách nhau bởi dấu chấm phẩy (;)

Kí hiệu Ý nghĩa

::=, hoặc , hoặc = được định nghĩa là

{ } chuỗi của 0 hoặc nhiều mục liệt kê tùy chọn

[ ] hoặc 0 hoặc 1 mục liệt kê tùy chọn

< > mục liệt kê phải được thay thế

| hoặc (theo nghĩa loịa trừ)

Các quy tắc BNF định nghĩa tên trong Pascal:

<tên> ::= <chữ> { <chữ> | <số> }

<chữ> ::= ‘A’ | … | ‘Z’ | ‘a’ | … | ‘z’

<số> ::= ‘)’ | … | ‘9’

Ví dụ văn phạm của một ngôn ngữ lập trình đơn giản dang BNF như sau:

<program> ::= program <statement> end

<statement> ::= <identifier> := <expression>;

<loop> ::= while <expression> do <statement> done

<expression> ::=

<value> | <value> + <value> | <value> <= <value>

<value> ::= <identifier> | <number>

<identifier> ::=

<letter> | <identifier><letter> | <identifier><digit>

<number>::= <digit> | <number><digit>

<letter> ::= ‘A’ | … | ‘Z’ | ‘a’ | … | ‘z’

Trang 20

1 Phân tích cú pháp

Một ngôn ngữ lập trình, như trình bày ở phần trên, được thường định nghĩa bởi cú pháp hayvăn phạm của nó bởi dạng chuẩn BNF Sau đó, khi người lập trình sử dụng ngôn ngữ đểviết chương trình, người lập trình phải tuân theo văn phạm đã được định nghĩa Để kiểm traxem một chương trình có đúng cú pháp hay không thì cần phải thực hiện phân tích cú pháp.Phân tích cú pháp là quá trình xác định xem một xâu/câu có thể được sinh ra từ một vănphạm cho trước không Cụ thể, phân tích cú pháp của một chương trình là xác định xemtừng câu lệnh của chương trình có được sinh ra bởi cú pháp của ngôn ngữ lập trình đókhông

Trong phần này, chúng ta chỉ giới thiệu sơ bộ về quá trình phân tích cú pháp Vấn đề này sẽđược trình bày đầy đủ hơn trong bài cuối cùng của môn học

Có nhiều phương pháp phân tích cú pháp khác nhau Tuy nhiên, các phương pháp này đềunằm trong hai lớp: từ trên xuống (top down) và từ dưới lên (bttom-up)

Để xác định xem một chương trình nguồn có được sinh ra từ một văn phạm hay không, cácphương pháp phân tích cú pháp thường xây dựng cây phân tích của chương trình nguồndựa trên văn phạm Nếu tồn tại cây phân tích thì ta nói chương trình được sinh ra bởi vănphạm hay chương trình đúng cú pháp, ngược lại thì chương trình nguồn là không đúng cúpháp

Để xây dựng cây phân tích cho một chương trình nguồn, chúng ta có thể tiến hành hai cách

cơ bản tương ứng với hai lớp các phương pháp phân tích cú pháp Phương pháp phân tích

từ trên xuống sẽ bắt đầu xây dựng cây phân tích từ các lá đi đến đỉnh của một câu haychương trình cho trước Ngược lại, phương pháp phân tích từ dưới lên sẽ bắt đầu xây dựngcây phân tích từ đỉnh đến các lá của một câu hay chương trình cho trước

Đối với mỗi lớp phương pháp phân tích cú pháp, có nhiều phương pháp khác nhau:

- Phân tích cú pháp từ trên xuống gồm:

o Phân tích đệ quy đi xuống: phương pháp này thực hiện việc xây dựng câyphân tích từ gốc đến lá và có khả năng quay lui (backtracking)

o Phân tích cú pháp đoán nhận trước: phương này phân tích từ trên xuốngnhưng không bị quay lui

o Phân tích cú pháp đoán nhận trước không đệ quy: phương này sử dụng ngănxếp (stack) thay vì quay lui

- Phân tích cú pháp từ dưới lên gồm:

o Phân tích cú pháp thứ tự yếu

o Phân tích cú pháp LR

Dưới đây là một ví dụ đơn giản minh họa phân tích cú pháp Chúng có văn phạm G địnhnghĩa ngôn ngữ sau:

<exp>  <exp> + <term>

<exp>  <exp> - <term>

<exp>  <term>

<term>  0

Trang 21

<term>  9

Chương trình nguồn là biểu thức: 9 – 5 + 3

Thực hiện việc phân tích cú pháp sẽ tạo được cây phân tích như sau:

Như thế, chương trình nguồn 9 – 5 + 3 là đúng đắn về mặt cú pháp

4 Ngữ nghĩa hình thức

Căn cứ vào cú pháp của ngôn ngữ lập trình, người lập trình viết chương trình gồmcác câu lệnh theo trình tự cho phép để giải quyết bài toán đặt ra Để đạt được mục đích đó,mỗi câu lệnh viết ra không những chỉ đúng đắn về mặt cú pháp mà còn phải đúng đắn vềmặt ngữ nhĩa (semantic) hay ý nghĩa logic câu lệnh Tính đúng đắn về mặt ngữ nghĩa chophép giải quyết được bài toán, chương trình chạy luôn dừng, ổn định và cho kết quả phùhợp với yêu cầu đặt ra

Ngữ nghĩa không chỉ là cơ sở cho việc chứng minh tính đúng đắn của chương trình mà còn

có ích cho quá trình thiết kế và cài đặt ngôn ngữ lập trình

Trong bài học này sẽ giới thiệu hai loại ngữ nghĩa hình thức: ngữ nghĩa tiên đề (axiomaticsemantics) và ngữ nghĩa biểu thị (denotationnal semantics)

5 Ngữ nghĩa tiên đề Ngữ nghĩa của phát biểu

Ngữ nghĩa của phát biểu đượcđặc tả bởi biểu thức sau:

{ P } S { Q }trong đó P là điều kiện về trị các biến trước khi thực thi S, gọi là điều kiện trước(precondition) của S; Q là điều kiện về trị các biến sau khi thực thi S, gọi là hậu điều kiện(postcondition) của S

Diễn dịch đặc tả trên: nếu P đúng thì sau khi S được thực hiện xong ta có Q đúng

Nếu với điều kiện sau bất kỳ của S, ta biết được những điều kiện trước sao cho khi S đượcthực hiện xong điều kiện sau trên được thỏa mãn, thì ta nói biết được ngữ nghĩa của S.Điều kiện P2 gọi là yếu hơn P1 nếu P1  P2 Điều kiện trước ở đặc tả của phát biểu càngyếu, ngữ nghĩa của phát biểu càng rõ Với điều kiện sau Q của S, chúng ta kí hiệu p (S, Q)

là điều kiện trước yếu nhất bảo đảm Q đúng sau khi được thực hiện xong Hàm p (S, Q)với Q là biến số có thể xem là ngữ nghĩa chính xác của S

Ví dụ: p (n := n +1, n > 0) = n  0 (n nguyên)

Trang 22

Với mọi điều kiện trước P về n thỏa mãn đặc tả:

Luật L3 cho chúng ta điều phải chứng minh

Luật L4: (luật về câu lệnh ghép)

Nếu ({P} S1 {Q})  ({Q} S2 {R})thì {P} S1 ; S2 {R}

Ví dụ 4.8, chứng minh tính đúng đắn của đặc tả:

{f = i!} i := i + 1; f = f * i {f = i!}

Theo ví dụ 4.6 và 4.7chúng ta có:

{ f = i!} i := i +1 {f * i = i!}  { f * i = i!} f := f * i {f = i!}

Áp dụng L4 cho chúng ta điều phải chứng minh

Trang 23

Luật L5: (luật về phát biểu IF)

Vì (x.y < 0)  (x > y)  x > 0 nên theo L2 ta có:

{(x.y < 0)  (x > y)} max := x {max > 0} (*)Tương tự theo L3 và L2 ta có:

{(x.y < 0)  (x  y)} max := y {max > 0} (**)

Luật L7: (luật về vòng lặp WHILE)

{f = i!} i = i +1; f := f*i {f = i!}

Vì (f = i!)  (i  n)  f = i! Nên theo L2 ta có:

{(f = i!)  (i  n)} i = i +1; f := f*i {f = i!}

Trang 24

nên theo L1 chúng ta suy ra được điều phải chứng minh.

5 Ngữ nghĩa biểu thị

Ở ngữ nghĩa biểu thị, ngữ nghĩa của mỗi cấu trúc cú pháp được đặc tả bằng một ánh

xạ, gọi là hàm ngữ nghĩa (semantic function), từ miền cú pháp (semantic domain) vào miềnngữ nghĩa (semantic domain)

Như thế, chúng ta nhận thấy, ngữ nghĩa biểu thị chỉ ra ngữ nghĩa của mỗi cấu trúc cú pháp,tưca là mỗi cấu trúc cú pháp có một ngữ nghĩa nhất định

Chúng ta sẽ lấy một ví dụ đơn giản: mô tả hình thức ngữ nghĩa của ngôn ngữ gồmcác số nhị phân bằng ngữ nghĩa biểu thị

Ngôn ngữ số nhị phân là ngôn ngữ chỉ gồm các số nhị phân ‘0’ và ‘1’ Ngữ nghĩa củacủa số nhị phân chính là giá trị thập phân của số nhị phân đó Như thế, miền cú pháp là tậphợp các số nhị phân, còn miền ngữ nghĩa là tập hợp các số tự nhiên (giá trị của các số nhịphân)

Cú pháp và ngữ nghĩa của ngôn ngữ số nhị phân được định nghĩa như sau:

Cú pháp:

N  Nml số nhị phân

N ::= 0 | 1 | N0 | N1Miền ngữ nghĩa:

N = {0, 1, 2, } số tự nhiênHàm ngữ nghĩa:

Bài tập:

Câu 1: Trình bày định nghĩa cú pháp

Câu 2:Hãy nêu các vấn đề cú pháp

Câu 3: Hãy nêu các phương pháp phân tích cú pháp

Câu 4: Hãy nêu các loại ngữ nghĩa hình thức

Trang 25

Bài 5 ĐẶC TRƯNG LẬP TRÌNH CÂU LỆNH (LẬP TRÌNH THỦ TỤC)

MÃ BÀI ITPRG3_06.5Học xong bài này học viên sẽ có khả năng:

5.1.1 Biến

Biến là một ÐTDL được người lập trình định nghĩa và đặt tên một cách tường minhtrong chương trình Giá trị của biến có thể bị thay đổi trong thời gian tồn tại của nó Tên biếnđược dùng để xác định và tham khảo tới biến Trong các NNLT, tên biến thường được quyđịnh dưới dạng một dãy các chữ cái, dấu gạch dưới và các chữ số, bắt đầu bằng một chữcái và có chiều dài hữu hạn

5.1.2 Hằng

Hằng là một ÐTDL có tên và giá trị của hằng không thay đổi trong thời gian tồn tạicủa nó Hằng trực kiện (literal constant) là một hằng mà tên của nó là sự mô tả giá trị của nó(chẳng hạn "27" là sự mô tả số thập phân của ÐTDL giá trị 27) Chú ý sự khác biệt giữa 2giá trị 27 Một cái là một số nguyên được biểu diễn thành một dãy các bit trong bộ nhớ trongquá trình thực hiện chương trình và cái tên "27" là một chuỗi 2 ký tự "2" và "7" mô tả một sốnguyên như nó được viết trong chương trình

5.2 Lập trình cấu trúc

Lệnh đơn là một sự tính toán được kết thúc bằng dấu chấm phẩy Các định nghĩa

biến và các biểu thức được kết thúc bằng dấu chấm phẩy như trong ví dụ sau:

int i; // lệnh khai báo

++i; // lệnh này có một tác động chính yếu

double d = 10.5; // lệnh khai báo

Trang 26

Nhiều lệnh đơn có thể kết nối lại thành một lệnh phức bằng cách rào chúng bên

trong các dấu ngoặc xoắn Ví dụ:

{ int min, i = 10, j = 20;

min = (i < j ? i : j);

cout << min << '\n';

}

Bởi vì một lệnh phức có thể chứa các định nghĩa biến và định nghĩa một phạm vi cho

chúng, nó cũng được gọi một khối Phạm vi của một biến C++ được giới hạn bên trong khối

trực tiếp chứa nó Các khối và các luật phạm vi sẽ được mô tả chi tiết hơn khi chúng ta thảoluận về hàm trong chương kế

3.2 Lệnh if

Đôi khi chúng ta muốn làm cho sự thực thi một lệnh phụ thuộc vào một điều kiện nào

đó cần được thỏa Lệnh if cung cấp cách để thực hiện công việc này, hình thức chung củalệnh này là:

average = sum / count;

Để làm cho nhiều lệnh phụ thuộc trên cùng điều kiện chúng ta có thể sử dụng lệnhphức:

balance += interest;

} else {

Trang 27

interest = balance * debitRate;

else interest = balance * debitRate;

balance += interest;

Hoặc đơn giản hơn bằng việc sử dụng biểu thức điều kiện:

interest = balance * (balance > 0 ? creditRate : debitRate);

balance += interest;

Hoặc chỉ là:

balance += balance * (balance > 0 ? creditRate : debitRate);

Các lệnh if có thể được lồng nhau bằng cách để cho một lệnh if xuất hiện bên trongmột lệnh if khác Ví dụ:

if (callHour > 6) {

if (callDuration <= 5) charge = callDuration * tarrif1;

else charge = 5 * tarrif1 + (callDuration - 5) * tarrif2;

} else charge = flatFee;

Một hình thức được sử dụng thường xuyên của những lệnh if lồng nhau liên quanđến phần else gồm có một lệnh if-else khác Ví dụ:

if (ch >= '0' && ch <= '9') kind = digit;

else {

if (ch >= 'A' && ch <= 'Z') kind = upperLetter;

else {

if (ch >= 'a' && ch <= 'z') kind = lowerLetter;

else kind = special;

} }

Để cho dễ đọc có thể sử dụng hình thức sau:

if (ch >= '0' && ch <= '9') kind = digit;

Trang 28

else if (ch >= 'A' && ch <= 'Z') kind = capitalLetter;

else if (ch >= 'a' && ch <= 'z') kind = smallLetter;

else kind = special;

Ví dụ, chúng ta phải phân tích cú pháp một phép toán toán học nhị hạng thành bathành phần của nó và phải lưu trữ chúng vào các biến operator , operand1 , và operand2 Lệnh switch sau thực hiện phép toán và lưu trữ kết quả vào result

Trang 29

Như đã được minh họa trong ví dụ, chúng ta cần thiết chèn một lệnh break ở cuốimỗi case Lệnh break ngắt câu lệnh switch bằng cách nhảy đến điểm kết thúc của lệnh này.

Ví dụ, nếu chúng ta mở rộng lệnh trên để cho phép x cũng có thể được sử dụng như là toán

tử nhân, chúng ta sẽ có:

switch (operator) { case '+': result = operand1 + operand2;

Chúng ta có thể quan sát rằng bất kỳ lệnh switch nào cũng có thể được viết nhưnhiều câu lệnh if-else Ví dụ, lệnh trên có thể được viết như sau:

if (operator == '+') result = operand1 + operand2;

else if (operator == '-') result = operand1 - operand2;

else if (operator == 'x' || operator == '*') result = operand1 * operand2;

else if (operator == '/') result = operand1 / operand2;

else cout << "unknown operator: " << ch << '\n';

Người ta có thể cho rằng phiên bản switch là rõ ràng hơn trong trường hợp này Tiếpcận if-else nên được dành riêng cho tình huống mà trong đó switch không thể làm đượccông việc (ví dụ, khi các điều kiện là phức tạp không thể đơn giản thành các đẳng thức toánhọc hay khi các nhãn cho các case không là các hằng số)

Trang 30

khác 0 thì sau đó lệnh (cũng được gọi là thân vòng lặp) được thực hiện và toàn bộ quá trìnhđược lặp lại Ngược lại, vòng lặp được kết thúc

Ví dụ, chúng ta muốn tính tổng của tất cả các số nguyên từ 1 tới n Điều này có thểđược diễn giải như sau:

Bảng 3.1 Vết của vòng lặp while

Vòng lặp i n i <= n sum += i++

Một 1 5 1 1 Hai 2 5 1 3

Ba 3 5 1 6 Bốn 4 5 1 10 Năm 5 5 1 15

Đôi khi chúng ta có thể gặp vòng lặp while có thân rỗng (nghĩa là một câu lệnh null)

Ví dụ vòng lặp sau đặt n tới thừa số lẻ lớn nhất của nó

while (n % 2 == 0 && n /= 2) ;

Ở đây điều kiện lặp cung cấp tất cả các tính toán cần thiết vì thế không thật sự cần mộtthân cho vòng lặp Điều kiện vòng lặp không những kiểm tra n là chẵn hay không mà nó cònchia n cho 2 và chắc chắn rằng vòng lặp sẽ dừng

3.5 Lệnh do - while

Lệnh do (cũng được gọi là vòng lặp do) thì tương tự như lệnh while ngoại trừ thân của

nó được thực thi trước tiên và sau đó điều kiện vòng lặp mới được kiểm tra Hình thứcchung của lệnh do là:

do {

Trang 31

3.6 Lệnh for

Lệnh for (cũng được gọi là vòng lặp for) thì tương tự như vòng lặp while nhưng có haithành phần thêm vào: một biểu thức được ước lượng chỉ một lần trước hết và một biểu thứcđược ước lượng mỗi lần ở cuối mỗi lần lặp Hình thức tổng quát của lệnh for là:

for ( biểu thức1; biểu thức2; biểu thức3)

sum = 0;

for (i = 1; i <= n; ++i) sum += i;

Điều này được ưa chuộng hơn phiên bản của vòng lặp while mà chúng ta thấy trước

đó Trong ví dụ này i thường được gọi là biến lặp

C++ cho phép biểu thức đầu tiên trong vòng lặp for là một định nghĩa biến Ví dụtrong vòng lặp trên thì i có thể được định nghĩa bên trong vòng lặp:

for (int i = 1; i <= n; ++i) sum += i;

Trái với sự xuất hiện, phạm vi của i không ở trong thân của vòng lặp mà là chínhvòng lặp Xét trên phạm vi thì ở trên tương đương với:

int i;

for (i = 1; i <= n; ++i) sum += i;

Bất kỳ biểu thức nào trong 3 biểu thức của vòng lặp for có thể rỗng Ví dụ, xóa biểuthức đầu và biểu thức cuối cho chúng ta dạng giống như vòng lặp while:

for (; i != 0;) // tương đương với: while (i != 0)

Trang 32

something; // something;

Xóa tất cả các biểu thức cho chúng ta một vòng lặp vô hạn Điều kiện của vòng lặpnày được giả sử luôn luôn là đúng

for (;;) // vòng lặp vô hạn something;

Trường hợp vòng lặp với nhiều biến lặp thì hiếm dùng Trong những trường hợp nhưthế, toán tử phẩy (,) được sử dụng để phân cách các biểu thức của chúng:

for (i = 0, j = 0; i + j < n; ++i, ++j) something;

Bởi vì các vòng lặp là các lệnh nên chúng có thể xuất hiện bên trong các vònglặp khác Nói các khác, các vòng lặp có thể lồng nhau Ví dụ,

for (int i = 1; i <= 3; ++i) for (int j = 1; j <= 3; ++j) cout << '(' << i << ',' << j << ")\n";

cho tích số của tập hợp {1,2,3} với chính nó, kết quả như sau:

(1,1) (1,2) (1,3) (2,1) (2,2) (2,3) (3,1) (3,2) (3,3)

do { cin >> num;

if (num < 0) continue;

// xử lý số ở đây … } while (num != 0);

Điều này tương đương với:

do { cin >> num;

if (num >= 0) {

Trang 33

// xử lý số ở đây … }

} while (num != 0);

Một biến thể của vòng lặp này để đọc chính xác một số n lần (hơn là cho tới khi số đó

là 0) có thể được diễn giải như sau:

for (i = 0; i < n; ++i) { cin >> num;

if (num < 0) continue; // làm cho nhảy tới: ++i // xử lý số ở đây …

} Khi lệnh continue xuất hiện bên trong vòng lặp được lồng vào thì nó áp dụng trực tiếplên vòng lặp gần nó chứ không áp dụng cho vòng lặp bên ngoài Ví dụ, trong một tập cácvòng lặp được lồng nhau sau đây, lệnh continue áp dụng cho vòng lặp for và không áp dụngcho vòng lặp while:

while (more) { for (i = 0; i < n; ++i) { cin >> num;

if (num < 0) continue; // làm cho nhảy tới: ++i // process num here

} //etc

}

3.8 Lệnh break

Lệnh break có thể xuất hiện bên trong vòng lặp (while, do, hay for) hoặc một lệnhswitch Nó gây ra bước nhảy ra bên ngoài những lệnh này và vì thế kết thúc chúng Giốngnhư lệnh continue, lệnh break chỉ áp dụng cho vòng lặp hoặc lệnh switch gần nó Sử dụnglệnh break bên ngoài vòng lặp hay lệnh switch là lỗi

Ví dụ, chúng ta đọc vào một mật khẩu người dùng nhưng không cho phép một số hữu hạnlần thử:

for (i = 0; i < attempts; ++i) { cout << "Please enter your password: ";

Trang 34

for (i = 0; i < attempts && !verified; ++i) { cout << "Please enter your password: ";

cin >> password;

verified = Verify(password));

if (!verified) cout << "Incorrect!\n";

} Người ta cho rằng phiên bản của break thì đơn giản hơn nên thường được ưa chuộnghơn

3.9 Lệnh goto

Lệnh goto cung cấp mức thấp nhất cho việc nhảy Nó có hình thức chung là: gotonhãn; trong đó nhãn là một định danh được dùng để đánh dấu đích cần nhảy tới Nhãn cầnđược theo sau bởi một dấu hai chấm (:) và xuất hiện trước một lệnh bên trong hàm nhưchính lệnh goto

Ví dụ, vai trò của lệnh break trong vòng lặp for trong phần trước có thể viết lại bởi một lệnhgoto

for (i = 0; i < attempts; ++i) { cout << "Please enter your password: ";

//etc

Bởi vì lệnh goto cung cấp một hình thức nhảy tự do không có cấu trúc (không giốngnhư lệnh break và continue) nên dễ làm gãy đổ chương trình Phần lớn các lập trình viênngày nay tránh sử dụng nó để làm cho chương trình rõ ràng Tuy nhiên, goto có một vài (dùcho hiếm) sử dụng chính đáng Vì sự phức tạp của những trường hợp như thế mà việc cungcấp những ví dụ được trình bày ở những phần sau

Trang 35

int main (void) {

cout << "Hello World\n";

return 0;

} Khi một hàm có giá trị trả về không là void (như trong ví dụ trên), nếu không trả vềmột giá trị sẽ mang lại một cảnh báo trình biên dịch Giá trị trả về thực sự sẽ không đượcđịnh nghĩa trong trường hợp này (nghĩa là, nó sẽ là bất cứ giá trị nào được giữ trong vị trí bộnhớ tương ứng của nó tại thời điểm đó)

Bài tập

3.1 Viết chương trình nhập vào chiều cao (theo centimet) và trọng lượng (theo kilogram) của

một người và xuất một trong những thông điệp: underweight , normal , hoặcoverweight , sử dụng điều kiện:

Underweight: weight < height/2.5

Normal: height/2.5 <= weight <= height/2.3

Overweight: height/2.3 < weight

3.2 Giả sử rằng n là 20, đoạn mã sau sẽ xuất ra cái gì khi nó được thực thi?

if (n >= 0)

if (n < 10) cout << "n is small\n";

else cout << "n is negative\n";

3.3 Viết chương trình nhập một ngày theo định dạng dd/mm/yy và xuất nó theo định dạng

3.5 Viết chương trình nhập vào một số cơ số 8 và xuất ra số thập phân tương đương Ví dụ

sau minh họa các công việc thực hiện của chương trình theo mong đợi:

Nhap vao so bat phan: 214 BatPhan(214) = ThapPhan(140) 3.6 Viết chương trình cung cấp một bảng cửu chương đơn giản của định dạng sau cho các

số nguyên từ 1 tới 9:

1 x 1 = 1

1 x 2 = 2

9 x 9 =

Trang 36

BÀI 6 LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG

MÃ BÀI ITPRG3_06.5

6.1 Giới thiệu

Hướng đối tượng (object orientation) cung cấp một kiểu mới để xây dựng phần mềm.Trong kiểu mới này, các đối tượng (object) và các lớp (class) là những khối xây dựng trongkhi các phương thức (method), thông điệp (message), và sự thừa kế (inheritance) cung cấpcác cơ chế chủ yếu

Lập trình hướng đối tượng (OOP- Object-Oriented Programming) là một cách tư

duy mới, tiếp cận hướng đối tượng để giải quyết vấn đề bằng máy tính Thuật ngữ OOPngày càng trở nên thông dụng trong lĩnh vực công nghệ thông tin

Nếu bạn chưa bao giờ sử dụng một ngôn ngữ OOP thì trước tiên bạn nên nắm vữngcác khái niệm của OOP hơn là viết các chương trình Bạn cần hiểu được đối tượng (object)

là gì, lớp (class) là gì, chúng có quan hệ với nhau như thế nào, và làm thế nào để các đốitượng trao đổi thông điệp (message) với nhau, vâng vâng

OOP là tập hợp các kỹ thuật quan trọng mà có thể dùng để làm cho việc triển khaichương trình hiệu quả hơn Quá trình tiến hóa của OOP như sau:

􀂃Lập trình tuyến tính

􀂃Lập trình có cấu trúc

􀂃Sự trừu tượng hóa dữ liệu

􀂃Lập trình hướng đối tượng

Lập trình hướng đối tượng (OOP) là một phương pháp thiết kế và phát triển phần

mềm dựa trên kiến trúc lớp và đối tượng

Chương 6: Lập trình hướng đối tượng 76

6.2 Trừu tượng hóa (Abstraction)

Trừu tượng hóa là một kỹ thuật chỉ trình bày những các đặc điểm cần thiết của vấn

đề mà không trình bày những chi tiết cụ thể hay những lời giải thích phức tạp của vấn đề đó.Hay nói khác hơn nó là một kỹ thuật tập trung vào thứ cần thiết và phớt lờ đi những thứkhông cần thiết

Ví dụ những thông tin sau đây là các đặc tính gắn kết với con người:

Sự trừu tượng hóa đã không ngừng phát triển trong các ngôn ngữ lập trình, nhưngchỉ ở mức dữ liệu và thủ tục Trong OOP, việc này được nâng lên ở mức cao hơn – mức đối

Trang 37

tượng Sự trừu tượng hóa được phân thành sự trừu tượng hóa dữ liệu và trừu tượng hóachương trình

Khái niệm 6.2

6.3 Đối tượng (object)

Các đối tượng là chìa khóa để hiểu được kỹ thuật hướng đối tượng Bạn có thể nhìnxung quanh và thấy được nhiều đối tượng trong thế giới thực như: con chó, cái bàn, quyển

vở, cây viết, tivi, xe hơi Trong một hệ thống hướng đối tượng, mọi thứ đều là đối tượng.Một bảng tính, một ô trong bảng tính, một biểu đồ, một bảng báo cáo, một con số hay một sốđiện thoại, một tập tin, một thư mục, một máy in, một câu hoặc một từ, thậm chí một ký tự,tất cả chúng là những ví dụ của một đối tượng Rõ ràng chúng ta viết một chương trìnhhướng đối tượng cũng có nghĩa là chúng ta đang xây dựng một mô hình

Trừu tượng hóa dữ liệu (data abstraction) là tiến trình xác định và nhóm các thuộctính và các hành động liên quan đến một thực thể đặc thù trong ứng dụng đang phát triển

Trừu tượng hóa chương trình (program abstraction) là một sự trừu tượng hóa dữ liệu

mà làm cho các dịch vụ thay đổi theo dữ liệu

của một vài bộ phận trong thế giới thực Tuy nhiên các đối tượng này có thể đượcbiểu diễn hay mô hình trên máy tính

Một đối tượng thế giới thực là một thực thể cụ thể mà thông thường bạn có thể sờ,nhìn thấy hay cảm nhận được Tất cả các đối tượng trong thế giới thực đều có trạng thái(state) và hành động (behaviour) Ví dụ:

Trạng thái Hành động

Con chó

􀂃 Tên

􀂃 Màu

􀂃 Giống

􀂃 Vui sướng

􀂃 Bàn đạp

􀂃 Dây xích

􀂃 Bánh xe

􀂃 Tăng tốc

􀂃 Giảm tốc

􀂃 Chuyển bánh răng

Hình 6.1 Ví dụ về trạng thái và hành động

Trang 38

Các đối tượng phần mềm (software object) có thể được dùng để biểu diễn cácđối tượng thế giới thực Chúng được mô hình sau khi các đối tượng thế giới thực có cảtrạng thái và hành động Giống như các đối tượng thế giới thực, các đối tượng phần mềmcũng có thể có trạng thái và hành động Một đối tượng phần mềm có biến (variable) haytrạng thái (state) mà thường được gọi là thuộc tính (attribute; property) để duy trì trạng tháicủa nó và phương thức (method) để thực hiện các hành động của nó Thuộc tính là mộthạng mục dữ liệu được đặt tên bởi một định danh (identifier) trong khi phương thức là mộtchức năng được kết hợp với đối tượng chứa nó

OOP thường sử dụng hai thuật ngữ mà sau này Java cũng sử dụng là thuộc tính (attribute)

và phương thức (method) để đặc tả tương ứng cho trạng thái (state) hay biến (variable) vàhành động (behavior) Tuy nhiên C++ lại sử dụng hai thuật ngữ dữ liệu thành viên (memberdata) và hàm thành viên (member function) thay cho các thuật ngữ này

Xét một cách đặc biệt, chỉ một đối tượng riêng rẽ thì chính nó không hữu dụng Một chươngtrình hướng đối tượng thường gồm có hai hay nhiều hơn các đối tượng phần mềm tươngtác lẫn nhau như là sự tương tác của các đối tượng trong trong thế giới thực

xe đạp sẽ có các thuộc tính để xác định các trạng thái của chiếc xe đạp như: tốc độ của nó

là 10 km trên giờ, nhịp bàn đạp là 90 vòng trên phút, và bánh răng hiện tại là bánh răng thứ

5 Các thuộc tính này thông thường được xem như thuộc tính thể hiện (instance attribute)bởi vì chúng chứa đựng các trạng thái cho một đối tượng xe đạp cụ thể Trong kỹ thuậthướng đối tượng thì một đối tượng cụ thể được gọi là một thể hiện (instance)

Khái niệm 6.4

Hình 6.2 minh họa một xe đạp được mô hình như một đối tượng phần mềm:

Đối tượng xe đạp phần mềm cũng có các phương thức để thắng lại, tăng nhịp đạphay là chuyển đổi bánh răng Nó không có phương thức để thay đổi tốc độ vì tốc độ của xeđạp có thể tình ra từ hai yếu tố số vòng quay và bánh răng hiện tại Những phương thức nàythông thường được biết như là các phương thước thể hiện (instance method) bởi vì chúngtác động hay thay đổi trạng thái của một đối tượng cụ thể

Một đối tượng cụ thể được gọi là một thể hiện (instance)

6.4 Lớp (Class)

Trong thế giới thực thông thường có nhiều loại đối tượng cùng loại Chẳng hạn chiếc

xe đạp của bạn chỉ là một trong hàng tỉ chiếc xe đạp trên thế giới Tương tự, trong mộtchương trình hướng đối tượng có thể có nhiều đối tượng cùng loại và chia sẻ những đặcđiểm chung Sử dụng thuật ngữ hướng đối tượng, chúng ta có thể nói rằng chiếc xe đạp củabạn là một thể hiện của lớp xe đạp Các xe đạp có một vài trạng thái chung (bánh răng hiện

Trang 39

tại, số vòng quay hiện tại, hai bánh xe) và các hành động (chuyển bánh răng, giảm tốc) Tuynhiên, trạng thái của mỗi xe đạp là độc lập và có thể khác với các trạng thái của các xe đạpkhác Trước khi tạo ra các xe đạp, các nhà sản xuất thường thiết lập một bảng thiết kế(blueprint) mô tả các đặc điểm và các yếu tố cơ bản của xe đạp Sau đó hàng loạt xe đạp sẽđược tạo ra từ bản thiết kế này Không hiệu quả nếu như tạo ra một bản thiết kế mới chomỗi xe đạp được sản xuất

Trong phần mềm hướng đối tượng cũng có thể có nhiều đối tượng cùng loại chia sẻnhững đặc điểm chung như là: các hình chữ nhật, các mẫu tin nhân viên, các đoạn phim, …Giống như là các nhà sản xuất xe đạp, bạn có thể tạo ra một bảng thiết kế cho các đốitượng này Một bảng thiết kế phần mềm cho các đối tượng được gọi là lớp (class)

Khái niệm 6.5

Trở lại ví dụ về xe đạp chúng ta thấy rằng một lớp Xedap là một bảng thiết kế chohàng loạt các đối tượng xe đạp được tạo ra Mỗi đối tượng xe đạp là một thể hiện của lớpXedap và trạng thái của nó có thể khác với các đối tượng xe đạp khác Ví dụ một xe đạphiện tại có thể là ở bánh răng thứ 5 trong khi một chiếc khác có thể là ở bánh răng thứ 3

Lớp Xedap sẽ khai báo các thuộc tính thể hiện cần thiết để chứa đựng bánh rănghiện tại, số vòng quay hiện tại, cho mỗi đối tượng xe đạp Lớp Xedap cũng khai báo vàcung cấp những thi công cho các phương thức thể hiện để cho phép người đi xe đạpchuyển đổi bánh răng, phanh lại, chuyển đổi số vòng quay, như Hình 6.3

Lớp (class) là một thiết kế (blueprint) hay một mẫu ban đầu (prototype) định nghĩa cácthuộc tính và các phương thức chung cho tất cả các đối tượng của cùng một loại nào đó Một đối tượng là một thể hiện cụ thể của một lớp

Sau khi bạn đã tạo ra lớp xe đạp, bạn có thể tạo ra bất kỳ đối tượng xe đạp nào từlớp này Khi bạn tạo ra một thể hiện của lớp, hệ thống cấp phát đủ bộ nhớ cho đối tượng vàtất cả các thuộc tính thể hiện của nó Mỗi thể hiện sẽ có vùng nhớ riêng cho các thuộc tínhthể hiện của nó Hình 6.4 minh họa hai đối tượng xe đạp khác nhau được tạo ra từ cùng lớpXedap:

Ngoài các thuộc tính thể hiện, các lớp có thể định nghĩa các thuộc tính lớp (classattribute) Một thuộc tính lớp chứa đựng các thông tin mà được chia sẻ bởi tất cả các thểhiện của lớp Ví dụ, tất cả xe đạp có cùng số lượng bánh răng Trong trường hợp này, địnhnghĩa một thuộc tính thể hiện để giữ số lượng bánh răng là không hiệu quả bởi vì tất cả cácvùng nhớ của các thuộc tính thể hiện này đều giữ cùng một giá trị Trong những trường hợpnhư thế bạn có thể định nghĩa một thuộc tính lớp để chứa đựng số lượng bánh răng của xeđạp.Tất cả các thể hiện của lớp Xedap sẽ chia thuộc tính này Một lớp cũng có thể khai báocác phương thức lớp (class methods) Bạn có thể triệu gọi một phương thức lớp trực tiếp từlớp nhưng ngược lại bạn phải triệu gọi các phương thức thể hiện từ một thể hiện cụ thể nàođó

6.5 Thuộc tính (Attribute)

Các thuộc tính trình bày trạng thái của đối tượng Các thuộc tính nắm giữ các giá trị

dữ liệu trong một đối tượng, chúng định nghĩa một đối tượng đặc thù

Trang 40

Khái niệm 6.7

Một thuộc tính có thể được gán một giá trị chỉ sau khi một đối tượng dựa trên lớp ấyđược tạo ra Một khi các thuộc tính được gán giá trị chúng mô tả một đối tượng Mọi đốitượng của một lớp phải có cùng các thuộc tính nhưng giá trị của các thuộc tính thì có thểkhác nhau Một thuộc tính của đối tượng có thể nhận các giá trị khác nhau tại những thờiđiểm khác nhau

Thuộc tính lớp(class attribute) là một hạng mục dữ liệu liên kết với một lớp cụ thể mà không liên kết với các thể hiện của lớp Nó được định nghĩa bên trong định nghĩa lớp và được chia sẻ bởi tất cả các thể hiện của lớp

Phương thức lớp (class method) là một phương thức được triệu gọi mà không tham khảo tới bất kỳ một đối tượng nào Tất cả các phương thức lớp ảnh hưởng đến toàn bộ lớp chứ không ảnh hưởng đến một lớp riêng rẽ nào

Thuộc tính (attribute) là dữ liệu trình bày các đặc điểm về một đối tượng

Chương 6: Lập trình hướng đối tượng 82 6.6 Phương thức (Method)

Các phương thức thực thi các hoạt động của đối tượng Các phương thức là nhân tốlàm thay đổi các thuộc tính của đối tượng

Khái niệm 6.8

Các phương thức xác định cách thức hoạt động của một đối tượng và được thực thikhi đối tượng cụ thể được tạo ra.Ví dụ, các hoạt động chung của một đối tượng thuộc lớpChó là sủa, vẫy tai, chạy, và ăn Tuy nhiên, chỉ khi một đối tượng cụ thể thuộc lớp Chó đượctạo ra thì các phương thức sủa, vẫy tai, chạy, và ăn mới được thực thi

Các phương thức mang lại một cách nhìn khác về đối tượng Khi bạn nhìn vào đốitượng Cửa ra vào bên trong môi trường của bạn (môi trường thế giới thực), một cách đơngiản bạn có thể thấy nó là một đối tượng bất động không có khả năng suy nghỉ Trong tiếpcận hướng đối tượng cho phát triển hệ thống, Cửa ra vào có thể được liên kết tới phươngthức được giả sử là có thể được thực hiện Ví dụ, Cửa ra vào có thể mở, nó có thể đóng, nó

có thể khóa, hoặc nó có thể mở khóa Tất cả các phương thức này gắn kết với đối tượngCửa ra vào và được thực hiện bởi Cửa ra vào chứ không phải một đối tượng nào khác

6.7 Thông điệp (Message)

Một chương trình hay ứng dụng lớn thường chứa nhiều đối tượng khác nhau Cácđối tượng phần mềm tương tác và giao tiếp với nhau bằng cách gởi các thông điệp(message) Khi đối tượng A muốn đối tượng B thực hiện các phương thức của đối tượng Bthì đối tượng A gởi một thông điệp tới đối tượng B

Ví dụ đối tượng người đi xe đạp muốn đối tượng xe đạp thực hiện phương thứcchuyển đổi bánh răng của nó thì đối tượng người đi xe đạp cần phải gởi một thông điệp tớiđối tượng xe đạp

Đôi khi đối tượng nhận cần thông tin nhiều hơn để biết chính xác thực hiện công việc

gì Ví dụ khi bạn chuyển bánh răng trên chiếc xe đạp của bạn thì bạn phải chỉ rõ bánh răng

Ngày đăng: 17/01/2022, 11:31

HÌNH ẢNH LIÊN QUAN

Hình 4.2 Hai cây phân tích cú pháp - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 4.2 Hai cây phân tích cú pháp (Trang 17)
Văn phạm cho các biểu thức số học có thể xây dựng từ bảng kết hợp và ưu tiên của các toán tử - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
n phạm cho các biểu thức số học có thể xây dựng từ bảng kết hợp và ưu tiên của các toán tử (Trang 18)
4. Ngữ nghĩa hình thức - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
4. Ngữ nghĩa hình thức (Trang 21)
Hình 6.1 Ví dụ về trạng thái và hành động - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 6.1 Ví dụ về trạng thái và hành động (Trang 37)
Hình 7.1 sau biểu diễn phân lớp các kiểu dữ liệu trong Prolog. - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 7.1 sau biểu diễn phân lớp các kiểu dữ liệu trong Prolog (Trang 45)
Hình 7.2.Ví dụ về cây gia hệannajerrry - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 7.2. Ví dụ về cây gia hệannajerrry (Trang 46)
Mô hình phân tích- tổng hợp của một trình biên dịch - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
h ình phân tích- tổng hợp của một trình biên dịch (Trang 66)
Hình 10.1 Mô hình phân tích- tổng hợp của một trình biên dịch - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 10.1 Mô hình phân tích- tổng hợp của một trình biên dịch (Trang 66)
Hình 10.2 Một quá trình biên dịch điển hình - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 10.2 Một quá trình biên dịch điển hình (Trang 67)
Ðể dễ hình dung, một trình biên dịch được chia thành các giai đoạn, mỗi giai đoạn chuyển chương trình nguồn từ một dạng biểu diễn này sang một dạng biểu diễn khác - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
d ễ hình dung, một trình biên dịch được chia thành các giai đoạn, mỗi giai đoạn chuyển chương trình nguồn từ một dạng biểu diễn này sang một dạng biểu diễn khác (Trang 67)
Hình 10.4 Minh họa quá trình phân tích cú pháp từ trên xuống - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 10.4 Minh họa quá trình phân tích cú pháp từ trên xuống (Trang 70)
Hình 10.5 Giao diện bộ phân tích từ vựng - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 10.5 Giao diện bộ phân tích từ vựng (Trang 73)
Hình 10.6 Bảng ký hiệuvà mảng để lưu các chuỗi - Giáo trình Lý thuyết ngôn ngữ lập trình (Nghề Lập trình máy tính): Phần 2 - Tổng cục dạy nghề
Hình 10.6 Bảng ký hiệuvà mảng để lưu các chuỗi (Trang 76)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm