Tải bản đầy đủ (.docx) (19 trang)

Names, binding, type checking and scopes

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.35 MB, 19 trang )

Chương 5 Names, Binding, Type Checking and Scopes
I. Giới thiệu :
• Các vấn đề cơ bản về ngữ nghĩa của biến
Ngôn ngữ mệnh lệnh là sự trừu tượng hóa của kiến trúc von
Neumann
Biến là sự trừu tượng hóa của các ô nhớ
Biến được đặt trương bởi nhiều thuộc tính, nhưng thuộc tính quan
trọng nhất là kiểu dữ liệu(data type)
• Để thiết kế một kiểu dữ liệu có một số vấn đề cần quan tâm
Phạm vi và thời gian sống của biến
Kiểm tra kiểu và khởi tạo giá trị ban đầu cho biến
Tương thích kiểu
• Tên
Là một chuỗi dùng để định danh một thực thể trong chương trình
Name :tên biến, nhãn chương trình, tên chương trình con, tên cấu
trúc, tên lớp
Các vấn đề khi đặt tên
 Chiều dài tối đa :nếu ngắn quá thì không diễn đạt được ý
nghĩa của biến
 Ví dụ : trong FORTRAN I: maximum 6
 FORTRAN 90 and ANSI C: maximum 31
 Ada and Java: no limit
 –C++: không xác định phù thuộc vào trình biên dịch
 Ký tự kết nối(_)
 Modula-2 and FORTRAN 77 don't allow
 –Others do
 Phân biệt hoa, thường
 Nếu ngôn ngữ có phân biệt tên hoa và tên thường sẽ
ảnh hưởng đến tính dễ đọc của ngôn ngữ
 Rất hay gặp lỗi vì nhập văn bản
 Ví dụ :c,c++,java phân biệt hoa thường,Ada ,vb basic


không phân biệt
 Từ đặt biệt :được dùng để làm cho chương trình dễ đọc hơn
 Từ khóa (keyword)là một từ chỉ có ý nghĩa đặt biệt khi
nằm trong một ngữ cảnh nào đó
 Từ dành riêng(reserved word) là từ đặt biệt mà người
dùng không thể dùng để đặt tên cho một đối tượng
 Tên được định nghĩa sẳn (predefined name) là một từ
dành riêng nhưng người dùng có thể định nghĩa lại
• Ví dụ nhưng lệnh printf,scanf là từ dành riêng để xuất
và nhập dữ liệu trong c trong thư viện stdio.h, nếu
1
trong chương trình không include thư viện này thì có
thể dùng printf và scanf làm tên biến
• Biến
Là sự trừu tượng hóa của ô nhớ
 Biến sẽ được liên kết với một tập các ô nhớ vật lý
 Thay thế một địa chỉ tuyệt đối bằng một tên
 Nếu chương trình không dùng biến để chỉ ô nhớ chưa dữ
liệu, thì phải dùng địa chỉ tuyệt đối để lưu dữ liệu, khi thực
hiện chương trình dữ liệu phải đươc đưa vào ô nhớ tuyệt đối
này, nhưng với tên biến thì chương trình sẽ truy cập dữ liệu
thông qua tên biến,khi chạy thì hệ thống mới cấp địa chỉ
tuyệt đối cho biến
Một biến có sáu thuộc tính quan trọng
 Name :
 Địa chỉ(L-value):là địa chỉ của vùng nhớ đã cấp phát cho
biến
 Ví dụ :cho lệnh a=a+5
hệ thống sẽ thực hiện như sau :
L-value(a)=R-value(a)+5

 Cùng một tên biến có thể có những địa chỉ khác nhau
tại những vị trí khác nhau trong chương trình
• ví dụ : biến cục bộ :hai biến có tên giống nhau
có thể được khai báo trong hai chương trình
con khác nhau
 Một biến có thể có những địa chỉ khác nhau trong
từng thời điểm khác nhau của chương trình
• Ví dụ gọi đệ qui một chương trình con A, trong
chương trình con này có khai báo biến cục bộ
I,tại mỗi thời điểm gọi đệ qui biến I được cấp
phát những địa chỉ khác nhau
 Có thể có hai hoặc nhiều biến cùng truy cập đến một
địa chỉ vùng nhớ gọi là đa danh(aliases)
• Ảnh hưởng đến tính dễ đọc
• Khó Kiểm soát chương trình
• Ví dụ
2

 Kiểu dữ liệu(Type):bao gồm 2 thành phần
 Miền giá trị
 Các toán tử được định nghĩa trên kiểu dữ liệu đó
3
 Nếu kiểu dấu chấm động :kiểu cũng xác định độ
