Nếu các tập tin được dùng chung với nhau một cách hiệu quá thì cĩ thể phải dùng đến một số ¿ham chiếu ngồi (external reference), trong đĩ mã chương trình của một tập tin cĩ tham chiếu đến một vị trí trong một tập tin khác. Tham chiếu này cĩ thể chỉ đến một vị trí được định nghĩa trong một tập tin nhưng được dùng trong một tập tin cĩ thể chỉ đến một điểm vào của một thủ tục xuất hiện trong một tập tin và được gọi từ một tập tìn khác. Tập tin mã máy khá tái định vị phải giữ thơng tin này trong bảng ký hiệu cho mỗi vị trí đữ liệu hoặc nhãn chỉ thị được tham chiếu ngồi. Nếu khơng biết trước chỗ nào cần phải tham chiếu, chúng ta phải gộp tồn bệ bảng ký hiệu hợp ngữ làm thành phần của mã máy khả tái định vị.
Thí dụ, đoạn mã của (1.7) cĩ thể được đặt trước bởi
a 9 b 4 b 4
Nếu một tập tìn được tải với (1.7) cĩ tham chiếu đến b, thế thì tham chiếu đĩ sẽ được thay bằng 4 cộng với offset mà các vị trí đữ liệu trong tập tin (1.7) đã được tái định vị.
1.5 NHĨM CÁC GIAI ĐOẠN
hi thảo luận về các giai đoạn ở Phần 1.3, chúng ta đã xem xét về tổ chức logic của một trình biên dịch. Khi cài đặt, hoạt động của nhiều giai đoạn thường được nhĩm lại với nhau.
Kỳ đầu và kỳ sau
“Thường thì các giai đoạn được gom lại thành kỳ đu front end) và &ÿ sau (back end). Kỳ đầu gồm cĩ các giai đoạn hoặc các phần giai đoạn phụ thuộc nhiều vào ngơn ngữ nguồn (source language) và hấu như độc lập với máy đích. Thơng thường nĩ bao gồm giai đoạn phân tích từ oựng (lexical analysis) và phân tích cú pháp (syntactic analy- sis), quá trình tạo bảng ký hiệu (symbol table), phân tích ngữ nghĩa (semantic analy- sis) và sinh mã trung gian (generation of intermediate code). Một phần cơng việc tối ưu hĩa mã cũng cĩ thể được thực hiện ở kỳ đầu. Kỳ đầu cũng phải thực hiện xử lý lỗi xuất hiện ở từng giai đoạn vừa nêu,
Kỳ sau bao gồm các phần phụ thuộc vào máy đích và nĩi chung chúng khơng phụ thuộc vào ngơn ngữ nguồn mà là ngơn ngữ trung gian. Trong kỳ sau chúng ta gặp một. số vấn để tối ưu hĩa mã, phát sinh mã cùng với việc xử lý lỗi và các thao tác trên bảng ký hiệu.
Chúng ta cĩ thể lấy kỳ đầu của một trình biên dịch rồi thực biện lại kỳ sau, tạo ra một trình biên địch cho chính ngơn ngữ nguồn đĩ trên một mắy khác. Nếu kỳ sau được thiết kế cẩn thận thì cĩ thể khơng phải thiết kế lại quá nhiều; điều này sẽ được thảo luận trong Chương 9. Người ta cũng muốn biên dịch nhiều ngơn ngữ khác nhau thành
PHẦN 1.5 NHĨM CÁC GIẢI ĐOẠN 2a
một ngơn ngữ truug gian và dùng một kỳ sau chung cho nhiều kỳ đầu khác nhau, vì thế thu được nhiều trình biên địch cho một máy. Tuy nhiên vì những khác biệt tính tế về quan điểm của các ngơn ngữ nên mới chỉ cĩ ít thành cơng theo hướng này,
Các lượt
Một số giai đoạn biên địch thường được cài đặt bằng một /ượt (pass) duy nhất, bao gầm việc đọc tập tin nguyên liệu và ghi ra tập tin thành phẩm. Trong thực hành cĩ khác biệt rất lớn trong phương thức nhĩm các giai đoạn cửa trình biên dịch thành các lượt, vì thế chúng tơi sẽ thảo luận về trình biên địch dựa theo các giai đoạn chứ khơng phải theo lượt. Chương 12 sẽ thảo luận về một số trình biên dịch tiêu biểu và bàn thèm vẻ cách thức cấu trúc các giai đoạn vào các lượt.
Như chúng tơi đã để cập, người ta hay nhĩm nhiều giai doạn vào một lượt, và hoạt động của các giai đoạn này được thực hiện đan xen lẫn nhau. Thí dụ các giai đoạn phân tích từ vựng, phân tích cú pháp, phân tích ngữ nghia và phát sinh mã trung gian cĩ thể được nhĩm lại thành một lượt. Nếu như thế thì dịng thẻ từ sau giai đoạn phản tích cĩ thể được dịch trực tiếp thành mã trung gian. Chỉ tiết hơn, chứng ta xem (ế phân cú pháp (parser) là "nhân vật điều phối". Nĩ cố găng khám phá cấu trúc ngữ pháp trên những thẻ từ nĩ gặp; nĩ thu nhận các thẻ từ này khi cần đến chúng bằng cách yêu cầu ¿bể phân từ uựng (lexical analyzer) tìm thẻ từ tiếp theo. Khí cấu trúc ngữ pháp được khám phá ra, thể phân cú pháp sẽ gọi thể sinh mũ trung gian (intermediate code generator) để thực hiện việc phân tích ngữ nghĩa và sinh ra một phần mã. Một trình biên dịch được tổ chức theo cách này sẽ được trình bày trong Chương 2.
Thu gọn số lượt
Người ta chỉ muốn cĩ một số ít lượt thơi bởi vì mỗi lượt đều mất thời gian đọc và ghi ra tập tín trung gian. Ngược lại nếu chúng ta gom quá nhiều giai đoạn vào trong một. lượt thì cĩ thể phải duy trì tồn bộ chương trình trong bộ nhớ, bởi vì một giai đoạn cĩ thể cần thơng tin theo một thứ tự khác với thứ tự nĩ đã được tạo ra. Dạng biểu diễn trung gian của chương trình cĩ thể lớn hơn nhiều so với chương trình nguồn hoặc chương trình đích, vì thế khơng gian cần dùng cĩ thể khơng phải là vấn đề cĩ thể bỏ qua được.
Đối với một số giai đoạn, nhĩm chúng vào một lượt làm nảy sinh một số vấn đẻ, Chẳng hạn, như chúng ta đà nĩi ở trên, giao tiếp giữa thể phân từ vựng và thể phân cú pháp thường bị hạn chế qua một thẻ từ duy nhất Mặt khác sẽ rất khĩ thực hiện việc tạo mã trước khi tạo xong mã trung gian, Thí dụ các ngơn ngữ như PL/I và Algol 68 cho phép các biến được dùng trước khi khai báo. Chúng ta khơng thể tạo ra mã đích cho một kết cấu nếu khơng biết được kiểu của các biến cĩ mặt trong kết cấu đĩ. Tương tự phẩn lớn các ngơn ngữ đều cho phép dùng lệnh gote để nhảy tới trước trong chương trình. Chúng ta khơng thể xác định được địa chỉ đích của một lệnh nhảy như