You are on page 1of 21

Some issues

Early binding vs. Late binding


Static binding vs. Dynamic binding
Polymorphism - A name is bound to more than one entity. (Một
tên được liên kết với nhiều thực thể)
Alias - Many names are bound to one entity (Nhiều tên được
liên kết với một thực thể)

Binding Time
Language design time
Language implementation time
Programming time
Compilation time
Linking time
Load time
Runtime
Object Lifetime
Object
Object lifetime
Binding lifetime
Dangling reference
Leak memory - Garbage
Blocks: Một khối là một vùng văn bản, có thể chứa các khai báo cho
vùng đó
Scope: Phạm vi của một liên kết là vùng văn bản của chương trình mà
liên kết có hiệu lực.
Static vs. Dynamic
Phạm vi tĩnh, hoặc phạm vi từ vựng, được xác định trong quá trình
biên dịch (compilation)
Liên kết hiện tại - trong khối bao quanh chặt chẽ nhất
Phạm vi toàn cầu
Phạm vi tĩnh cục bộ
Phạm vi động được xác định trong thời gian chạy. (runtime)
Ràng buộc hiện tại - lần thực thi gần đây nhất nhưng không bị
phá hủy

Quy tắc phạm vi tĩnh cho các khối

Tham chiếu đến một số identifier luôn bị ràng buộc với khai báo cục
bộ nhất của nó
Một khai báo là ẩn bên ngoài khối mà nó xuất hiện
Các khai báo trong các khối bao quanh có thể nhìn thấy trong các
khối bên trong, trừ khi chúng đã được khai báo lại
Các khối có thể được đặt tên và việc khai báo tên của nó được coi là
một khai báo cục bộ của khối bên ngoài.
Referencing Environment -> môi trường có thể tham khảo đến được.
Môi trường tham chiếu của một câu lệnh là tập hợp tất cả các
tên hiển thị cho câu lệnh
Trong ngôn ngữ có phạm vi tĩnh, đó là các tên cục bộ + tất cả
các tên hiển thị trong tất cả các phạm vi bao quanh
Trong một ngôn ngữ có phạm vi động, môi trường tham chiếu là
các liên kết cục bộ + tất cả các liên kết hiển thị trong tất cả các
chương trình con đang hoạt động.

 Name
 Binding
 Scope
 Referencing Environment

Static-scoped Language

Môi trường tham khảo của hàm:


Main
Sub1
Sub2 là gì???
Dynamic-scoped Language

Môi trường tham khảo của

Bảng hoạt động là gì??


Sự phát triển của các ngôn ngữ lập trình có thể được nhìn nhận một
cách rộng rãi như là một quá trình đã dẫn đến định nghĩa về các hình
thức ngày càng xa rời máy vật lý. Trong bối cảnh này, tên đóng một
vai trò cơ bản. Một cái tên, thực sự, không gì khác hơn là một chuỗi
ký tự (có thể có ý nghĩa) được sử dụng để đại diện cho một số thứ
khác.
Chúng cho phép trừu tượng hóa một trong hai khía cạnh của dữ liệu,
ví dụ như sử dụng tên để biểu thị vị trí trong bộ nhớ, hoặc các khía
cạnh của điều khiển, ví dụ đại diện cho một tập hợp lệnh có tên. Việc
xử lý chính xác các tên đòi hỏi các quy tắc ngữ nghĩa chính xác cũng
như các cơ chế thực hiện đầy đủ
Trong chương này, chúng tôi sẽ phân tích các quy tắc này. Đặc biệt,
chúng ta sẽ xem xét khái niệm về môi trường và các cấu trúc được sử
dụng để tổ chức nó. Chúng tôi cũng sẽ xem xét các quy tắc về khả
năng hiển thị (hoặc scope). Chúng tôi để lại cho đến khi điều trị
chương tiếp theo của việc đề cập đến các khái niệm này. Chúng ta
hãy ngay lập tức quan sát cách, trong các ngôn ngữ có thủ tục, để
xác định chính xác khái niệm môi trường, người ta cần các khái niệm
khác, liên quan đến việc truyền tham số. Chúng ta sẽ thấy những khái
niệm này trong Chap. 7. Trong trường hợp của ngôn ngữ hướng đối
tượng, cuối cùng, có những quy tắc hiển thị cụ thể khác mà chúng ta
sẽ xem xét trong Chap. 10.
4.1 Names and Denotable Object
Định nghĩa biến