chính xác
 Giá trị (RValue):giá trị của vùng nhớ cấp phát cho biến
 Thời gian sống(Lifetime )
 Phạm vi( Scope)
 Kết nối (Binding):là sự kết hợp giữa một thuộc tính và một
thực thể hoặc giữa một toán tử và một ký hiệu
 Thời điểm kết nối(Binding time) : là thời điểm mà tại đó kết

nối xảy ra
 Thời điểm thiết kế chương trình :ví dụ như kết nối
giữa ký hiệu của toán tử với toán tử(ký hiệu + :dùng
cộng hai số)
 Thời điểm xây dựng chương trình dịch :kết nối kiểu
có dấu chấm động với một biểu diển của nó
 Thời gian biên dịch :giữa tên biến và kiểu của nó
 Link time:gọi đến các hàm thư viện
 Load time:Tải chương trình vào bộ nhớ,cấp phát vùng
nhớ cho biến toàn cục
 Runtime :tại thời điểm thực thi biến cục bộ sẽ được
khởi tạo khi hàm chứa nó được gọi
 Ví dụ cho đoạn lệnh
Int count;

Count=count+5
• Định nghĩa kiểu int :thời điểm thiết kế chương
trình
• Định nghĩa kiểu của biến Count :tại thời điểm
biên dịch
• Định nghĩa Lệnh gán :thời điểm thiết kế trình
biên dịch
• Gán giá trị cho biến count :tại thời điểm thực
thi câu lệnh gán
• Định nghĩa toán tử +:thời điểm thiết kế chương
trình
• Ngữ nghĩa của phép + sẽ được kết nối tại thời
điểm biên dịch do khi đó hệ thống mới biết là
phép cộng được thực hiện trên kiểu dữ liệu gì
• Giá trị 5 :thời điểm xây dựng trình biên dịch

 Sự kết nối được xem là tĩnh nếu nó xảy ra trước thời điểm
chạy chương trình(Thời điểm biên dịch)và không đổi trong
suốt thời gian thực thi chương trình
 Một kết nối là động nếu nó xảy ra trong khi thực thi chương
trình và có thể thay đổi trong lúc thực thi
• Kết nối kiểu
4
 Trước khi biến được tham chiếu trong chương trình nó phải
được liên kết với một kiểu dữ liệu nào đó
 Có hai vấn đề quan trọng trong khi phải làm rõ
 Làm sao để chỉ ra kiểu dữ liệu của biến
 Khi nào kết nối kiểu sẽ xãy ra
 Kiểu của biến có thể được chỉ ra khi khai báo, khai báo có
thể tường minh hay không tường minh
 Việc khai báo biến tường minh hay không tường minh tạo
một kết nối tĩnh khi thực thi chương trình
 Một khai báo tường minh là câu lệnh dùng để khai báo kiểu
cho biến
 Ví dụ
• int a;//khai báo a có kiểu interger
 Một khai báo không tường minh là kỹ thuật dùng biến mà
không cần khai báo,việc xác định kiểu của biến thông qua
lệnh truy xuất đầu tiên đến biến
 Ưu điểm
• Ưu điểm :Dễ viết :sử dụng biến mà không cần
khai báo
• Khuyết điểm :độ tin cậy giảm
 Khai báo biến và định nghĩa biến
 Khai báo :là lệnh cho biết biến có tên là gì, có kiểu dữ
liệu gì? Nhưng không cấp phát vùng nhớ

 Định nghĩa :là lệnh cho biết biến có tên là gì, có kiểu
dữ liệu gì và yêu cầu hệ thống cấp phát vùng nhớ
 Ví dụ trong php ta có đoạn lênh sau:
<?php
$a = 1;//Định nghĩa
$b = 2;//Định nghĩa
function Sum()
{
global $a, $b;//khai báo
$b = $a + $b;
}
?>
 Kết nối kiểu động :kết nối xảy ra tại thời điểm thực thi lệnh
gán
Ví dụ trong PHP
<?php
5
$a=array(1,4,5);//$a là 1 mảng
$a=”vntan”;//@a là một chuổi
?>
 Ưu điểm :linh động khi xây dựng chương trình con khi
đó ds tham số có thể nhận kiểu dữ liệu bất kỳ
 Khuyết điểm:
• chi phí thời gian cao vì phải kiểm tra kiểu trong
khi thực thi
• Dò tìm kiểu của trình biên dịch khó khăn, hệ
thống thực thi ngôn ngữ để lưu lại kiểu dữ liệu
trong thời gian thực thi chương trình
• Chỉ dùng trình thông dịch để dịch chương
trình vì nếu dùng trình biên dịch để dịch thì đối

