Chương 5: Thực hiện chương trình con
Giảng viên: Ph.D Nguyễn Văn Hòa Khoa KT-CN-MT – ðH An Giang
1
ðịnh nghĩa
(cid:1) Trong NNLT, tác vụ gọi “call” và trả về (return) của chương trình con ñược gọi chung là liên kết chương trình con “subprogram linkage”
2
Nội dung chính của chương
(cid:1) Giới thiệu chung về ngữ nghĩa của Call và Return (cid:1) Thực hiện chương trình con ñơn giản (cid:1) Thực hiện chương trình con với biến cục bộ ñộng
Stack
(cid:1) Chương trình con lòng nhau (nested
Subprograms) (cid:1) Khối (Blocks) (cid:1) Cài ñặt phạm vi ñộng
3
Ngữ nghĩa của việc gọi (call) và trả về (return) (cid:1) Một số tác vụ cần thiết cho việc gọi chương trình
con (cid:2) Cơ chế truyền các tham số (truyền tham trị, truyền quy
chiếu, truyền kết quả, ...)
(cid:2) Các biến cục bộ là static hay not static (cid:2) Lưu lại trạng thái hiện hành (execution status) của
chương trình gọi CTC
(cid:2) Chuyển quyền ñiều khiển cho CTC (cid:2) Cung cấp các truy xuất ñến các biến không cục bộ
4
Thực hiện CTC ñơn giản: Call
(cid:1) Chương trình con ñơn giản “simple”
(cid:2) Không lòng nhau và các biến là tĩnh (static)
(cid:1) Các tác vụ có cần thiết
(cid:2) Lưu hiện trạng thực thị của chương trình gọi “caller” (cid:2) Thực hiện tiến trình truyền tham số (cid:2) Chuyển ñịa chỉ trả về cho chương trình con “callee” (cid:2) Chuyển quyền ñiều khiển cho chương trình con
“callee”
5
Thực hiện CTC ñơn giản: Return
(cid:1) Nếu sử dụng truyền trị-kết quả, thì di chuyển giá trị hiện hành của các tham số hình thức ñến từng tham số thực tương ứng
(cid:1) Nếu là hàm, di chuyển giá trị của hàm ñến vị trí
mà caller có thể lấy ñược
(cid:1) Phục hồi lại trạng thái thực thi của caller (cid:1) Trả quyền ñiều khiển lại cho caller
6
Thực hiện CTC ñơn giản: Parts
(cid:1) Có 2 phần phân biệt: phần code thực và phần noncode (biến cục bộ và dữ liệu có thể bị thay ñổi)
(cid:1) ðịnh dạng, hoặc layout, của phần noncode của một chương trình thực thi con ñược gọi là bản hoạt ñộng (activation)
(cid:1) Một thể hiện (instance) bản hoạt ñộng là mẫu cụ thể của bản hoạt ñộng (bao gồm dữ liệu hoạt ñộng của chương trình con)
7
Bản hoạt ñộng của chương trình con ñơn giản
8
Code và bản hoạt ñộng của chương trình với chương trình con ñơn giản
9
Cài ñặt CTC với biến cục bộ ñộng Stack
(cid:1) Bản hoạt ñộng phức tạp
(cid:2) Trình biên dịch phải sinh code ñể cấp phát và giải
phóng một cách tường minh cho các tham số cục bộ (cid:2) Phải hỗ trợ ñệ qui “recursion” (tạo ñồng thời nhiều thể
hiện bản hoạt ñộng của một chương trình con)
(cid:2) ðệ qui yêu cầu nhiều thể hiện của bản hoạt ñộng, mỗi thể hiện của bản hoạt ñộng tương ứng với 1 một lần gọi ñệ qui
(cid:2) Mỗi thể hiện cầu 1 bản copy các tham số hình thức,
các biến cục bộ cấp phát ñộng và ñịa chỉ trả về
10
Bản hoạt ñộng của NN với biến cục bộ ñộng Stack
11
Cài ñặt CTC với biến cục bộ ñộng Stack : Bản hoạt ñộng
(cid:1) ðịnh dạng của bản hoạt ñộng là tĩnh, nhưng kích
thước của nó có thể ñộng
(cid:1) Liên kết ñộng (dynamic link) trỏ ñến ñỉnh của bản
hoạt ñộng của caller
(cid:1) Bản hoạt ñộng ñược xác ñịnh ra một cách ñộng
khi gọi chương trình con
(cid:1) Run-time stack
12
Ví dụ: Hàm C
void sub(float total, int part) {
int list[5]; float sum; …
}
13
Ví dụ không ñệ qui
void fun1(int x) {
(cid:3) 2
int y; ... fun3(y);
} void fun2(float r) {
(cid:3) 1
int s, t; ... fun1(s);
Hàm main gọi fun2 Hàm fun2 gọi fun1
} void fun3(int q) { (cid:3) 3
...
Hàm fun1 gọi fun3
} void main() { float p; ... fun2(p);
}
14
Ví dụ không ñệ qui
15
Dynamic Chain và Local Offset
(cid:1) Tập hợp các dynamic links trong stack tại một thời ñiểm nào ñó ñược gọi là dynamic chain, hoặc call chain
(cid:1) Các biến cục bộ có thể ñược truy xuất thông qua các offset của nó trong bản hoạt ñộng. Offset này ñược gọi là local_offset
(cid:1) Local_offset của một biến cục bộ có thể ñược xác ñịnh bởi trình biên dịch ngay thời ñiểm dịch hoặc thời ñiểm thực thi
16
Ví dụ với ñệ qui
int factorial (int n) {
<-----------------------------1
if (n <= 1) return 1; else return (n * factorial(n - 1)); <-----------------------------2
} void main() { int value; value = factorial(3);
<-----------------------------3
}
17
Bản hoạt ñộng của factorial
18
19
20
Chương trình con lòng nhau
(cid:1) Vài NNLT với phạm vi tĩnh (e.g., Fortran 95,
Ada, JavaScript) dùng các biến cục bộ ñộng stack và cho phép các chương trình con lòng vào nhau (cid:1) Các biến bên trong các bản hoạt ñộng trong stack có thể ñược truy xuất một cách không cục bộ (cid:1) Hai bước ñể tham chiếu các biến không cục bộ:
(cid:2)
Tìm kiếm thể hiện bản hoạt ñộng tương ứng
(cid:2) Xác ñịnh offset của biến trong thể hiện ñó
21
ðịnh vị các tham chiếu không cục bộ
(cid:1) Tìm Offset: khá dễ dàng (cid:1) Tìm thể hiện bản hoạt ñộng tương ứng
(cid:2) ðể ñảm bảo có thể tham chiếu ñến các biến không cục bộ thì các biến này phải ñược cấp phát trong các thể hiện bản hoạt ñộng trong stack
22
Phạm vi tĩnh
(cid:1) Static chain là tập hợp các static links liên kết một
vài bản hoạt ñộng trong stack
(cid:1) Static chain là cách cài ñặt phổ biến trong các NNLT
hỗ trợ CTC lòng nhau
(cid:1) Liên kết tĩnh (static link) trong một thể hiện bản hoạt ñộng nào ñó của 1 CTC là 1 pointer trỏ ñến phần dưới cùng của thể hiện bản hoạt ñộng cha, liên kết này dùng ñể truy xuất các biến không cục bộ
(cid:1) Chuỗi tĩnh (static chain) của một thể hiện bản hoạt ñộng nào ñó ñều phải kết nối với thể hiện bản hoạt ñộng của CTC tổ tiên (ancestors)
23
VD chương trình Pascal
program MAIN_2;
var X : integer; procedure BIGSUB;
var A, B, C : integer; procedure SUB1;
var A, D : integer; begin { SUB1 } A := B + C; <-----------------------1 end; { SUB1 }
procedure SUB2(X : integer);
var B, E : integer; procedure SUB3;
var C, E : integer; begin { SUB3 } SUB1; E := B + A: <--------------------2 end; { SUB3 }
begin { SUB2 } SUB3; A := D + E; <-----------------------3 end; { SUB2 } begin { BIGSUB } SUB2(7); end; { BIGSUB }
begin BIGSUB; end; { MAIN_2 }
24
Stack ở vi trí 1
Thứ tự gọi các hàm như sau:
MAIN_2 calls BIGSUB BIGSUB calls SUB2 SUB2 calls SUB3 SUB3 calls SUB1
25
Khối (blocks) (cid:1) Khối là vùng hay phạm vi hoạt ñộng các biến do người
dùng chỉ ñịnh (cid:1) VD chương trình C
{int temp;
temp = list [upper]; list [upper] = list [lower]; list [lower] = temp
}
(cid:1) Thời gian tồn tại của temp trong VD trên bắt ñầu ngay
khi chương trình bắt ñầu tiến vào khối
(cid:1) Ưu ñiểm của việc dùng biến cục bộ như temp là biến temps không trở ngại nào nếu như có 1 biến khác cùng tên
26
Cài ñặt khối
(cid:1) Có hai cách:
(cid:2) Khối ñược xem như là các tham số của chương trình
con mà nó ñược gọi tại ngay vị trí của nó – Mỗi khối có 1 thể hiện bản hoạt ñộng, nó ñược tạo ra ngay
thời ñiểm khối ñược thực thi
(cid:2) Vì kích thước lưu trữ cho 1 khối có thể xác ñịnh
trong suốt thời gian thực hiện khối, kích thước này có thể ñược cấp phát sau các biến cục bộ trong bản hoạt ñộng
27
28
Cài ñặt phạm vi ñộng
(cid:1) Truy xuất sâu (deep access): Các tham chiếu
không cục bộ có thể ñược tìm thấy trong các bản hoạt ñộng hiện hữu trong các liên kết ñộng (dynamic chain)
(cid:1) Truy xuất cạn (shallow access): tập trung các biến
cục bộ vào một nơi (cid:2) Mỗi biến có 1 stack (cid:2) Central table xác ñịnh các biến và chương trình con
29
VD chương trình
void sub3(){ int x,z; x=u+z; …
} void sub2(){ int w,x; …
} void sub1(){ int v,w; …
} void main(){ int v,u; …
}
30
Minh họa Deep access
main gọi sub2
sub2 gọi sub1
sub1 gọi sub2
sub2 gọi sub3
31
Minh họa Shallow Access
main gọi sub1 (A)
sub1 gọi sub1
sub1 gọi sub2 (B)
sub2 gọi sub3 (C)
32