Định nghĩa hàm:


chúng tôi giới thiệu các tên mới, chẳng hạn như fie và foo để đại diện
cho một đối tượng (một biến và một hàm trong ví dụ của chúng tôi).
Chuỗi ký tự fie có thể được sử dụng mỗi khi chúng ta muốn tham
chiếu đến biến mới, giống như foo chuỗi ký tự cho phép chúng ta gọi
hàm gán giá trị 1.
Do đó, tên không khác gì một chuỗi các ký tự được sử dụng để đại
diện hoặc biểu thị một đối tượng khác.
Trong hầu hết các ngôn ngữ, tên được hình thành từ các định danh,
có nghĩa là từ chữ và số đếm tokens, hơn nữa các ký hiệu khác cũng
có thể là tên. Ví dụ, + và - là tên biểu thị, nói chung, các phép toán
nguyên thủy.
Mặc dù nó có vẻ hiển nhiên, nhưng điều quan trọng là phải nhấn mạnh
rằng tên và đối tượng mà nó biểu thị không giống nhau. Thực tế, tên
chỉ là một chuỗi ký tự, trong khi ký hiệu của nó có thể là một đối
tượng phức tạp như một biến, một hàm, một kiểu, v.v.
Và trên thực tế, một đối tượng duy nhất có thể có nhiều hơn một tên
(trong trường hợp này, người ta nói về alias), trong khi một tên duy
nhất có thể biểu thị các đối tượng khác nhau tại các thời điểm khác
nhau. Do đó, khi chúng ta có thể sử dụng cụm từ “biến fie” hoặc cụm
từ “hàm foo”, cần nhớ rằng các cụm từ này là chữ viết tắt của “biến
có tên fie” và “hàm với tên foo ”. Nói một cách tổng quát hơn, trong
thực tế lập trình, khi một cái tên được sử dụng, nó hầu như luôn có ý
nghĩa để chỉ đối tượng mà nó biểu thị.
Việc sử dụng tên thực hiện cơ chế trừu tượng hóa dữ liệu đầu tiên,
cơ bản.
Ví dụ, khi, trong một ngôn ngữ mệnh lệnh, chúng ta xác định tên
bằng cách sử dụng một biến, chúng ta đang giới thiệu một mã định
danh tượng trưng cho một vị trí bộ nhớ; do đó chúng tôi đang trừu
tượng hóa các chi tiết cấp thấp của địa chỉ bộ nhớ. Nếu, sau đó,
chúng tôi sử dụng lệnh gán:
giá trị 2 sẽ được lưu trữ ở vị trí dành riêng cho biến có tên fie. Ở cấp
độ lập trình, việc sử dụng tên giúp tránh phải bận tâm đến bất kỳ vị
trí nào. Sự tương ứng giữa tên và vị trí bộ nhớ phải được đảm bảo bởi
quá trình triển khai. Chúng tôi sẽ sử dụng thuật ngữ môi trường
 để chỉ phần triển khai đó chịu trách nhiệm về các liên kết giữa
tên và các đối tượng mà chúng biểu thị.
Chúng ta sẽ thấy rõ hơn trong Sect. 6.2.1 chính xác thì cái gì cấu
thành một biến và cách nó có thể được liên kết với các giá trị
Tên là cơ bản ngay cả khi triển khai một dạng trừu tượng điều khiển.
Thủ tục(procedure) không gì khác hơn là một tên được liên kết với
một tập hợp các lệnh, để có được các quy tắc hiển thị nhất định sẵn
có cho lập trình viên giao diện duy nhất của nó (bao gồm tên của thủ
tục và có thể là một số tham số). Chúng ta sẽ xem các chi tiết cụ thể
của sự trừu tượng hóa điều khiển trong Chap. 7.