với một biết chỉ được liên kết với kiểu dữ liệu
một lần khi biên dịch và các toán tữ được dùng
với biến hay danh sách tham số của chương
trình con sẽ được xác định tại thời gian biên
dịch
 Suy luận kiểu :được dùng trong các ngôn ngữ ML, Miranda
and Haskell, kiểu được suy luận thông qua phép gán trong
một ngữ cảnh nào đó
Ví dụ :
• Kết nối vùng nhớ và thời gian sống
 Kết nối vùng nhớ cho một biến là quá trình cấp pháp hay thu
hồi vùng nhớ của một biến
 Cấp phát vùng nhớ :yêu cầu một vùng nhớ từ vùng
nhớ khả dụng
 Giải phòng vúng nhớ : trả vùng nhớ được dùng cho
biến về vùng nhớ khả dụng
6
 Thời gian sống của một biến là khoảng thời gian từ khi biến
được khởi tạo cho đến khi biến bị thu hồi vùng nhớ
• Phân loại biến theo thời gian sống : có 4 loại biến
 Biến tĩnh(Static variable) :là loại biến kết nối với vùng nhớ
trước khi thực thi và duy trì cho đến khi kết thúc chương
trình (biến toàn cục)
 Ưu điểm :
• Tính hiệu quả : truy xuất trực tiếp đến địa chỉ
của ô nhớ
• Hỗ trợ quản lý thông tin sử dụng chương trình
con (biến cục bộ có kiểu static trong c)
 Nhược điểm :
• thiếu tính linh động, không đệ quy

• không chia sẽ vùng nhớ cho biến khác
 Biến ngăn xếp(Stack-dynamic variable) :kết nối vùng nhớ khi
câu lệnh khai báo biến cục bộ được khai báo trong chương
trình coni, hầu hết các thuộc tính của biên đều được xác
định tại thời điểm biên dịch nhưng địa chỉ của ô nhớ mà biến
truy xuất sẽ được cấp phát lúc thực thi
 Kết nối vùng nhớ khi câu lệnh khai báo được thực thi
 Ưu điểm
• Hỗ trợ đệ quy
• Các chương trình con có thể chia sẻ bộ nhớ
 Nhược điểm
• Phải cấp phát và giải phóng vùng nhớ mỗi khi
gọi hàm
• Không lưu trữ thông tin
• Truy xuất gián tiếp thông qua bản ghi hoạt
động của chương trình con(lấy địa chỉ của con
trỏ +địa chỉ tương đối được cấp cho biến trong
ngăn xếp)
 Biến được cấp phát động trong vùng nhớ Head(Explicit
heap-dynamic) :việc cấp phát này thông qua các lệnh cấp
phát tường minh
 Ví dụ như các hàm cấp phát malloc, hoặc alloc trong
c
 Khuyết điểm
• Sự an toàn của biến phụ thuộc vào người lập
trình
• Tham chiếu gián tiếp thông qua con trỏ hoặc
tham chiếu
 Ưu điểm :quản lý hiệu quả vùng nhớ
 Biến động sử dụng bộ nhớ Head:vùng nhớ cấp phát cho

biến thay đổi khi thực thi
7
 ví dụ
• list=array(1,2,3)

• List=’vntan’
 Ưu điểm
• Linh động
 Nhược điểm
• Kém hiệu quả
1. Ví dụ :
List=array(1,3,4)
List[100]=5
//cấp phát lại vùng nhớ, sao chép dữ liệu và
giải phóng vùng nhớ cũ
• Mất đi khả năng dò tìm lổi của trình biên dịch
 Định kiểu mạnh
 Một ngôn ngữ lập trình được gọi là định kiểu mạnh
nếu các lỗi về kiểu đều được phát hiện
 Một ngôn ngữ định kiểu mạnh có các thuộc tính:
• Tất cả các biến trong chương trình đều phải có duy
nhất một kiểu và kiểu dữ liệu của biến sẽ được xác
định tại thời điểm biên dịch
• Có thể phát hiện tất cả các lỗi sai về kiểu của biến
• Phát hiện các lỗi về kiểu đối với những biến có nhiều
kiểu dữ liệu(kiểu Union)
• Ví dụ trong đoạn chương trình sau ta khai báo một
record(union) định nghĩa hai kiễu dữ liệu là real và
một mảng int , hai kiểu này dùng chung vùng nhớ 4
byte,trong chương trình ta khai báo một biến x có

