Trước khi xem xét vấn đề sinh mã được trình bày ở các chương sau, chương này trình bày một số vấn đề liên quan đến việc gọi thực hiện chương trình con, các chiến lược cấp phát bộ nhớ và quản lý bảng ký hiệu. Cùng một tên trong chương trình nguồn có thể biểu thị cho nhiều đối tượng dữ liệu trong chương trình đích. Sự biểu diễn của các đối tượng dữ liệu tại thời gian thực thi được xác định bởi kiểu của nó. Sự cấp phát và thu hồi các đối tượng dữ liệu được quản lý bởi một tập các chương trình con ở dạng mã đích.
CHƯƠNG VII MÔI TRƯỜNG THỜI GIAN THỰC HIỆN Nội dung chính: Trước xem xét vấn đề sinh mã trình bày chương sau, chương trình bày số vấn đề liên quan đến việc gọi thực chương trình con, chiến lược cấp phát nhớ quản lý bảng ký hiệu Cùng tên chương trình nguồn biểu thị cho nhiều đối tượng liệu chương trình đích Sự biểu diễn đối tượng liệu thời gian thực thi xác định kiểu Sự cấp phát thu hồi đối tượng liệu quản lý tập chương trình dạng mã đích Việc thiết kế chương trình xác định ngữ nghĩa chương trình nguồn Mỗi thực thi chương trình gọi mẩu tin kích hoạt Nếu chương trình đệ quy, số mẩu tin kích hoạt tồn thời điểm Mỗi ngơn ngữ lập trình có quy tắc tầm vực để xác định việc xử lý tham khảo đến tên không cục Tùy vào ngôn ngữ, cho phép chương trình chứa chương trình lồng không lồng nhau; Cho phép gọi đệ quy không đệ quy; Cho phép truyền tham số giá trị hay tham chiếu …Vì thế, thiết kế chương trình dạng mã đích ta cần ý đến yếu tố Mục tiêu cần đạt: Sau học xong chương này, sinh viên phải nắm được: • Cách gọi thực thi chương trình • Cách tổ chức nhớ chiến lược cấp phát – thu hồi nhớ Kiến thức bản: Sinh viên phải biết số ngôn ngữ lập trình cấp cao Pascal, C++, Java, v.v học mơn ngơn ngữ lập trình (phần đề cập đến chương trình con) Tài liệu tham khảo: [1] Compilers : Principles, Technique and Tools - Alfred V.Aho, Jeffrey D.Ullman - Addison - Wesley Publishing Company, 1986 [2] Modern Compiler Implementation in C - Andrew W Appel - Cambridge University Press, 1997 I CHƯƠNG TRÌNH CON Ðịnh nghĩa chương trình Ðịnh nghĩa chương trình khai báo Dạng đơn giản kết hợp tên chương trình thân Ví dụ 7.1: Chương trình Pascal đọc xếp số nguyên 142 (1) program sort(input, output) (2) var a: array[0 10] of integer; (3) procedure readarray; (4) var i: integer; (5) begin (6) for i=1 to read(a[i]); (7) end; (8) function partition(y,z:integer): integer; (9) var i,j,x,v: integer; (10) begin (11) end; (12) (13) (14) procedure quicksort(m,n:integer); var i: integer; begin; (15) if (n>m) then begin (16) i:= partition(m,n); (17) quicksort(m,i-1); (18) quicksort(i+1,n); (19) end; (20) end; (21) begin (22) a[0]:= -9999, a[10]:= 9999; (23) readarray; (24) quicksort(1,9); (25) end Hình 7.1- Chương trình Pascal đọc xếp số nguyên Chương trình chứa định nghĩa chương trình - Chương trình readarray từ dịng - 7, thân từ - - Chương trình partition từ dịng - 11, thân từ 10 - 11 - Chương trình quicksort từ dịng 12 - 20, thân từ 14 - 20 Chương trình xem chương trình có thân từ dịng 21 - 25 Khi tên chương trình xuất phần thân chương trình ta nói chương trình gọi điểm 143 Cây hoạt động Trong q trình thực chương trình thì: Dịng điều khiển tuần tự: tức việc thực chương trình bao gồm chuỗi bước Tại bước có điều khiển xác định Việc thực chương trình bắt đầu điểm bắt đầu thân chương trình trả điều khiển cho chương trình gọi điểm nằm sau lời gọi việc thực chương trình kết thúc • Thời gian tồn chương trình p chuỗi bước bước bước cuối thực thân chương trình bao gồm thời gian thực chương trình gọi p • Nếu a b hai hoạt động hai chương trình tương ứng thời gian tồn chúng tách biệt lồng • Một chương trình đệ quy hoạt động bắt đầu trước hoạt động trước chương trình kết thúc • Ðể đặc tả cách thức điều khiển vào hoạt động chương trình ta dùng cấu trúc gọi hoạt động Mỗi nút biểu diễn cho hoạt động chương trình Nút gốc biểu diễn cho hoạt động chương trình Nút a cha b dịng điều khiển hoạt động từ a sang b Nút a bên trái nút b thời gian tồn a xuất trước thời gian tồn b Ví dụ 7.2: Xét chương trình sort nói - Bắt đầu thực chương trình - Vào readarray - Ra khỏi readarray - Vào quicksort(1,9) - Vào partition(1,9) - Ra khỏi partition(1,9) // giả sử trả - Vào quicksort(1,3) - - Ra khỏi quicksort(1,3) - Vào quicksort(5,9); - - Ra khỏi quicksort(5,9) - Sự thực kết thúc 144 Hình 7.2 - Xuất mẩu tin hoạt động đề nghị chương trình hình 7.1 Ta có hoạt động tương ứng s r q(1,9) p(1,9) q(1,3) p(1,3) q(5,9) q(1,0) q(2,3) p(5,9) q(5,5) p(2,3) q(2,1) q(3,3) q(7,9) p(7,9) q(7,7) q(9,9) Hình 7.3- Cây hoạt động tương ứng với phần xuất hình 7.2 Ngăn xếp điều khiển Dòng điều khiển chương trình tương ứng với phép duyệt theo chiều sâu hoạt động Bắt đầu từ nút gốc, thăm nút trước thăm cách đệ quy nút từ trái sang phải Chúng ta dùng Stack, gọi Stack điều khiển, để lưu trữ hoạt động chương trình Khi hoạt động chương trình bắt đầu đẩy nút tương ứng với hoạt động lên đỉnh Stack Khi hoạt động kết thúc pop nút khỏi Stack Nội dung Stack thể đường dẫn đến nút gốc hoạt động Khi nút n nằm đỉnh Stack Stack chứa nút nằm đường từ n đến gốc Ví dụ 7.3: Hình sau trình bày nội dung Stack lưu trữ đường từ nút q(2, 3) đến nút gốc Các cạnh nét đứt thể nút pop khỏi Stack s q(1,9) r q(1,3) p(1,9) p(1,3) q(1,0) q(2,3) Hình 7.4 - Stack điều khiển chứa nút dẫn tới nút gốc Tại thời điểm đường dẫn tới gốc là: s q(1, 9) q(1, 3) q(2, 3) ( q(2, 3) nằm đỉnh Stack) 145 Tầm vực khai báo Ðoạn chương trình chịu ảnh hưởng khai báo gọi tầm vực khai báo Trong chương trình có nhiều khai báo trùng tên ví dụ biến i chương trình sort Các khai báo độc lập với chịu chi phối quy tắc tầm ngôn ngữ Sự xuất tên chương trình gọi cục (local) chương trình tầm vực khai báo nằm chương trình con, ngược lại gọi không cục (nonlocal) Liên kết tên Trong ngơn ngữ ngơn ngữ lập trình, thuật ngữ môi trường (enviroment) để ánh xạ từ tên đến vị trí nhớ thuật ngữ trạng thái (state) để ánh xạ từ vị trí nhớ tới giá trị lưu trữ mơi trường tên trạng thái giá trị nhớ Hình 7.5 - Hai ánh xạ từ tên tới giá trị Môi trường khác trạng thái: lệnh gán làm thay đổi trạng thái không thay đổi môi trường Khi mơi trường kết hợp vị trí nhớ s với tên x ta nói x liên kết tới s Sự kết hợp gọi mối liên kết x Liên kết động (dynamic counterpart) khai báo Chúng ta có tương ứng ký hiệu động tĩnh: Ký hiệu tĩnh Bản động Ðịnh nghĩa chương trình Sự hoạt động cuả chương trình Sự khai báo tên Liên kết tên Tầm vực khai báo Thời gian tồn liên kết Hình 7.6 - Sự tương ứng ký hiệu động tĩnh Các vấn đề cần quan tâm làm chương trình dịch Các vấn đề cần đặt tổ chức lưu trữ liên kết tên: Chương trình đệ quy khơng? Ðiều xảy cho giá trị tên cục trả điều khiển từ hoạt động chương trình 146 Một chương trình tham khảo tới tên cục khơng? Các tham số truyền gọi chương trình Một chương trình truyền tham số? Một chương trình trả kết quả? Bộ nhớ có cấp phát động khơng? Bộ nhớ có phải giải phóng cách tường minh? II TỔ CHỨC BỘ NHỚ Tổ chức nhớ thời gian thực sử dụng cho ngôn ngữ Fortran, Pascal C Phân chia nhớ thời gian thực Bộ nhớ chia để lưu trữ phần: Mã đích Ðối tượng liệu Bản Stack điều khiển để lưu trữ hoạt động chương trình Trong kích thước mã đích xác định thời gian dịch cấp phát tĩnh vùng thấp nhớ Tương tự kích thước số đối tượng liệu biết thời gian dịch cấp phát tĩnh Cài đặt ngôn ngữ Pascal, C dùng mở rộng Stack điều khiển để quản lý hoạt động chương trình Khi có lời gọi chương trình con, thể hoạt động bị ngắt thơng tin tình trạng máy, chẳng hạn giá trị đếm chương trình (program counter) ghi lưu vào Stack Khi điều khiển trả từ lời gọi, hoạt động tiếp tục sau khôi phục lại giá trị ghi đặt đếm chương trình vào sau lời gọi Ðối tượng liệu mà thời gian tồn chứa hoạt động lưu Stack Một vùng khác nhớ gọi Heap lưu trữ tất thông tin khác Code Static Data Stack Heap 147 Hình 7.7 - Phân chia nhớ thời gian thực cho mã đích vùng liệu khác Mẩu tin hoạt động Thông tin cần thiết để thực chương trình quản lý cách dùng mẩu tin hoạt động bao gồm số trường sau : Giá trị trả Các tham số thực tế Liên kết điều khiển Liên kết truy nhập Trạng thái máy Dữ liệu cục Giá trị tạm thời Hình 7.8 - Mẩu tin hoạt động tổng quát Ý nghĩa trường sau: Giá trị tạm thời: lưu giữ trình đánh giá biểu thức Dữ liệu cục bộ: Lưu trữ liệu cục thực chương trình Trạng thái máy: lưu giữ thông tin trạng thái máy trước chương trình gọi Thơng tin máy bao gồm đếm chương trình ghi lệnh mà phục hồi điều khiển trả từ chương trình Liên kết truy nhập: tham khảo tới liệu không cục lưu mẩu tin hoạt động khác Liên kết điều khiển: trỏ tới mẩu tin hoạt động chương trình gọi Các tham số thực tế: sử dụng chương trình gọi chương trình gọi Thơng thường tham số lưu ghi mẩu tin hoạt động Giá trị trả về: dùng chương trình gọi để trả cho chương trình gọi giá trị Trong thực tế giá trị thường trả ghi III CHIẾN LƯỢC CẤP PHÁT BỘ NHỚ Ðối với vùng nhớ khác tổ chức nhớ, ta có chiến lược cấp phát khác : Cấp phát tĩnh cho tất đối tượng liệu thời gian dịch 148 Cấp phát sử dụng Stack cho nhớ thời gian thực Ðối với vùng liệu Heap sử dụng cấp phát thu hồi dạng Heap Cấp phát tĩnh Trong cấp phát tĩnh, tên liên kết với vùng nhớ lúc chương trình dịch Vì mối liên kết khơng thay đổi thời gian chạy nên lần chương trình kích hoạt, tên liên kết với vùng nhớ Tính chất cho phép giá trị tên cục giữ lại thơng qua hoạt động chương trình Từ kiểu tên, trình biên dịch xác định kích thước nhớ Do trình biên dịch xác định vị trí mẩu tin kích hoạt đoạn mã chương trình mẩu tin kích hoạt khác Trong thời gian biên dịch, điền vào đoạn địa mà mã lệnh tìm đến để truy xuất liệu Tương tự địa vùng lưu trữ thông tin chương trình gọi xác định thời gian dịch Tuy nhiên cấp phát tĩnh có số hạn chế sau: Kích thước vị trí đối tượng liệu nhớ phải xác định thời gian dịch Không cho phép gọi đệ quy tất kích hoạt chương trình dùng chung liên kết tên cục Cấu trúc liệu khơng thể cấp phát động khơng có chế để cấp phát thời gian thực Cấp phát ô nhớ sử dụng Stack Bộ nhớ tổ chức Stack Các mẩu tin kích hoạt push vào Stack hoạt động bắt đầu pop khỏi Stack hoạt động kết thúc Ví dụ 7.4: Chúng ta minh họa việc cấp phát loại bỏ mẩu tin kích hoạt tương ứng với hoạt động chương trình sort: Cây hoạt động Mẩu tin kích hoạt Stack s a: array s s s a: array r r i: integer s r s a: array q(1,9) q(1,9) i: integer 149 s r s a: array q(1,9) q(1,9) i: integer p(1,9) q(1,3) p(1,3) q(1,3) q(1,0) q(2,3) i: integer q(2,3) i: integer Hình 7.9 - Sự cấp phát lọai bỏ mẩu tin kích hoạt Bộ nhớ cho liệu cục lần gọi chương trình chứa mẩu tin kích hoạt cho lần gọi Như tên cục liên kết với nhớ hoạt động, mẩu tin kích hoạt push vào Stack có lời gọi chương trình Dữ liệu biến cục bị xóa bỏ thực chương trình kết thúc Giả sử ghi top đánh dấu đỉnh Stack Tại thời gian thực mẩu tin kích hoạt cấp phát thu hồi cách tăng giảm ghi top bằịng kích thước mẩu tin kích hoạt Gọi thực chương trình Gọi chương trình thực lệnh gọi mã đích - lệnh gọi cấp phát mẩu tin kích hoạt đưa thông tin vào cho trường - lệnh trở phục hồi trạng thái máy để chương trình gọi tiếp tục thực Tham số giá trị trả Liên kết trạng thái máy Dữ liệu tạm cục Tham số trị trả Liên kết trạng thái máy top_sp Dữ liệu tạm cục Mẩu tin kích hoạt chương trình gọi Trách nhiệm chương trình gọi Mẩu tin kích hoạt chương trình bị gọi Trách nhiệm chương trình bị gọi Hình 7.10 - Phân chia cơng việc chương trình gọi chương trình bị gọi 150 Hình mơ tả mối quan hệ mẩu tin kích hoạt chương trình gọi chương trình bị gọi Mỗi mẩu tin có ba trường chủ yếu: tham số thực tế trị trả về, mối liên kết trạng thái máy cuối trường liệu tạm cục Thanh ghi top.sp đến cuối trường mối liên kết trạng thái máy Vị trí biết chương trình gọi Ðoạn mã cho chương trình bị gọi truy xuất liệu tạm cục cách sử dụng độ dời (offsets) từ top.sp Lệnh gọi thực công việc sau : Chương trình gọi đánh giá tham số thực tế Chương trình gọi lưu địa trả giá trị cũ top.sp vào mẩu tin kích hoạt chương trình bị gọi Sau tăng giá trị top.sp Chương trình gọi lưu giá trị ghi thông tin trạng thái khác Chương trình gọi khởi tạo liệu cục bắt đầu thực Lệnh trả thực công việc sau: Chương trình bị gọi gởi giá trị trả vào mẩu tin kích hoạt chương trình gọi Căn vào thông tin trường trạng thái, chương trình bị gọi khơi phục top_sp giá trị ghi truyền tới địa trả mã chương trình gọi Mặc dù top_sp bị giảm, chương trình gọi cần chép giá trị trả vào mẩu tin kích hoạt để sử dụng cho việc tính tốn biểu thức Dữ liệu có kích thước thay đổi Một số ngơn ngữ cho phép liệu có kích thước thay đổi Chẳng hạn chương trình p có mảng có kích thước thay đổi, mảng lưu trữ ngồi mẩu tin kích hoạt p Trong mẩu tin kích hoạt p chứa trỏ trỏ tới điểm bắt đầu mảng Ðịa tương đối trỏ biết thời gian dịch nên mã đích truy nhập tới phần tử mảng thơng qua trỏ Hình sau trình bày chương trình q gọi p Mẩu tin kích hoạt q nằm sau mảng p Truy nhập vào liệu Stack thông qua hai trỏ top, top.sp: top đỉnh Stack nơi mẩu tin kích hoạt bắt đầu top_sp dùng để tìm liệu cục 151 Các hoạt động Các mẩu tin kích hoạt Stack s s r q(1,9) Các mẩu tin kích hoạt Heap s q(1,9) Liên kết điều khiển r Liên kết điều khiển q(1,9) Liên kết điều khiển Hình 7.12 - Mẩu tin kích hoạt giữ lại Heap Về mặt vật lý, mẩu tin kích hoạt cho q(1,9) khơng phụ thuộc mẩu tin kích hoạt cho r Khi mẩu tin kích hoạt cho r bị giải phóng quản lý Heap dùng vùng nhớ tự để cấp phát cho mẩu tin khác Một số vấn đề thuộc quản lý hiệu Heap trình bày mục VIII IV TRUY XUẤT TÊN KHÔNG CỤC BỘ Quy tắc tầm vực Quy tắc tầm vực ngôn ngữ xác định việc xử lý tham khảo đến tên không cục Quy tắc tầm vực bao gồm hai loại: Quy tắc tầm tĩnh quy tắc tầm động Quy tắc tầm tĩnh (static - scope rule): Xác định khai báo áp dụng cho tên cách kiểm tra văn chương trình nguồn Các ngơn ngữ Pascal, C Ada sử dụng quy tắc tầm tĩnh với quy định bổ sung: “tầm gần nhất” Quy tắc tầm động (dynamic- scope rule): Xác định khai báo áp dụng cho tên thời gian thực cách xem xét hoạt động hành Các ngôn ngữ Lisp, APL Snobol sử dụng quy tắc tầm động Cấu trúc khối Một khối bắt đầu tập hợp khai báo cho tên (khai báo biến, định nghĩa kiểu, định nghĩa ) sau tập hợp lệnh mà tên tham khảo Cấu trúc khối thường sử dụng ngôn ngữ cấu trúc Pascal, Ada, PL/1 Trong chương trình hay chương trình tổ chức thành khối lồng 153 Ngôn ngữ cấu trúc khối sử dụng quy tắc tầm tĩnh Tầm khai báo cho quy tắc tầm gần (most closely nested) Một khai báo đầu khối xác định tên cục khối Bất kỳ tham khảo tới tên thân khối xem xét tham khảo tới liệu cục khối tồn Nếu tên x tham khảo thân khối B x không khai báo B x xem tham khảo tới khai báo B’ khối nhỏ chứa B Nếu B’ khơng có khai báo cho x lại tham khảo tới B’’ khối nhỏ chứa B’ Nếu khối chứa định nghĩa khối khác khai báo khối hoàn toàn bị che dấu khối ngồi Cấu trúc khối cài đặt cách sử dụng chế cấp phát Stack Khi điều khiển vào khối ô nhớ cho tên cấp phát chúng bị thu hồi điều khiển rời khỏi khối Tầm tĩnh với chương trình khơng lồng Quy tắc tầm tĩnh ngôn ngữ C đơn giản so với Pascal định nghĩa chương trình C khơng lồng Một chương trình C chuỗi khai báo biến hàm Nếu có tham khảo khơng cục đến tên a hàm a phải tham khảo bên tất hàm Tất tên khai báo bên ngồi hàm cấp phát tĩnh Vị trí nhớ biết thời gian dịch tham khảo tới tên không cục thân hàm xác định địa tuyệt đối Các tên cục hàm nằm mẩu tin hoạt động đỉnh Stack xác định cách sử dụng địa tương đối Tầm tĩnh với chương trình lồng Trong ngơn ngữ Pascal chương trình lồng nhiều cấp Ví dụ 7.5: Xét chương trình (1) program sort(input, output); (2) var a: array [0 10] of integer; (3) x : integer; (4) procedure readarray; (5) var y : integer; (6) begin a end; {readarray} (7) procedure exchange(i,j:integer); (8) begin (9) x:= a[i]; a[i] := a[j]; a[j] := x; (10) end; {exchange} (11) procedure quicksort(m,n:integer); (12) var k,v: integer; 154 (13) function partition(y,z: integer) : integer; (14) var i,j : integer; (15) begin a (16) .v (17) .exchange(i,j) (18) end; {partition} (19) begin end; {quicksort} (20) begin end; {sort} Hình 7.13 - Một chương trình Pascal với chương trình lồng Xét chương trình partition, tham khảo đến tên khơng cục như: a: Khai báo chương trình v: khai báo quicksort; exchange:khai báo chương trình Ðộ sâu lồng Chúng ta sử dụng thuật ngữ độ lồng sâu để tầm tĩnh Tên chương trình có độ sâu cấp tăng thêm từ chương trình vào chương trình bao (khai báo) Như chương trình partition, a có độ sâu cấp 1, v có độ sâu cấp 2, i có độ sâu cấp Quicksort có độ sâu cấp 2, partition có độ sâu cấp 3, exchange có độ sâu cấp Liên kết truy xuất Ðể cài đặt tầm tĩnh cho chương trình lồng ta dùng trỏ liên kết truy xuất mẩu tin kích hoạt Nếu chương trình p lồng trực tiếp q liên kết mẩu tin kích hoạt p trỏ tới liên kết truy xuất mẩu tin kích hoạt hành q Hình sau mơ tả nội dung Stack thực chương trình sort ví dụ Ví dụ 7.6: s s a,x a,x q(1,9) q(1,9) access link q(1,9) k,v access link q(1,3) access link k,v (a) k,v access link (b) k,v 155 s s a,x a,x q(1,9) q(1,9) k,v access link q(1,9) access k,v link q(1,3) q(1,3) k,v access link access link k,v k,v p(1,3) p(1,3) access link access link i,j i,j access link e(1,3) (c) (d) access link Hình 7.14 - Liên kết truy xuất cho phép tìm kiếm nhớ tên không cục Liên kết truy xuất s rỗng s khơng có bao đóng Liên kết truy xuất mẩu tin kích hoạt chương trình trỏ đến mẩu tin kích hoạt bao đóng Giả sử chương trình p có độ lồng sâu np tham khảo tới tên khơng cục a có độ lồng sâu na cần hạ hai cấp Từ p(1,3) hạ cấp đến q(1,3) theo liên kết truy xuất Từ q(1,3) hạ cấp đến s theo liên kết truy xuất đến s nơi a khai báo 156 Ðể xác định v cần tính np- nv = 3- = => cần hạ cấp xuốn q(1,3) nơi v khai báo Giả sử chương trình p có độ lồng sâu np gọi chương trình e độ lồng sâu ne Ðoạn mã để thiết lập liên kết truy xuất phụ thuộc vào việc chương trình gọi có định nghĩa chương trình gọi hay khơng? Trường hợp 1: np < ne: Chương trình e có độ lồng sâu lớn chương trình p e lồng p p tham khảo đến e (e bị che dấu khỏi p) Ví dụ sort gọi quickort, quicksort gọi partition Trường hợp 2: np >= ne: chương trình e có độ lồng sâu nhỏ độ lồng sâu chương trình p Theo quy tắc tầm tĩnh p tham khảo e Ví dụ quicksort gọi nó, partition gọi exchange Từ chương trình gọi np-ne +1 bước làm theo liên kết truy nhập ta tìm mẩu tin kích hoạt bao đóng gần chứa chương trình gọi chương trình gọi Chẳng hạn p(1,3) gọi e(1,3), np =3, ne =2 Ta phải làm - + hai bước theo liên kết truy xuất từ p đến s Display: để truy xuất nhanh tên không cục người ta dùng mảng d trỏ tới mẩu tin kích hoạt mảng gọi display Giả sử điều khiển nằm hoạt động chương trình t có độ lồng sâu j j-1 phần tử display trỏ tới mẩu tin kích hoạt bao đóng gần p d[j] trỏ tới kích hoạt p Một tên khơng cục a có độ sâu i nằm mẩu tin kích hoạt trỏ d[i] Ví dụ 7.8: s s d[1] d[1] d[2] q(1,9) d[2] q(1,9) saved d[2] saved d[2] (a) q(1,3) saved d[2] (b) 157 s d[1] d[2] d[3] q(1,9) saved d[2] s d[1] d[2] d[3] q(1,9) saved d[2] q(1,3) q(1,3) saved d[2] (d) (c) saved d[2] p(1,3) p(1,3) saved d[3] saved d[3] e(1,3) saved d[2] Hình 7.15 - Sử dụng display chương trình khơng truyền tham số (a): Tình trạng trước q(1,3) bắt đầu, quicksort có độ lồng sâu cấp 2, d[2] gửi cho mẩu tin kích hoạt quicksort bắt đầu Giá trị d[2] lưu mẩu tin kích hoạt q(1,9) (b): Khi q(1,3) bắt đầu d[2] trỏ tới mẩu tin kích hoạt mức ứng với q(1,3), giá trị d[2] lại lưu mẩu tin Giá trị cần thiết để phục hồi display cũ điều khiển trả cho q(1,9) Như mẩu tin kích họat đẩy vào Stack thì: - Lưu giá trị d[i] vào mẩu tin - Ðặt d[i] trỏ tới mẩu tin Khi mẩu tin pop khỏi Stack d[i] phục hồi Giả sử chương trình có độ lồng sâu cấp j gọi chương trình có độ lồng sâu cấp i Có hai trường hợp xảy phụ thuộc chương trình gọi có định nghĩa chương trình gọi hay khơng Trường hợp 1: j < i => i = j+1: thêm ô nhớ d[i], cấp phát mẩu tin kích hoạt cho chương trình i, ghi d[i] vào đặt d[i] trỏ tới (ví dụ 7.8a, 7.8c) Trường hợp 2: j >= i: Ghi giá trị cũ d[i] vào mẩu tin kích hoạt đặt d[i] trỏ vào mẩu tin cuối (ví dụ 7.8b 7.8d) Tầm động Với khái niệm tầm động, hoạt động kế thừa liên kết tồn tên không cục Tên không cục a hoạt động chương trình gọi tham khảo đến ô nhớ hoạt động chương trình gọi Ðối với tên cục liên kết thiết lập tới ô nhớ mẩu tin hoạt động 158 Ví dụ 7.9: Xét chương trình: (1) program dynamic (input, output); (2) var r : real; (3) procedure show; (4) begin write(r : : 3); end; (5) procedure small; (6) var r : real; (7) begin r := 0.125; show; end; (8) begin (9) r := 0.25; (10) show, small, writeln; (11) end; Hình 7.16 - Kết chương trình tùy thuộc vào tầm động hay tầm tĩnh sử dụng Kết thực chương trình: • Dưới tầm tĩnh; 0.250 0.250 • Dưới tầm động: 0.250 0.125 Khi show gọi dịng 10 chương trình 0.250 in r chương trình sử dụng Tuy nhiên show gọi dòng small 0.125 in r chương trình small sử dụng Cơ chế tầm động sử dụng liên kết điều khiển để tham khảo tên không cục Dynamic Dynamic r = 0.25 r = 0.25 show small control link control link r = 0.125 Show gọi dòng 10 tham khảo r= 0.25 show control link Show gọi dòng tham khảo r = 0.125 159 Hình 7.17 - Sử dụng liên kết điều khiển để tham khảo tên không cục V TRUYỀN THAM SỐ Khi chương trình gọi chương trình khác phương pháp thông thường để giao tiếp chúng thông qua tên không cục thông qua tham số chương trình gọi Ví dụ 7.10: Ðể đổi hai giá trị a[i] a[j] cho ta dùng (1) procedure exchange(i,j : integer); (2) var x : integer; (3) begin (4) (5) x := a[i]; a[i] := a[j]; a[j] := x; end; mảng a tên không cục i,j tham số Có nhiều phương pháp truyền tham số như: - Truyền giá trị (Transmision by value, call- by-value) - Truyền tham khảo (Transmision by name, call- by-name) Ở xét hai phương pháp phổ biến nhất: Truyền giá trị Là phương pháp đơn giản truyền tham số sử dụng C Pascal Truyền giá trị xử lý sau: Tham số hình thức xem tên cục nhớ tham số hình thức nằm mẩu tin kích hoạt chương trình gọi Chương trình gọi đánh giá tham số thực tế đặt giá trị chúng vào ô nhớ tham số hình thức Truyền tham chiếu (truyền địa hay truyền vị trí) Chương trình gọi truyền cho chương trình gọi trỏ tới địa tham số thực tế Ví dụ 7.11: (1) program reference (input, output) (2) var i: integer; (3) a: array[0 10] of integer; (4) procedure swap(var x, y: integer); (5) var temp : integer; (6) begin (7) temp := x; 160 (8) x := y; (9) y := temp; (10) end; (11) begin (12) i := 1; a[1] := 2; (13) swap(i,a[1]); (14) end; Hình 7.18 - Chương trình Pascal với thủ tục swap Với lời gọi dòng (13) ta có bước sau: Copy địa i a[ i] vào mẩu tin hoạt động swap thành arg1, arg2 tương ứng với x, y Ðặt temp nội dung vị trí trả arg1 tức temp := Bước tương ứng lệnh temp := x dòng (7) swap Ðặt nội dung vị trí trỏ arg1 giá trị vị trí trả arg2, tức i := a[1] Bước tương ứng lệnh x := y dòng (8) swap Ðặt nội dung vị trí trỏ arg2 giá trị temp Tức a[1] := i Bước tương ứng lệnh y := temp VI BẢNG KÝ HIỆU Chương trình dịch sử dụng bảng ký hiệu để lưu trữ thông tin tầm vực mối liên kết tên Bảng ký hiệu truy xuất nhiều lần tên xuất chương trình nguồn Có hai chế tổ chức bảng ký hiệu danh sách tuyến tính bảng băm Cấu trúc ô bảng ký hiệu Mỗi ô bảng ký hiệu tương ứng với tên Ðịnh dạng ô thường không giống thơng tin lưu trữ tên phụ thuộc vào việc sử dụng tên Thơng thường ô cài đặt mẩu tin Nếu muốn có đồng mẩu tin ta lưu thơng tin bên ngồi bảng ký hiệu, ô bảng chứa trỏ trỏ tới thơng tin đó, Trong bảng ký hiệu có lưu từ khóa ngơn ngữ Nếu chúng phải đưa vào bảng ký hiệu trước phân tích từ vựng bắt đầu Vấn đề lưu trữ lexeme danh biểu Các danh biểu ngơn ngữ lập trình thường có hai loại: Một số ngơn ngữ quy định độ dài danh biểu không vượt giới hạn Một số khác khơng giới hạn độ dài 161 Trường hợp danh biểu bị giới hạn độ dài chuỗi ký tự tạo nên danh biểu lưu trữ bảng ký hiệu Attribute Name s o r t e a d a r a r r a y i Hình 7.19 - Bảng ký hiệu lưu giữ tên bị giới hạn độ dài Trường hợp độ dài tên không bị giới hạn Lexeme lưu mảng riêng bảng ký hiệu giữ trỏ trỏ tới đầu Lexeme Name Attribute SymTable Lexeme s o r t eos a eos r e a d a r r a y eos i eos Hình 7.20 - Bảng ký hiệu lưu giữ tên không bị giới hạn độ dài Tổ chức bảng ký hiệu danh sách tuyến tính Cấu trúc đơn giản, dễ cài đặt cho bảng ký hiệu danh sách tuyến tính mẩu tin Ta dùng mảng nhiều mảng tương đương để lưu trữ tên thông tin kết hợp với chúng Các tên đưa vào danh sách theo thứ tự mà chúng phát Vị trí mảng đánh dấu trỏ available ô bảng tạo Việc tìm kiếm tên bảng ký hiệu available đến đầu bảng Trong ngôn ngữ cấu trúc khối sử dụng quy tắc tầm tĩnh Thông tin kết hợp với tên bao gồm thơng tin độ sâu tên Bằng cách tìm kiếm từ available trở đầu mảng đảm bảo tìm thấy tên tầng gần id1 info id2 info2 162 Hình 7.21 - Danh sách tuyến tính mẩu tin Tổ chức bảng ký hiệu bảng băm Kỹ thuật sử dụng bảng băm để cài đặt bảng ký hiệu thường sử dụng tính hiệu Cấu tạo bao gồm hai phần; bảng băm danh sách liên kết CP m match 20 last action ws 32 210 Hình 7.22 - Bảng băm có kích thước 211 Bảng băm mảng bao gồm m trỏ Bảng danh biểu chia thành m danh sách liên kết, danh sách liên kết trỏ phần tử bảng băm Việc phân bổ danh biểu vào danh sách liên kết hàm băm (hash function) quy định Giả sử s chuỗi ký tự xác định danh biểu, hàm băm h tác động lên s trả giá trị nằm m- h(s) = t => Danh biểu s đưa vào danh sách liên kết trỏ phần tử t bảng băm Có nhiều phương pháp để xác định hàm băm Phương pháp đơn giản sau: Giả sử s bao gồm ký tự c1, c2, c3, , ck Mỗi ký tự cho ứng với số nguyên dương n1, n2, n3, ,nk; lấy h = n1 + n2 + + nk Xác định h(s) = h mod m 163 BÀI TẬP CHƯƠNG VII 7.1 Hãy dùng quy tắc tầm vực ngôn ngữ Pascal để xác định tầm vực ý nghĩa khai báo cho lần xuất tên a, b chương trình sau Output chương trình số nguyên từ đến Program a ( input, output); Procedure b ( u, v, x, y : integer); Var a : record a, b : integer end; b : record a, b : integer end; begin With a begin a := u ; b := v end; With b begin a := x ; b := y end; Writeln ( a.a, a.b, b.a, b.b ); end; Begin B ( 1, 2, 3, 4) End 7.2 Chương trình sau in giá trị giả sử thông số truyền bằng: a) trị b) quy chiếu c) trị - kết d) tên Program main ( input, output); Procedure p ( x, y, z ); begin y := y + 1; z := z + x; end; Begin a := ; b := ; p (a +b ; a, a ) print a 164 End 7.3 Cho đoạn chương trình Algol sau : begin Procedure A ( px); procedure px { tham số hình thức px thủ tục } begin procedure B ( pz); procedure pz { tham số hình thức pz thủ tục } begin pz; end; B (px); end; procedure C; begin procedure D; begin end; A(D); end; C; end Hãy giải thích q trình thực thi chương trình trên, bước truyền tham số (giải thích hình ảnh Stack) 7.4 Cho đoạn chương trình sau: var a, b : integer; Procedure Var AB a, c : real; k, l : integer; procedure Var AC x, y : real; b : array [ 10] of integer; begin 165 end; begin end; begin end Hãy xây dựng bảng ký hiệu thao phương pháp sau: a) Danh sách tuyến tính b) Băm (hash), giả sử ta có kết hàm biến đổi băm sau: a = 3; b = 4; c = 4; k = 2; x = 4; y = 5; AB = 2; AC = 6; l = 3; 7.5 Cho đoạn chương trình sau: Program Var baitap; a : real; procedure Var sub1 ; x, y : real; begin end; procedure Var sub2 (t :integer); k : integer; procedure Var sub3 ; m : real; begin end; procedure Var t; x, y : real; begin end; 166 begin end Hãy vẽ bảng ký hiệu cho chương trình có trỏ trỏ đến bảng ký hiệu chương trình bị gọi có trỏ trỏ ngược lại bảng ký hiệu chương trình gọi 167 ... nguyên Chương trình chứa định nghĩa chương trình - Chương trình readarray từ dịng - 7, thân từ - - Chương trình partition từ dịng - 11, thân từ 10 - 11 - Chương trình quicksort từ dịng 12 - 20, thân... việc thực chương trình kết thúc • Thời gian tồn chương trình p chuỗi bước bước bước cuối thực thân chương trình bao gồm thời gian thực chương trình gọi p • Nếu a b hai hoạt động hai chương trình. .. từ 14 - 20 Chương trình xem chương trình có thân từ dịng 21 - 25 Khi tên chương trình xuất phần thân chương trình ta nói chương trình gọi điểm 143 Cây hoạt động Trong trình thực chương trình