Các đối tượng mà một tên có thể được đặt được gọi là các đối tượng
có thể ký hiệu. Ngay cả khi có sự khác biệt đáng kể giữa các ngôn ngữ
lập trình, sau đây là danh sách không đầy đủ các đối tượng có thể
biểu thị:
• Các đối tượng có tên do người dùng xác định: biến, tham số
chính thức, biện pháp xử lý chuyên nghiệp (theo nghĩa rộng), kiểu do
người dùng xác định, nhãn, mô-đun, hằng số do người dùng xác định,
ngoại lệ.
• Các đối tượng có tên được xác định bởi ngôn ngữ lập trình:
kiểu nguyên thủy, phép toán nguyên thủy, hằng số xác định trước.
Mối liên kết (hoặc ràng buộc) giữa một tên và một đối tượng mà nó
biểu thị có thể được tạo ra ở nhiều thời điểm khác nhau. Một số tên
được liên kết với các đối tượng trong quá trình thiết kế một ngôn
ngữ, trong khi các liên kết khác chỉ được giới thiệu khi một chương
trình được thực thi. Xem xét toàn bộ quá trình từ định nghĩa ngôn
ngữ lập trình đến thực thi một chương trình cụ thể, chúng ta có thể
xác định các giai đoạn sau để tạo liên kết tên với đối tượng:
Thiết kế ngôn ngữ Trong giai đoạn này, các ràng buộc giữa các hằng
nguyên thủy, kiểu và phép toán của ngôn ngữ được xác định (ví dụ, +
biểu thị phép cộng và int biểu thị kiểu số nguyên, v.v.).
Viết chương trình Cho rằng lập trình viên chọn tên khi họ viết một
chương trình, chúng ta có thể coi giai đoạn này như một giai đoạn với
định nghĩa một phần của một số ràng buộc, sau đó sẽ được hoàn
thành. Liên kết của một mã định danh với một biến, ví dụ, được định
nghĩa trong chương trình nhưng chỉ được tạo hiệu quả khi không gian
cho biến được cấp phát trong bộ nhớ.
Thời gian biên dịch Trình biên dịch, dịch các cấu trúc của ngôn ngữ
cấp cao thành mã máy, phân bổ không gian bộ nhớ cho một số cấu
trúc dữ liệu có thể được xử lý tĩnh. Ví dụ, đây là trường hợp của các
biến toàn cục của một chương trình. Kết nối giữa số nhận dạng của
một biến và vị trí bộ nhớ tương ứng được hình thành tại thời điểm
này.
Thời gian chạy Thuật ngữ này biểu thị toàn bộ khoảng thời gian từ khi
bắt đầu đến khi kết thúc chương trình. Tất cả các liên kết chưa được
tạo trước đó phải được hình thành trong thời gian chạy. Đây là
trường hợp, ví dụ, đối với các ràng buộc của bộ định giá iden biến với
vị trí bộ nhớ cho các biến cục bộ trong một thủ tục đệ quy hoặc đối
với các biến con trỏ có bộ nhớ được cấp phát động.
Trong mô tả trước, chúng tôi đã bỏ qua các giai đoạn quan trọng
khác, chẳng hạn như linking và loading trong đó các ràng buộc khác
(ví dụ: đối với tên bên ngoài đề cập đến các đối tượng trong các mô-
đun khác). Tuy nhiên, trong thực tế, hai giai đoạn nguyên tắc được
đánh giá bằng cách sử dụng các thuật ngữ “tĩnh” và “động”. Thuật
ngữ “tĩnh” được sử dụng để chỉ mọi thứ xảy ra trước khi thực thi,
trong khi “động” đề cập đến mọi thứ xảy ra trong quá trình thực thi.
Vì vậy, ví dụ, quản lý bộ nhớ tĩnh được thực hiện bởi trình biên dịch,
trong khi quản lý động được thực hiện bởi các hoạt động đã được
thích hợp được thực thi bởi máy trừu tượng trong thời gian chạy.

4.2 Environments and Blocks