kiểu bảng ghi và chọn kiểusố thực để gán dữ liệu
nhưng khi xuất thì xuất mảng nhưng chương trình
không báo lỗi =>Pascal không phải là ngôn ngữ định
kiểu mạnh
8
• Trong C người lập trình có thể sử dụng toán tử ép
kiểu =>có rủi ro=>c ,hỗ trợ union, không có kiểm tra
kiểu khi truyền tham số không phải là ngôn ngữ định
kiểu mạnh
• Kiểm tra kiểu :
 là quá trình được sử dụng để đảm bảo các toán hạng của
một toán tử phải tương thích kiểu với nhau
 tương thích kiểu là :được chấp nhận bởi toán hạng hoặc
được ngôn ngữ hỗ trợ chuyển kiểu về các kiểu hợp lệ
 lỗi về kiểu là thực hiện một toán tử trên các toán hạn có kiểu
không phù hợp
 nếu kết nối kiểu là tĩnh thì kiểm tra kiểu là tĩnh và ngược lại
 Ba luật kiểm tra kiểu
 Luật tương đương kiểu
 Luật tương thích kiểu
 Luật suy luận kiểu
 Luật tương đương kiểu :có hai loại tương dương
 Tương đương cấu trúc :có cấu trúc giống nhau thì
tương đương nhau
 Tương đương tên:nếu hai biến được khai báo cùng
một tên kiểu thì tương đương
9
 Các ngôn ngữ thường kết hợp hai kiểu tương đương
này
• Tương đương theo cấu trúc :tùy theo ngôn ngữ lập trình mà khác nhau

Ví dụ
 Để kiểm tra hai kiểu có tương đương cấu trúc hay không,
toàn bộ cấu trúc của hai kiểu sẽ được so sánh
 Quá trình kiểm tra sẽ thay đổi các kiểu được định nghĩa về
các toán tử dựng kiểu (array)và các kiểu cơ bản
 Nếu sau khi phân tích nhận được hai chuổi như nhau thì
tương đương kiểu với nhau
 Ví dụ
#define Songuyen int
#define Mang int[50]
Hai biến
Int a;
Songuyen b;
Tương đương kiểu
Int a[50];
Mang b;
Tương đương kiểu với nhau
10
• Tương đương theo tên
 Nếu người lập trình đã định nghĩa tên của hai tên kiểu mới,
thì người lập trình muốn ngầm định đây là hai kiểu khác
nhau
 Ví dụ
• #define Songuyenduong int
• #define Songuyen int;
• Songuyenduong a;
• Songuyen=b;
• a=b;//báo lỗi nếu xét tương đương tên

 Hai biến được gọi tương đương theo tên thì hệ thống sẽ so

sánh theo tên
 Có hai loại tương đương tên
 Tương đương theo tên tuyệt đối(strict name
equivalence)
• #define Songuyenduong int
• #define Songuyen int;
• Songuyenduong a;
• Songuyen=b;
• a=b;//báo lỗi nếu xét tương đương tên
 Tương đương theo tên tương đối(loose name
equivalence)
• #define Songuyenduong int
• #define Songuyen int;
• Songuyenduong a;
• Songuyen=b;
• a=b;//không báo lỗi nếu xét tương đương tên
 Trong ngôn ngữ lập trình ada cho phép hai khả năng tương
đương theo tên thông qua hai khái niệm kiểu con (subtype)
và kiểu dẫn xuất(derived type)
 Kiểu con tương thích với kiểu cơ sở, các kiểu con mà
cùng kiểu cơ sở thì tương thích với nhau( tương thích
theo tên tương đối)
 Kiểu dẫn xuất :kế thừa mọi đặc tích của kiểu gốc
nhưng không tương đương với kiểu gốc(tương
đương theo tên tuyệt đối)
 Ví dụ
• subtype int is integer; //tương thích
• type celsius is new integer; //không tương thích
• type fahrenheit is new integer;
• int a;

• interger b;
• a=a+b;//tương thích
• celsius d;
• fahrenheit e;
• d=d+e;//không tương thích
• d=d+a;//không tương thích
• ví dụ

• So sánh tương đương theo tên và tương đương theo cấu trúc
 Tương đương theo cấu trúc linh động hơn tương đương
theo tên
 Cho dù người viết chương trình định nghĩa hai kiểu dữ liệu
khác nhau trên cùng một kiểu cơ sở với ngụ ý là hai kiểu dữ
liệu khác nhau nhưng nếu ngôn ngữ hỗ trợ tương đương
logic thì hai biến này là tương thích
• Ví dụ


 Lỗi hay không phụ thuộc vào ngôn ngữ lập trình
• Hầu hết các ngôn ngữ lập trình không yêu cầu phải tương đương kiểu mà
chì cần tương thích
 Một biểu thức đúng nếu các toán hạng tương thích với nhau
