Giáo trình cấu trúc trình biền dịch

207 490 0
Giáo trình cấu trúc trình biền dịch

Đ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

Để máy tính có thể hiểu và thực thi một chương trình được viết bằng ngôn ngữ cấp cao, ta cần phải có một trình biên dịch thực hiện việc chuyển đổi chương trình đó sang chương trình ở dạng ngôn ngữ đích. Chương này trình bày một cách tổng quan về cấu trúc của một trình biên dịch và mối liên hệ giữa nó với các thành phần khác “họ hàng” của nó như bộ tiền xử lý, bộ tải và soạn thảo liên kết,v.v. Cấu trúc của trình biên dịch được mô tả trong chương là một cấu trúc mức quan niệm bao gồm các giai đoạn: Phân tích từ vựng, Phân tích cú pháp, Phân tích ngữ nghĩa, Sinh mã trung gian, Tối ưu mã và Sinh mã đích

CHƯƠNG I GIỚI THIỆU VỀ SỰ BIÊN DỊCH Nội dung chính: Để máy tính hiểu thực thi chương trình viết ngôn ngữ cấp cao, ta cần phải có trình biên dịch thực việc chuyển đổi chương trình sang chương trình dạng ngôn ngữ đích Chương trình bày cách tổng quan cấu trúc trình biên dịch mối liên hệ với thành phần khác - “họ hàng” - tiền xử lý, tải soạn thảo liên kết,v.v Cấu trúc trình biên dịch mô tả chương cấu trúc mức quan niệm bao gồm giai đoạn: Phân tích từ vựng, Phân tích cú pháp, Phân tích ngữ nghĩa, Sinh mã trung gian, Tối ưu mã Sinh mã đích Mục tiêu cần đạt: Sau học xong chương này, sinh viên phải nắm cách tổng quan nhiệm vụ thành phần trình biên dịch, mối liên hệ thành phần môi trường nơi trình biên dịch thực công việc Tài liệu tham khảo: [1] Trình Biên Dịch - Phan Thị Tươi (Trường Ðại học kỹ thuật Tp.HCM) - NXB Giáo dục, 1998 [2] Compilers : Principles, Technique and Tools - Alfred V.Aho, Jeffrey D.Ullman - Addison - Wesley Publishing Company, 1986 [3] Compiler Design – Reinhard Wilhelm, Dieter Maurer - Addison - Wesley Publishing Company, 1996 I TRÌNH BIÊN DỊCH Nói cách đơn giản, trình biên dịch chương trình làm nhiệm vụ đọc chương trình viết ngôn ngữ - ngôn ngữ nguồn (source language) - dịch thành chương trình tương đương ngôn ngữ khác - ngôn ngữ đích (target languague) Một phần quan trọng trình dịch ghi nhận lại lỗi có chương trình nguồn để thông báo lại cho người viết chương trình Chương trình nguồn Trình biên dịch Chương trình đích Hình 1.1 - Một trình biên dịch Mô hình phân tích - tổng hợp trình biên dịch Chương trình dịch thường bao gồm hai trình : phân tích tổng hợp - Phân tích → đặc tả trung gian - Tổng hợp → chương trình đích Chương trình nguồn Phán Phân tích Phán têch têch Tổng hợp Đặc tả trung gian Chương trình đích Hình 1.2 - Mô hình phân tích - tổng hợp Trong trình phân tích chương trình nguồn phân rã thành cấu trúc phân cấp, thường dạng - cú pháp (syntax tree) mà có nút toán tử nhánh toán hạng Ví dụ 1.1: Cây cú pháp cho câu lệnh gán position := initial + rate * 60 := position + initial * rate 60 Môi trường trình biên dịch Ngoài trình biên dịch, cần dùng nhiều chương trình khác để tạo chương trình đích thực thi (executable) Các chương trình gồm: Bộ tiền xử lý, Trình dịch hợp ngữ, Bộ tải soạn thảo liên kết Một chương trình nguồn phân thành module lưu tập tin riêng rẻ Công việc tập hợp lại tập tin thường giao cho chương trình riêng biệt gọi tiền xử lý (preprocessor) Bộ tiền xử lý "bung" ký hiệu tắt gọi macro thành câu lệnh ngôn ngữ nguồn Ngoài ra, chương trình đích tạo trình biên dịch cần phải xử lý thêm trước chúng chạy Thông thường, trình biên dịch tạo mã lệnh hợp ngữ (assembly code) để trình dịch hợp ngữ (assembler) dịch thành dạng mã máy liên kết với số thủ tục thư viện hệ thống thành mã thực thi máy Hình sau trình bày trình biên dịch điển hình : Chương trình nguồn khung Bộ tiền xử lý Chương trình nguồn Trình biên dịch Chương trình đích hợp ngữ Trình dịch hợp ngữ Mã máy khả tái định vị Trình tải / Liên kết Thư viện, Tập tin đối tượng khả tái định vị Mã máy tuyệt đối Hình 1.3 - Một trình xử lý ngôn ngữ điển hình II SỰ PHÂN TÍCH CHƯƠNG TRÌNH NGUỒN Phần giới thiệu trình phân tích cách dùng thông qua số ngôn ngữ định dạng văn Phân tích từ vựng (Lexical Analysis) Trong trình biên dịch, giai đọan phân tích từ vựng đọc chương trình nguồn từ trái sang phải (quét nguyên liệu - scanning) để tách thành thẻ từ (token) Ví dụ 1.2: Quá trình phân tích từ vựng cho câu lệnh gán position := initial + rate * 60 tách thành token sau: Danh biểu position Ký hiệu phép gán := Danh biểu initial Ký hiệu phép cộng (+) Danh biểu rate Ký hiệu phép nhân (*) Số 60 Trong trình phân tích từ vựng khoảng trắng (blank) bị bỏ qua Phân tích cú pháp (Syntax Analysis) Giai đoạn phân tích cú pháp thực công việc nhóm thẻ từ chương trình nguồn thành ngữ đoạn văn phạm (grammatical phrase), mà sau trình biên dịch tổng hợp thành phẩm Thông thường, ngữ đoạn văn phạm biểu diễn dạng phân tích cú pháp (parse tree) với : - Ngôn ngữ đặc tả luật sinh - Phân tích cú pháp dựa vào luật sinh để xây dựng phân tích cú pháp Ví dụ 1.3: Giả sử ngôn ngữ đặc tả luật sinh sau : Stmt → id := expr expr → expr + expr | expr * expr | id | number Với câu nhập: position := initial + rate * 60, phân tích cú pháp xây dựng sau : Stmt id expr := position expr + expr id expr expr initial id number rate Hình 1.4 - Một phân tích cú pháp 60 Cấu trúc phân cấp chương trình thường diễn tả quy luật đệ qui Ví dụ 1.4: 1) Danh biểu (identifier) biểu thức (expr) 2) Số (number) biểu thức 3) Nếu expr1 expr2 biểu thức thì: expr1 + expr2 expr1 * expr2 (expr) biểu thức Câu lệnh (statement) định nghĩa đệ qui : 1) Nếu id1 danh biểu expr2 biểu thức id1 := expr2 lệnh (stmt) 2) Nếu expr1 biểu thức stmt2 lệnh while (expr1) stmt2 if (expr1) then stmt2 lệnh Người ta dùng qui tắc đệ qui để đặc tả luật sinh (production) cho ngôn ngữ Sự phân chia trình phân tích từ vựng phân tích cú pháp tuỳ theo công việc thực Phân tích ngữ nghĩa (Semantic Analysis) Giai đoạn phân tích ngữ nghĩa thực việc kiểm tra xem chương trình nguồn có chứa lỗi ngữ nghĩa hay không tập hợp thông tin kiểu cho giai đoạn sinh mã sau Một phần quan trọng giai đoạn phân tích ngữ nghĩa kiểm tra kiểu (type checking) ép chuyển đổi kiểu Ví dụ 1.5: Trong biểu thức position := initial + rate * 60 Các danh biểu (tên biến) khai báo real, 60 số integer trình biên dịch đổi số nguyên 60 thành số thực 60.0 := + position * initial 60 rate thành := + position * initial rate inttoreal 60.0 Hình 1.5 - Chuyển đổi kiểu phân tích cú pháp III CÁC GIAI ÐOẠN BIÊN DỊCH Ðể dễ hình dung, trình biên dịch chia thành giai đoạn, giai đoạn chuyển chương trình nguồn từ dạng biểu diễn sang dạng biểu diễn khác Một cách phân rã điển hình trình biên dịch trình bày hình sau Chương trình nguồn Phân tích từ vựng Phân tích cú pháp Phân tích ngữ nghĩa Quản lý bảng ký hiệu Xử lý lỗi Sinh mã trung gian Tối ưu mã Sinh mã đích Chương trình đích Hình 1.6 - Các giai đoạn trình biên dịch Việc quản lý bảng ký hiệu xử lý lỗi thực xuyên suốt qua tất giai đoạn Quản lý bảng ký hiệu Một nhiệm vụ quan trọng trình biên dịch ghi lại định danh sử dụng chương trình nguồn thu thập thông tin thuộc tính khác định danh Những thuộc tính cung cấp thông tin vị trí lưu trữ cấp phát cho định danh, kiểu tầm vực định danh, định danh tên thủ tục thuộc tính thông tin số lượng kiểu đối số, phương pháp truyền đối số kiểu trả thủ tục có Bảng ký hiệu (symbol table) cấu trúc liệu mà phần tử mẩu tin dùng để lưu trữ định danh, bao gồm trường lưu giữ ký hiệu thuộc tính Cấu trúc cho phép tìm kiếm, truy xuất danh biểu cách nhanh chóng Trong trình phân tích từ vựng, danh biểu tìm thấy đưa vào bảng ký hiệu nói chung thuộc tính chưa xác định giai đoạn Ví dụ 1.6: Chẳng hạn, khai báo Pascal có dạng var position, initial, rate : real thuộc tính kiểu real chưa thể xác định danh biểu xác định đưa vào bảng ký hiệu Các giai đoạn sau phân tích ngữ nghĩa sinh mã trung gian đưa thêm thông tin vào sử dụng chúng Nói chung giai đoạn sinh mã thường đưa thông tin chi tiết vị trí lưu trữ dành cho định danh sử dụng chúng cần thiết Bảng ký hiệu position initial rate Xử lý lỗi Mỗi giai đoạn gặp nhiều lỗi, nhiên sau phát lỗi, tùy thuộc vào trình biên dịch mà có cách xử lý lỗi khác nhau, chẳng hạn : - Dừng thông báo lỗi gặp lỗi (Pascal) - Ghi nhận lỗi tiếp tục trình dịch (C) Giai đoạn phân tích từ vựng thường gặp lỗi ký tự ghép thành token Giai đoạn phân tích cú pháp gặp lỗi token kết hợp với theo cấu trúc ngôn ngữ Giai đoạn phân tích ngữ nghĩa báo lỗi toán hạng có kiểu không yêu cầu phép toán hay kết cấu nghĩa thao tác thực chúng hoàn toàn mặt cú pháp Các giai đoạn phân tích Giai đoạn phân tích từ vựng: Ðọc ký tự gộp lại thành token, token danh biểu, từ khóa, ký hiệu, Chuỗi ký tự tạo thành token gọi lexeme - trị từ vựng token Ví dụ 1.7: Danh biểu rate có token id, trị từ vựng rate danh biểu đưa vào bảng ký hiệu chưa có Giai đoạn phân tích cú pháp phân tích ngữ nghĩa: Xây dựng cấu trúc phân cấp cho chuỗi token, biểu diễn cú pháp kiểm tra ngôn ngữ theo cú pháp Ví dụ 1.8: Cây cú pháp cấu trúc lưu trữ cho biểu thức position := initial + rate * 60 := := + id1 id * id2 + id id3 60 id * num 60 Hình 1.7 - Cây cú pháp cấu trúc lưu trữ Sinh mã trung gian Sau phân tích ngữ nghĩa, số trình biên dịch tạo dạng biểu diễn trung gian chương trình nguồn Chúng ta xem dạng biểu diễn chương trình dành cho máy trừu tượng Chúng có đặc tính quan trọng : dễ sinh dễ dịch thành chương trình đích Dạng biểu diễn trung gian có nhiều loại Thông thường, người ta sử dụng dạng "mã máy địa chỉ" (three-address code), tương tự dạng hợp ngữ cho máy mà vị trí nhớ đóng vai trò ghi Mã máy địa dãy lệnh liên tiếp, lệnh có tối đa đối số Ví dụ 1.9: t1 := inttoreal (60) t2 := id3 * t1 t3 := id2 + t2 id1 := t3 Dạng trung gian có số tính chất: - Mỗi lệnh chứa nhiều toán tử Do tạo lệnh này, trình biên dịch phải xác định thứ tự phép toán, ví dụ * thực trước + - Trình biên dịch phải tạo biến tạm để lưu trữ giá trị tính toán cho lệnh - Một số lệnh có toán hạng Tối ưu mã Giai đoạn tối ưu mã cố gắng cải thiện mã trung gian để có mã máy thực nhanh Một số phương pháp tối ưu hóa hoàn toàn bình thường Ví dụ 1.10: Mã trung gian nêu tối ưu thành: t1 := id3 * 60.0 id1 := id2 + t1 Ðể tối ưu mã, ta thấy việc đổi số nguyên 60 thành số thực 60.0 thực lần vào lúc biên dịch, loại bỏ phép toán inttoreal Ngoài ra, t3 dùng lần để chuyển giá trị cho id1 nên giảm bớt Có khác biệt lớn khối lượng tối ưu hoá mã trình biên dịch khác thực Trong trình biên dịch gọi "trình biên dịch chuyên tối ưu", phần thời gian đáng kể dành cho giai đoạn Tuy nhiên, có phương pháp tối ưu giúp giảm đáng kể thời gian chạy chương trình nguồn mà không làm chậm thời gian dịch nhiều Sinh mã Giai đoạn cuối biên dịch sinh mã đích, thường mã máy mã hợp ngữ Các vị trí vùng nhớ chọn lựa cho biến chương trình sử dụng Sau đó, thị trung gian dịch thành chuỗi thị mã máy Vấn đề định việc gán biến cho ghi Ví dụ 1.11: Sử dụng ghi (chẳng hạn R1, R2) cho việc sinh mã đích sau: MOVF id3, R2 MULF #60.0, R2 MOVF id2, R1 ADDF R2, R1 MOVF R1, id1 Toán hạng thứ thứ hai thị tương ứng mô tả đối tượng nguồn đích Chữ F thị cho biết thị xử lý số chấm động (floating_point) Dấu # để xác định số 60.0 xem số Ví dụ Xem hình vẽ 1.8 (trang 10) mô tả giai đoạn biên dịch cho biểu thức: position := initial + rate * 60 IV NHÓM CÁC GIAI ÐOẠN Các giai đoạn mà đề cập thực theo trình tự logic trình biên dịch Nhưng thực tế, cài đặt hoạt động nhiều giai đoạn nhóm lại với Thông thường chúng nhóm thành hai nhóm bản, gọi là: kỳ đầu (Front end) kỳ sau (Back end) Kỳ đầu (Front End) Kỳ đầu bao gồm giai đoạn phần giai đoạn phụ thuộc nhiều vào ngôn ngữ nguồn độc lập với máy đích Thông thường, chứa giai đoạn sau: Phân tích từ vựng, Phân tích cú pháp, Phân tích ngữ nghĩa Sinh mã trung gian Một phần công việc tối ưu hóa mã thực kỳ đầu Front end bao gồm việc xử lý lỗi xuất giai đoạn Kỳ sau (Back End) Kỳ sau bao gồm số phần trình biên dịch phụ thuộc vào máy đích nói chung phần không phụ thuộc vào ngôn ngữ nguồn mà ngôn ngữ trung gian Trong kỳ sau, gặp số vấn đề tối ưu hoá mã, phát sinh mã đích với việc xử lý lỗi thao tác bảng ký hiệu position := initial + rate * 60 Phân tích từ vựng id1 := id2 + id3 * 60 := Phân tích cú pháp + id1 id2 * 60 id3 := Phân tích ngữ nghĩa + id1 * id2 id3 Sinh mã trung gian Tối ưu hóa mã Phát sinh mã đích inttoreal t1 := inttoreal (60) t2:= id3 * t1 t3 := id2 + t2 id1 := t3 60.0 t1 := id3 * 60.0 id1 := id2 + t1 MOVF MULF MOVF ADDF MOVF id3, R2 #60.0, R2 id2, R1 R2, R1 R1, id1 Hình 1.8 - Minh họa giai đoạn biên dịch biểu thức 10 mẩu tin hoạt động Như ta nói chương VII, mẩu tin hoạt động cho thủ tục có trường: tham số, kết quả, thông tin trạng thái máy, liệu cục bộ, lưu trữ tạm thời cục bộ, liên kết Trong phần này, ta minh họa chiến lược cấp phát sử dụng trường trạng thái để giữ giá trị trả liệu cục bộ, trường lại dùng đề cập chương VII Việc cấp phát giải phóng mẩu tin hoạt động phần chuỗi hành vi gọi trả chương trình Ta quan tâm đến việc sinh mã cho lệnh sau: call return halt action /* tượng trưng cho lệnh khác */ Chẳng hạn, mã ba địa chỉ, chứa loại câu lệnh trên, cho chương trình c p mẩu tin hoạt động chúng: /* mã cho s */ action1 call p action2 halt /* mã cho c */ action3 return Bảng mã 0: Địa trả 0: Địa trả 8: arr 4: buf 56: i 60: i Bảng ghi hoạt động cho c 84: n Bảng ghi hoạt động cho p Hình 9.2 – Dữ liệu vào sinh mã Kích thước việc xếp đặt mẩu tin kết hợp với sinh mã nhờ thông tin tên bảng danh biểu Ta giả sử nhớ thời gian thực phân chia thành vùng cho mã, liệu tĩnh Stack Cấp phát tĩnh Chúng ta xét thị cần thiết để thực việc cấp phát tĩnh Lệnh call mã trung gian thực dãy hai thị đích Chỉ thị MOV lưu địa trả Chỉ thị GOTO chuyển quyền điều khiển cho chương trình gọi MOV # here + 20, callee.static_area GOTO callee.code_area Các thuộc tính callee.static_area callee.code_area tham chiếu tới địa mẩu tin hoạt động thị đoạn mã chương trình gọi # here + 20 thị MOV địa trả Nó địa thị đứng sau lệnh GOTO Mã chương trình kết thúc lệnh trả chương trình gọi, trừ chương trình chính, lệnh halt Lệnh trả quyền điều khiển cho hệ điều hành Lệnh trả dịch sang mã máy GOTO *callee_static_area thực việc chuyển quyền điều khiển địa lưu giữ ô nhớ mẩu tin hoạt động 192 Ví dụ 9.1: Mã đích chương trình sau tạo từ chương trình c p hình 9.2 Giả sử rằng: mã lưu địa bắt đầu 100 200, thị action chiếm 20 byte, mẩu tin hoạt động cho c p cấp phát tĩnh bắt đầu địa 300 364 Ta dùng thị action để thực câu lệnh action Như vậy, mã đích cho chương trình con: /* mã cho c*/ 100: ACTION1 120: MOV #140, 364 /* lưu địa trả 140 */ 132: GOTO 200 /* gọi p */ 140: ACTION2 160: HALT /* mã cho p */ 200: ACTION3 220: GOTO *364 /* trả địa lưu vị trí 364 */ /* 300-364 lưu mẩu tin hoạt động c */ 300: /* chứa địa trả */ 304: /* liệu cục c */ /* 364 - 451 chứa mẩu tin hoạt động p */ 364: /* chứa địa trả */ 368: /* liệu cục p */ Hình 9.3 - Mã đích cho liệu vào hình 9.2 Sự thực bắt đầu thị action địa 100 Chỉ thị MOV địa 120 lưu địa trả 140 vào trường trạng thái máy, từ mẩu tin hoạt động p Chỉ thị GOTO 200 chuyển quyền điều khiển thị đoạn mã chương trình p Chỉ thị GOTO *364 địa 132 chuyển quyền điều khiển sang thị mã đích chương trình gọi Giá trị 140 lưu vào địa 364, *364 biểu diễn giá trị 140 lệnh GOTO địa 220 thực Vì quyền điều khiển trả địa 140 tiếp tục thực chương trình c Cấp phát theo chế Stack Cấp phát tĩnh trở thành cấp phát Stack ta sử dụng địa tương đối để lưu giữ mẩu tin hoạt động Vị trí mẩu tin hoạt động xác định thời gian thực thi Trong cấp phát Stack, vị trí thường lưu vào ghi Vì ô nhớ mẩu tin hoạt động truy xuất độ dời (offset) so với giá trị ghi Thanh ghi SP chứa địa bắt đầu mẩu tin hoạt động chương trình nằm đỉnh Stack Khi lời gọi chương trình xuất hiện, chương trình bị gọi cấp phát, SP tăng lên giá trị kích thước mẩu tin hoạt động chương trình gọi chuyển quyền điều khiển cho chương trình gọi Khi quyền điều khiển trả cho chương trình gọi, SP giảm khoảng kích thước mẩu tin hoạt động chương trình gọi Vì thế, mẩu tin chương trình gọi giải phóng Mã cho chương trình có dạng: 193 MOV # Stackstart, SP /* khởi động Stack */ Ðoạn mã cho chương trình HALT /* kết thúc thực thi */ Trong thị MOV #Stackstart, SP khởi động Stack theo cách đặt SP với địa bắt đầu Stack vùng nhớ Chuỗi gọi tăng giá trị SP, lưu giữ địa trả chuyển quyền điều khiển chương trình gọi ADD # caller.recordsize, SP MOV # here + 16, *SP /* lưu địa trả */ GOTO callee.code_area Thuộc tính caller.recordsize biểu diễn kích thước mẩu tin hoạt động Vì thế, thị ADD đưa SP trỏ tới phần bắt đầu mẩu tin hoạt động #here +16 thị MOV địa thị theo sau GOTO, lưu địa trỏ SP Chuỗi trả gồm hai thị: Chương trình chuyển quyền điều khiển tới địa trả GOTO *0(SP) /* trả chương trình gọi */ SUB #caller.recordsize, SP Trong O(SP) địa ô nhớ mẩu tin hoạt động *O(SP) trả địa lưu Chỉ thị SUB #caller.recordsize, SP: Giảm giá trị SP xuống khoảng kích thước mẩu tin hoạt động chương trình gọi Như mẩu tin hoạt động chương trình bị gọi xóa khỏi Stack Ví dụ 9.2: Giả sử kích thước mẩu tin hoạt động chương trình s, p, q xác định thời gian biên dịch ssize, psize, qsize tương ứng Ô nhớ mẩu tin hoạt động lưu địa trả Ta giả sử rằng, đoạn mã cho chương trình bắt đầu địa 100, 200, 300 tương ứng, địa bắt đầu Stack 600 Mã đích cho chương trình hình 9.4 mô tả hình 9.5: 194 Hình 9.4 - Mã ba địa minh hoạ cấp phát sử dụng Stack /* mã cho s */ action1 call q action2 halt /* mã cho p */ action3 return /* mã cho q */ action4 call p action5 call q action6 call q return /* mã cho s*/ 100: MOV # 600, SP /* khởi động Stack */ 108: ACTION1 128: ADD #ssize, SP /* chuỗi gọi bắt đầu */ 136: MOV #152, *SP /* lưu địa trả */ 144: GOTO 300 152: SUB #ssize, SP /* gọi q */ /* Lưu giữ SP */ 160: ACTION2 180: HALT /* mã cho p */ 200: ACTION3 220: GOTO *0(SP) /* trả chương trình gọi */ /* mã cho q */ 300: ACTION4 320: ADD #qsize, SP 328: MOV #344, *SP 336: GOTO 200 344: SUB /* nhảy có điều kiện 456 */ /* lưu địa trả */ /* gọi p */ #qsize, SP 352: ACTION5 372: ADD #qsize, SP 380: MOV #396, *SP /* lưu địa trả */ 195 388: GOTO 300 /* gọi q */ 396: SUB #qsize, SP 404: ACTION6 424: ADD #qsize, SP 432: MOV #448, *SP /* lưu địa trả */ 440: GOTO 300 /* gọi q */ 448: SUB #qsize, SP 456: GOTO *0(SP) /* trả chương trình gọi */ 600: /* địa bắt đầu Stack trung tâm */ Hình 9.5 - Mã đích cho chuỗi ba địa hình 9.4 Ta giả sử action4 gồm lệnh nhảy có điều kiện tới địa 456 có lệnh trả từ q Ngược lại chương trình đệ quy q gọi Trong ví dụ giả sử lần gọi q không trả chương trình gọi ngay, lần sau SP có giá trị lúc đầu 600, địa bắt đầu Stack SP lưu giữ giá trị 620 trước chuyển quyền điều khiển từ s sang q kích thước mẩu tin hoạt động s 20 Khi q gọi p, SP tăng lên 680 thị địa 320 thực hiện, Sp chuyển sang 620 sau chuyển quyền điều khiển cho chương trình p Nếu lời gọi đệ quy q trả giá trị lain SP suốt trình thực 680 Vị trí cấp phát theo chế Stack lên đến địa 739 mẩu tin hoạt động q bắt đầu 680 chiếm 60 byte Ðịa tên thời gian thực Chiến lược cấp phát lưu trữ xếp đặt liệu cục mẩu tin hoạt động chương trình xác định cách thức truy xuất vùng nhớ tên Nếu dùng chế cấp phát tĩnh với vùng liệu cấp phát địa static Với lệnh gán x := 0, địa tương đối x bảng danh biểu 12 Vậy địa x nhớ static + 12 Lệnh gán x:=0 chuyển sang mã ba địa static[12] := Nếu vùng liệu bắt đầu địa 100, mã đích cho thị là: MOV #0,112 Nếu ngôn ngữ dùng chế display để truy xuất tên không cục bộ, giả sử x tên cục chương trình hành ghi R3 lưu giữ địa bắt đầu mẩu tin hoạt động dịch lệnh x := sang chuỗi mã ba địa chỉ: t1 := 12 + R3 * t1 := Từ ta chuyển sang mã đích: MOV #0, 12(R3) Chú ý rằng, giá trị ghi R3 không xác định thời gian biên dịch 196 IV KHỐI CƠ BẢN VÀ LƯU ÐỒ Ðồ thị biểu diễn lệnh ba địa chỉ, gọi lưu đồ, giúp ta hiểu giải thuật sinh mã đồ thị không xác định cụ thể giải thuật sinh mã Các nút lưu đồ biểu diễn tính toán, cạnh biểu diễn dòng điều khiển Khối Khối (basic block) chuỗi lệnh dòng điều khiển vào lệnh khối lệnh cuối khối mà không bị dừng rẽ nhánh Ví dụ chuỗi lệnh ba địa sau tạo nên khối t1 := a * a t2 := a * b t3 := * t2 t4 := t1 + t2 t5 := b * b t6 := t4 + t5 Lệnh ba địa x := y + z dùng giá trị chứa vị trí nhớ y, z để thực phép cộng xác định địa x để lưu kết phép cộng vào Một tên khối gọi ‘sống‘ điểm giá trị sử dụng sau điểm chương trình dùng khối khác Giải thuật sau phân chia chuỗi lệnh ba địa sang khối ‰ Giải thuật 9.1: Phân chia khối Input: Các lệnh ba địa Output: Danh sách khối với chuỗi lệnh ba địa cho khối Phương pháp: Xác định tập lệnh dẫn đầu (leader), lệnh khối bản, ta dùng quy tắc sau: i) Lệnh lệnh dẫn đầu ii) Bất kỳ lệnh đích nhảy đến lệnh GOTO có điều kiện không điều kiện lệnh dẫn đầu iii) Bất kỳ lệnh sau lệnh GOTO có điều kiện không điều kiện lệnh dẫn đầu Với lệnh dẫn đầu, khối gồm có tất lệnh không gồm lệnh dẫn đầu khác lệnh kết thúc chương trình Ví dụ 9.3: Ðoạn chương trình sau tính tích vectơ vô hướng hai vectơ a b có độ dài 20 Begin prod := i := Repeat prod: = prod + a [i] * b[i]; 197 i := i + Until i > 20 End Hình 9.6 - Chương trình tính tích vectơ vô hướng Ðoạn chương trình dịch sang mã ba địa sau: (1) prod := (2) i := (3) t1 := * i (4) t2 := a[t1] (5) t3 := * i (6) t4 := b[t3] (7) t5 := t2 * t4 (8) t6 := prod + t5 (9) prod := t6 (10) t7 := i + (11) i := t7 (12) if i=,, [...]... II DỊCH TRỰC TIẾP CÚ PHÁP (Syntax - Directed Translation) Ðể dịch một kết cấu ngôn ngữ lập trình, trong quá trình dịch, bộ biên dịch cần lưu lại nhiều đại lượng khác cho việc sinh mã ngoài mã lệnh cần tạo ra cho kết cấu Chẳng hạn nó cần biết kiểu (type) của kết cấu, địa chỉ của lệnh đầu tiên trong mã đích, số lệnh phát sinh,v.v Vì vậy ta nói một cách ảo về thuộc tính (attribute) đi kèm theo kết cấu. .. trực tiếp cú pháp (syntax - directed definition) nhằm đặc tả việc phiên dịch các kết cấu ngôn ngữ lập trình theo các thuộc tính đi kèm 15 với thành phần cú pháp của nó Chúng ta cũng sẽ sử dụng một thuật ngữ có tính thủ tục hơn là lược đồ dịch (translation scheme) để đặc tả quá trình dịch Trong chương này, ta sử dụng lược đồ dịch để dịch một biểu thức trung tố thành dạng hậu tố 1 Ký pháp hậu tố (Postfix... phần cấu tạo nên trình biên dịch đơn giản • Hoạt động và cách cài đặt các giai đoạn của kỳ trước của một trình biên dịch đơn giản • Cách sử dụng máy trừu tượng kiểu stack để chuyển đổi các biểu thức hậu tố sang mã máy ảo và cách thực thi các đoạn mã ảo này để có được kết quả cuối cùng Kiến thức cơ bản Để tiếp nhận các nội dung được trình bày trong chương 2, sinh viên phải: • Biết một ngôn ngữ lập trình. .. trong chương 2, sinh viên phải: • Biết một ngôn ngữ lập trình nào đó: C, Pascal, v.v để hiểu cách cài đặt trình biên dịch • Có kiến thức về cấu trúc dữ liệu để hiểu cách tổ chức dữ liệu khi thực hiện cài đặt Tài liệu tham khảo: [1] Trình Biên Dịch - Phan Thị Tươi (Trường Ðại học kỹ thuật Tp.HCM) - NXB Giáo dục, 1998 [2] Compilers : Principles, Technique and Tools - Alfred V.Aho, Jeffrey D.Ullman - Addison... trước khi cây con rest1 được thăm 6 Phát sinh bản dịch (Emitting a Translation) Trong chương này, hành vi ngữ nghĩa trong lược đồ dịch sẽ ghi kết quả của quá trình phiên dịch vào một tập tin, mỗi lần một chuỗi hoặc một ký tự Chẳng hạn, khi dịch 9 - 5 + 2 thành 9 5 - 2 + bằng cách ghi mỗi ký tự trong 9 - 5 + 2 đúng một lần mà không phải ghi lại quá trình dịch của các biểu thức con Khi tạo ra output dần... term → 9 { print(‘9’) } Hình sau đây mô tả quá trình dịch biểu thức 9 - 5 + 2 dựa vào lược đồ dịch trên: expr term 9 rest { print(‘9’) } - 5 term { print(‘-’) } { print(‘5’) } Hình 2.11 - Dịch 9 - 5+2 thành 9 5- 2+ rest + term { print(+’) } rest 2 { print(‘2’) } ε Bây giờ ta cài đặt chương trình dịch bằng C theo đặc tả như trên Phần chính của chương trình này là các đoạn mã C cho các hàm expr, term... } } } /* while */ /* lexan */ VI SỰ HÌNH THÀNH BẢNG KÝ HIỆU Một cấu trúc dữ liệu gọi là bảng ký hiệu (symbol table) thường được dùng để lưu giữ thông tin về các cấu trúc của ngôn ngữ nguồn Các thông tin này được tập hợp từ các giai đoạn phân tích của trình biên dịch và được sử dụng bởi giai đoạn tổng hợp để sinh mã đích Ví dụ trong quá trình phân tích từ vựng, các chuỗi ký tự tạo ra một token (trị từ... nút n; end 5 Lược đồ dịch (Translation Scheme) Một lược đồ dịch là một văn phạm phi ngữ cảnh, trong đó các đoạn chương trình gọi là hành vi ngữ nghĩa (semantic actions) được gán vào vế phải của luật sinh Lược đồ dịch cũng như định nghĩa trực tiếp cú pháp nhưng thứ tự đánh giá các quy tắc ngữ nghĩa được trình bày một cách rõ ràng Vị trí mà tại đó một hành vi được thực hiện được trình bày trong cặp dấu... lặp dễ dàng bằng lệnh break Ðoạn chương trình có thể được viết lại như sau : expr ( ) { term ( ) while (1) if (lookahead = = ‘+’ ) { match(‘+’) ; term( ) ; putchar (‘+ ‘) ; } else if (lookahead = = ‘-’) { match(‘-’) ; term( ) ; putchar (‘-’) ; } else break; } Chương trình C dịch biểu thức trung tố sang hậu tố Chương trình nguồn C hoàn chỉnh cho chương trình dịch có mã như sau : # include< ctype.h>...CHƯƠNG II MỘT TRÌNH BIÊN DỊCH ÐƠN GIẢN Nội dung chính: Chương này giới thiệu một trình biên dịch cho các biểu thức số học đơn giản (trình biên dịch đơn giản) gồm hai kỳ: Kỳ đầu (Front end) và kỳ sau (Back end) Nội dung chính của chương tập trung vào kỳ đầu gồm các giai đoạn: Phân

Ngày đăng: 11/10/2016, 09:15

Tài liệu cùng người dùng

Tài liệu liên quan