Không phải tất cả các liên kết giữa tên và các đối tượng có thể biểu
thị được cố định một lần và mãi mãi khi bắt đầu thực thi chương
trình. Nhiều loại có thể khác nhau trong quá trình thực hiện. Để có
thể hiểu được các hiệp hội này hoạt động như thế nào, chúng ta cần
đưa ra khái niệm về môi trường.
Định nghĩa 4.1 (Môi trường) Tập hợp các liên kết giữa tên và các đối
tượng có thể biểu thị tồn tại trong thời gian chạy tại một điểm cụ thể
trong chương trình và tại một thời điểm cụ thể trong quá trình thực
thi, được gọi là môi trường (tham chiếu).
Thông thường, khi chúng ta nói về môi trường, chúng ta chỉ đề cập
đến các liên kết không được thiết lập bởi định nghĩa ngôn ngữ. Do đó,
môi trường là thành phần của máy trừu tượng, đối với mọi tên được
lập trình viên giới thiệu và tại mọi thời điểm trong chương trình, cho
phép xác định kết hợp chính xác là gì.
Lưu ý rằng môi trường không tồn tại ở cấp độ của máy vật lý. Sự hiện
diện của môi trường tạo thành một trong những nguyên tắc của ngôn
ngữ bậc cao mà phải được mô phỏng một cách phù hợp bởi mỗi cách
triển khai của ngôn ngữ.
Khai báo là một cấu trúc cho phép giới thiệu một liên kết trong môi
trường. Các ngôn ngữ cấp cao thường có các khai báo rõ ràng, chẳng
hạn như

(đầu tiên là khai báo một biến, thứ hai của một hàm có tên f, thứ ba
là khai báo kiểu mới, T, trùng với kiểu int). Một số ngôn ngữ cho
phép các khai báo ngầm giới thiệu một liên kết trong môi trường cho
một tên khi nó được sử dụng lần đầu tiên. Kiểu của đối tượng được
biểu thị được suy ra từ ngữ cảnh mà tên được sử dụng lần đầu tiên
(hoặc đôi khi từ dạng cú pháp của tên).
Trước hết, một tên duy nhất có thể biểu thị các đối tượng khác nhau
trong các phần khác nhau của chương trình. Ví dụ, hãy xem xét mã
của Hình 4.1. Tên fie ngoài cùng biểu thị một biến số nguyên, trong
khi tên bên trong là kiểu char

Cũng có thể một đối tượng được biểu thị bằng nhiều hơn một tên
trong các môi trường khác nhau.
Ví dụ, nếu chúng ta truyền một biến bằng cách tham chiếu đến một
thủ tục, thì biến đó có thể truy cập được bằng cách sử dụng tên của
nó trong chương trình gọi và bằng tên của tham số chính thức trong
phần thân của thủ tục (xem Phần 7.1.2). Ngoài ra, chúng ta có thể sử
dụng con trỏ để tạo cấu trúc dữ liệu trong đó cùng một đối tượng sau
đó có thể truy cập được bằng cách sử dụng các tên khác nhau.
Trong khi các tên khác nhau cho cùng một đối tượng được sử dụng
trong các môi trường khác nhau, không có vấn đề cụ thể nào phát
sinh. Tình hình phức tạp hơn khi một đối tượng có thể nhìn thấy bằng
các tên khác nhau trong cùng một môi trường. Đây được gọi là
aliasing và các tên khác nhau của cùng một đối tượng được gọi là
aliases. Nếu tên của một biến được truyền qua tham chiếu đến một
thủ tục cũng có thể nhìn thấy bên trong cùng một thủ tục, chúng ta
có một tình huống là aliasing. Các tình huống alias khác có thể dễ
dàng xảy ra khi sử dụng con trỏ. Nếu X và Y là các biến kiểu con trỏ,
phép gán X = Y cho phép chúng ta truy cập cùng một vị trí bằng cách
sử dụng cả X và Y.