về kiểu
 Khi truyền tham số vào chương trình con, tham số thực và
tham số hình thức phải tương thích với n hau
• Chuyển kiểu(Coercion)
 Chuyển kiểu được thực hiện tự động do trình biên dịch thực
hiện (khác ép kiểu)
 Việc chuyễn kiểu tùy ý của lập trình viên ảnh hướng đến tính
định kiểu mạnh của ngôn ngữ

 Ví dụ trong c,C++ người sử dụng có thể chuyển từ số
thực sang số nguyên ->nguy cơ làm mất đi giá trị của
phần thập phân

II. Phạm vi của biến :
• là vùng lệnh có thể sử dụng biến
• Biến không cục bộ là biến có thể sử dụng trong chương trình con mà
không cần khai báo(biến toàn cục là một loại biến không cục bộ)
• Biến cục bộ là biến được khai báo và sử dụng trong một lô lệnh, trong một
chương trình con
• Luật phạm vi sử dụng biến :cách thức mà chương trình dịch sẽ tìm vị trí
khai báo biên
• Có hai loại phạm vi biến
 Phạm vi tĩnh :phạm vi xác định lúc biên dịch, khi gặp lệnh
sử dụng biến, trình biên dịch sẽ kiểm tra “từ trong ra ngoài”
để xác định vị trí khai báo biến
 Ví dụ :

 Khi sử dụng biến trong chương trình con, nếu biến vừa được khai báo trong
chương trình con, vừa được khai báo toàn cục, thì trình biên dịch sẽ sử dụng
biến được khai báo trong chương trình con

 Muốn truy xuất đến biến ngoài cùng tên với biến cục bộ trong C++ dùng cú
pháp ::tên biên

 Phạm vi biến trong khối lệnh :đây là phạm vi khai báo biến nhỏ nhất

 Ví dụ :

• if (FIRST > SECOND) {

• int TEMP; //
• TEMP = FIRST;
• FIRST = SECOND;
• SECOND = TEMP;
• }
 Trình biên dịch xem một khối lệnh giống như một chương trình con(cung cấp
vùng nhớ trong ngăn xếp)


 Phạm vi động :dựa vào dãy lời gọi của chương trình con, dựa vào quan hệ thời
gian gọi chương trình con ví dụ chương trình con A gọi chương trình con B,
chương trình con B gọi chương trình con C…,
 việc xác định phạm vi biến chỉ xác định được tại thời điểm chạy chương trình
dựa vào các lời gọi chương trình con
 ví dụ :

 Trong sub1 có sử dụng biến X,trình biên dịch sẽ tìm x trong sub1 nếu không tìm
thấy sẽ tự động tìm kiếm trong sub2(có),nếu không tìm thấy trong sub 2 thì sẽ
tìm ở big(ngược lại thứ tự gọi hàm)
 Đánh giá biến có phạm qui động
 Khuyết điểm
 Tất cả các biến cục bộ được khai báo trong chương trình con đều có
thể sử dụng ở những chương trình con mà nó gọi
 Phải tiến hành kiểm tra kiểu động
 ảnh hưởng đến tính dễ đọc và độ tin cậy
 Truy xuất đến biến không cục bộ trong phạm vi động lâu hơn truy xuất
đến biến cục bộ trong phạm vi tĩnh
 Ưu điểm :trong một số trường hợp không cần truyền tham
số cho chương trình con


 Phạm vi và thời gian sống của biến

 Phạm vi : là không gian từ lệnh khai báo biến đến lệnh kết
thúc chương trình con mà biến khai báo

 Thời gian sống :là khoảng thời gian chương trình con bắt
đầu thực thi cho đến thực thi xong

 Nếu biển cục bộ tĩnh (static):phạm vi sử dụng là trong
chương trình con, thời gian sống là thời gian sống của toàn
bộ chương trình

 Ví dụ :

• void A() { … }
• void B() { int x; … A(); … }
 Phạm vi của biến x: trong chương trình con B, thời gian
sống :bao gồm cả thời gian thực hiện chương trình con A
• Môi trường tham chiếu
 Môi trường tham chiếu của một câu lệnh là tập hợp các
biến, các chương trình con mà câu lệnh có thể truy xuất
đến
 Trong biến phạm vi tĩnh :môi trường tham chiếu của câu
lệnh là các biến được khai báo trong nó và các biến được
khai báo ở phạm vi chứa nó
 Với ngôn ngữ phạm vi động :môi trường tham chiếu là các
biến cục bô và các biến trong các chương trình con đang
hoạt động
 Ví dụ :phạm vi tĩnh



 Phạm vi động :


×