Tên X và Y biểu thị hai biến khác nhau, tuy nhiên, sau khi thực hiện
lệnh gán X = Y, cho phép truy cập cùng một vị trí bộ nhớ (do đó, lệnh
in tiếp theo sẽ xuất ra giá trị 10).
Cuối cùng, có thể là một tên duy nhất, trong một vùng văn bản của
chương trình, có thể biểu thị các đối tượng khác nhau theo luồng
thực thi của chương trình. Tình huống này phổ biến hơn so với cái
nhìn đầu tiên. Đó là trường hợp, ví dụ, đối với một thủ tục đệ quy
khai báo một tên cục bộ. Các trường hợp khác thuộc loại này, phức
tạp hơn, sẽ được thảo luận dưới đây trong chương này khi thảo luận
về phạm vi động (Lĩnh vực 4.3.2)
4.2.1 Blocks
Định nghĩa 4.2 (Khối) Một khối là một vùng văn bản của chương trình,
được xác định bằng dấu bắt đầu và dấu kết thúc, có thể chứa các
khai báo cục bộ cho vùng đó (nghĩa là xuất hiện trong vùng). Các cấu
trúc khối bắt đầu và kết thúc khác nhau tùy theo ngôn ngữ lập trình:
begin ... end cho các ngôn ngữ trong họ ALGOL, dấu ngoặc nhọn {...}
cho C và Java, dấu ngoặc tròn (...) cho LISP và các phương ngữ của
nó , let ... in ... end bằng ML, v.v.
Hơn nữa, định nghĩa chính xác của khối trong ngôn ngữ lập trình cụ
thể có thể hơi khác so với định nghĩa được đưa ra ở trên. Trong một
số trường hợp, chẳng hạn, người ta chỉ nói về khối khi có các khai
báo cục bộ. Tuy nhiên, thông thường, các khối có một chức năng
quan trọng khác, đó là nhóm một loạt lệnh thành một thực thể cú
pháp có thể được coi là một lệnh (tổng hợp) duy nhất.
Tuy nhiên, những sự khác biệt này không liên quan đến mức chúng ta
có liên quan. Do đó, chúng tôi sẽ sử dụng định nghĩa được đưa ra ở
trên và chúng tôi phân biệt hai trường hợp:
Block associated with a procedure Đây là một khối liên kết với
các khai báo cục bộ cho một thủ tục. Nó tương ứng bằng văn bản với
phần thân của chính thủ tục, được mở rộng với các khai báo của các
tham số chính thức.
In-line block Đây là khối không tương ứng với tuyên bố về quyền
ưu tiên và có thể xuất hiện (nói chung) ở bất kỳ vị trí nào mà lệnh có
thể xuất hiện.
4.2.2 Types of Environment
Môi trường thay đổi trong quá trình thực hiện một chương trình. Tuy
nhiên, các thay đổi thường xảy ra vào hai thời điểm chính xác: khi
vào và ra của một khối. Do đó, khối có thể được coi là cấu trúc có độ
chi tiết nhỏ nhất mà một môi trường không đổi có thể được liên kết
với nhau.
Môi trường của khối, theo thuật ngữ này, có nghĩa là môi trường
tồn tại khi khối được thực thi, ban đầu bao gồm các liên kết giữa các
tên được khai báo cục bộ với chính khối. Trong hầu hết các ngôn ngữ
cho phép các khối, các khối có thể được lồng vào nhau; nghĩa là,
định nghĩa của một khối có thể được bao gồm hoàn toàn trong định
nghĩa của khối khác. Ví dụ về các khối ẩn danh lồng nhau được hiển
thị trong Hình 4.1. Việc chồng chéo các khối để khối mở cuối cùng
không phải là khối đầu tiên bị đóng không bao giờ được phép. Nói
cách khác, một chuỗi lệnh thuộc loại sau không được phép sử dụng
bằng bất kỳ ngôn ngữ nào:

Các khai báo trong khối được đánh giá khi khối được nhập và hiển thị
trong toàn khối. Có nhiều ngoại lệ đối với quy tắc này, một số trong
số đó sẽ được thảo luận bên dưới.
Block nesting là một cơ chế quan trọng để cấu trúc môi trường. Có
những cơ chế cho phép các khai báo cục bộ cho một khối được hiển
thị trong các khối được lồng bên trong nó.
Vẫn còn không chính thức vào lúc này, chúng tôi nói rằng một khai
báo cục bộ cho một khối có thể nhìn thấy trong một khối khác khi
liên kết được tạo bởi một khai báo như vậy có mặt trong khối thứ
hai. Những cơ chế của ngôn ngữ quy định cách thức và thời điểm hiển
thị khai báo được gọi là visible rules. Quy tắc hiển thị chuẩn cho các
ngôn ngữ có khối được biết đến nhiều:
Một khai báo cục bộ cho một khối có thể nhìn thấy trong khối đó
và trong tất cả các khối được liệt kê bên trong nó, trừ khi có một
khai báo mới cùng tên trong cùng một khối đó. Trong trường hợp
này, trong khối chứa định nghĩa lại, khai báo mới sẽ ẩn khai báo
trước đó.
Trong trường hợp có định nghĩa lại, quy tắc hiển thị thiết lập rằng chỉ
tên cuối cùng được khai báo sẽ hiển thị trong khối bên trong, trong
khi ở khối bên ngoài có lỗ nhìn thấy. Trên thực tế, liên kết cho tên
được khai báo trong khối bên ngoài sẽ bị vô hiệu hóa đối với toàn bộ
khối bên trong (chứa khai báo mới) và sẽ được kích hoạt lại khi thoát
khỏi khối bên trong.
Lưu ý rằng không có tầm nhìn từ bên ngoài vào trong.
Mọi liên kết được giới thiệu trong môi trường cục bộ cho một khối
không hoạt động (hay đúng hơn là tên mà nó xác định không hiển thị)
trong một khối bên ngoài chứa khối bên trong. Tương tự, nếu chúng
ta có hai khối ở cùng mức lồng nhau hoặc nếu cả hai khối đều không
chứa khối kia, tên được giới thiệu cục bộ trong khối này sẽ không
hiển thị trong khối kia.
Định nghĩa vừa đưa ra, mặc dù có vẻ chính xác, nhưng không đủ để
xác định chính xác môi trường sẽ là gì tại một điểm tùy ý trong một
gam pro. Chúng tôi sẽ giả định quy tắc này cho phần còn lại của phần
này, trong khi phần tiếp theo sẽ liên quan đến việc nêu các quy tắc
hiển thị một cách chính xác.
Nói chung, chúng ta có thể xác định 3 thành phần của một môi
trường, như được nêu trong định nghĩa sau
Định nghĩa 4.3 (Loại môi trường) Môi trường liên kết với một khối
được hình thành từ các thành phần sau:
Môi trường cục bộ Điều này bao gồm tập hợp các liên kết cho các tên
được khai báo cục bộ cho khối. Trong trường hợp khối dành cho một
thủ tục, môi trường cục bộ cũng chứa các liên kết cho các tham số
chính thức, miễn là chúng có thể được nhìn thấy, liên quan đến môi
trường, như các biến được khai báo cục bộ.
Môi trường không cục bộ Đây là môi trường được hình thành từ các
liên kết cho các tên có thể nhìn thấy từ bên trong một khối nhưng
chưa được khai báo cục bộ.
Môi trường toàn cầu Cuối cùng, có một môi trường được hình thành
từ các hiệp hội được tạo ra khi bắt đầu thực hiện chương trình. Nó
chứa các liên kết cho các tên có thể được sử dụng trong tất cả các
khối tạo thành chương trình

Môi trường cục bộ cho một khối có thể được xác định bằng cách chỉ
xem xét các khai báo có trong khối. Chúng ta phải nhìn ra bên ngoài
khối để xác định môi trường không cục bộ. Môi trường toàn cầu là
một phần của môi trường phi địa phương. Các tên được giới thiệu
trong môi trường địa phương có thể tự xuất hiện trong môi trường
không địa phương. Trong những trường hợp như vậy, khai báo trong
cùng (cục bộ) sẽ ẩn khai báo ngoài cùng. Các quy tắc hiển thị chỉ định
cách các tên được khai báo trong các khối bên ngoài được hiển thị
trong các khối bên trong. Trong một số trường hợp, có thể nhập tên
từ các mô-đun khác, được xác định riêng. Các hiệp hội cho những cái
tên này là một phần của môi trường toàn cầu.
Bây giờ chúng ta sẽ xem xét ví dụ trong Hình 4.2, trong đó, để dễ
tham khảo, chúng ta giả định rằng các khối có thể được gắn nhãn
(như trước đây, chúng ta cũng giả sử rằng write (x) cho phép chúng
ta in một giá trị số nguyên). Các nhãn hoạt động như các nhận xét
trong chừng mực có liên quan đến việc thực thi.
Giả sử rằng khối A là khối ngoài cùng. Nó tương ứng với main
Việc khai báo biến a giới thiệu một liên kết trong global
Bên trong khối B có hai biến được khai báo cục bộ (b và c). Do đó,
môi trường cho B được hình thành từ môi trường cục bộ, chứa liên
kết cho hai tên (b và c) và từ môi trường toàn cục chứa liên kết cho
a.
b,c
a
Bên trong khối C, 2 biến cục bộ (c và d) được khai báo. Do đó, môi
trường của C được hình thành từ môi trường cục bộ, trong đó có liên
kết cho hai tên (c và d) và từ môi trường không cục bộ chứa cùng
một môi trường toàn cục như trên, và cũng là liên kết cho tên b là kế
thừa từ môi trường của khối B. Lưu ý rằng khai báo cục bộ của c
trong khối C ẩn phần khai báo của c có trong khối B. Do đó, lệnh print
có trong khối C sẽ in ra giá trị 6.
C,d (c ở đây che mất b)
A -> từ global
B -> b
Trong khối D, cuối cùng, chúng ta có một môi trường cục bộ chứa
liên kết cho tên cục bộ e, môi trường toàn cục thông thường và môi
trường không cục bộ, ngoài liên kết cho a còn chứa liên kết cho các
tên b và c được giới thiệu. trong khối B. Cho rằng biến c chưa được
khai báo lại bên trong, do đó, trong trường hợp này, biến được khai
báo trong khối B vẫn hiển thị và giá trị được in ra sẽ là 5.
Lưu ý rằng liên kết cho tên d không xuất hiện trong môi trường không
cục bộ đối với D, cho rằng tên này được giới thiệu trong một khối bên
ngoài không chứa D. Các quy tắc hiển thị, thực sự, chỉ cho phép kế
thừa các tên được khai báo trong khối bên ngoài từ khối bên trong
chứ không phải ngược lại
E -> local
A -> global
B,c -> block B.
E = a + b + c -> (5)
A= 1
B =2
C = 2 (do chưa thấy c được khai báo lại)
Write(e) // 5

4.2.3 Operations on Environments

Như chúng ta đã thấy, những thay đổi trong môi trường được tạo ra
khi vào và ra khỏi một khối. Chi tiết hơn, trong quá trình thực thi
chương trình, khi một khối mới được nhập vào, các sửa đổi sau được
thực hiện đối với môi trường:
1. Các liên kết giữa các tên được khai báo cục bộ và các đối tượng ký
hiệu tương ứng được tạo ra.
2. Các liên kết có tên được khai báo bên ngoài và được xác định lại
bên trong khối sẽ bị vô hiệu hóa.
Ngoài ra khi khối được thoát, môi trường được sửa đổi như sau:
1. Các liên kết cho các tên được khai báo cục bộ cho khối và các đối
tượng mà chúng biểu thị sẽ bị phá hủy.
2. Các liên kết được kích hoạt lại giữa các tên tồn tại bên ngoài khối
và các tên đã được xác định lại bên trong khối
Nói một cách tổng quát hơn, chúng ta có thể xác định các thao tác
sau đối với tên và trên môi trường
Tạo liên kết giữa tên và đối tượng được ký hiệu (đặt tên) Đây là việc
xây dựng một khai báo (hoặc kết nối của một hình thức với một tham
số thực tế) khi một khối mới chứa các khai báo cục bộ hoặc tham số
được nhập vào.
Tham chiếu đến một đối tượng được biểu thị thông qua tên của nó
Đây là cách sử dụng tên (trong một biểu thức, trong lệnh hoặc trong
bất kỳ ngữ cảnh nào khác). Tên được sử dụng để truy cập đối tượng
được ký hiệu.
Hủy kích hoạt liên kết giữa tên và đối tượng được biểu thị Điều này
xảy ra khi nhập một khối trong đó một liên kết mới cho tên đó được
tạo cục bộ.
Liên kết cũ không bị phá hủy mà vẫn còn (không hoạt động) trong môi
trường. Nó sẽ có thể sử dụng lại được khi khối chứa liên kết mới còn
lại.
Kích hoạt lại một liên kết giữa tên và đối tượng được biểu thị Khi rời
khỏi khối trong đó một liên kết mới cho tên đó được tạo cục bộ, việc
kích hoạt lại xảy ra. Liên kết trước đó, đã bị vô hiệu hóa khi nhập vào
khối, bây giờ có thể được sử dụng.
Việc hủy liên kết giữa tên và đối tượng được biểu thị (hủy đặt tên)
Điều này được thực hiện trên các liên kết cục bộ khi khối mà các khối
liên kết này được tạo ra bị thoát. Liên kết bị xóa khỏi môi trường và
không thể sử dụng được nữa.
Tuy nhiên, chúng ta hãy lưu ý một cách rõ ràng rằng bất kỳ môi
trường nào đều chứa cả các liên kết hoạt động và không hoạt động
(chúng tương ứng với các khai báo đã bị ẩn đi do tác động của các
quy tắc hiển thị). Đối với các đối tượng có liên quan, các thao tác
nhập sau được phép:
Tạo một đối tượng có thể biểu thị Thao tác này được thực hiện trong
khi phân bổ sung lượng cần thiết để chứa đối tượng. Đôi khi, việc tạo
cũng bao gồm việc khởi tạo đối tượng.
Truy cập vào đối tượng có thể biểu thị Sử dụng tên và do đó môi
trường, chúng ta có thể truy cập đối tượng có thể biểu thị và do đó
truy cập giá trị của nó (ví dụ, để đọc nội dung của một biến). Chúng
ta hãy quan sát rằng tập hợp các quy tắc xác định vị trí của môi
trường, như mục đích của nó, tạo ra sự liên kết giữa tên và đối tượng
nó đề cập đến một đối một (tại một điểm nhất định trong chương
trình và trong một lần thực thi nhất định).
Sửa đổi đối tượng biểu thị Luôn có thể truy cập đối tượng biểu thị
thông qua tên và sau đó sửa đổi giá trị của nó (ví dụ: bằng cách gán
giá trị cho một biến).
Sự phá hủy của một đối tượng đáng chú ý Một đối tượng có thể bị phá
hủy bằng cách phân bổ lại bộ nhớ dành riêng cho nó.
Trong nhiều ngôn ngữ, các thao tác tạo liên kết giữa tên và đối tượng
có thể biểu thị và thao tác tạo đối tượng có thể biểu thị diễn ra cùng
một lúc. Đây là trường hợp, ví dụ, trong một khai báo của biểu mẫu
int x;
Khai báo này đưa vào môi trường một liên kết mới giữa tên x và một
biến số nguyên. Đồng thời, nó cấp phát bộ nhớ cho biến.
Tuy nhiên, điều này không phải luôn luôn như vậy và nói chung,
người ta không tuyên bố rằng thời gian tồn tại của một đối tượng có
thể biểu thị, đó là thời gian từ khi tạo ra đối tượng đến khi nó bị hủy
hoại, trùng với thời gian tồn tại của mối liên hệ giữa tên và đối tượng
. Thật vậy, một đối tượng denotable có thể có thời gian tồn tại lớn
hơn sự liên kết giữa tên và bản thân đối tượng, như trường hợp một
biến được chuyển tới một thủ tục bằng tham chiếu. Mối liên kết giữa
tham số chính thức và biến được kết hợp có thời gian tồn tại nhỏ hơn
thời gian tồn tại của chính biến đó. Nói chung hơn, tình huống kiểu
này xảy ra khi một tên tạm thời (ví dụ: một cục bộ cho một khối)
được giới thiệu cho một đối tượng đã có tên.
Lưu ý rằng tình huống chúng ta đang xem xét không phải như trong
Hình 4.2. Trong trường hợp này, thực sự, khai báo bên trong của
biến, c, không giới thiệu tên mới cho một đối tượng hiện có, nhưng
giới thiệu một đối tượng mới (một biến mới). Ngay cả khi, ngay từ
cái nhìn đầu tiên, điều này có vẻ kỳ quặc, nó cũng có thể là trường
hợp thời gian tồn tại của mối liên kết giữa tên và một đối tượng được
biểu thị lớn hơn thời gian tồn tại của đối tượng chinh nó.
Chính xác hơn, nó có thể là trường hợp một tên cho phép truy cập
vào một đối tượng không còn tồn tại. Một tình huống bất thường như
vậy có thể xảy ra, ví dụ, nếu chúng ta gọi bằng cách tham chiếu một
đối tượng hiện có và sau đó phân bổ bộ nhớ cho nó trước khi thủ tục
kết thúc. Tham số chính thức của thủ tục, trong trường hợp này, sẽ
biểu thị một đối tượng không còn tồn tại. Một tình huống kiểu này,
trong đó có thể truy cập một đối tượng có bộ nhớ đã được phân bổ
lại, được gọi là tham chiếu treo và là một dấu hiệu của lỗi. Chúng ta
sẽ quay trở lại vấn đề tài liệu tham chiếu treo trong Chap. 8, nơi chúng
tôi sẽ trình bày một số phương pháp để xử lý chúng.

You might also like