Một macro object-like có thể tham chiếu đến chính nó hoặc tạo thành vòng lặp tham chiếu lẫn nhau (ví dụ #define X 1 + X). Nếu khai triển "ngây thơ" (cứ thấy tên macro là thay thế) thì quá trình này sẽ lặp vô hạn. Các trình biên dịch C thật sự tránh điều này bằng quy tắc: trong quá trình khai triển một macro, nếu tên của chính nó (hoặc tên của một macro "tổ tiên" đang trong quá trình khai triển dẫn đến vị trí hiện tại) xuất hiện lại, thì không khai triển tiếp occurrence đó nữa — giữ nguyên nó như một token thường (dân trong ngành gọi vui là macro đó đã bị "sơn xanh" tại vị trí đó).
Cho n định nghĩa macro object-like (không tham số) NAME t_1 t_2 \dots t_B, trong đó NAME là tên macro và t1,…,tB là thân macro — một dãy token (B≥0), mỗi token có thể là tên của một macro khác (kể cả chính nó) hoặc một token thường. Cho một tên macro truy vấn Q (đảm bảo đã được định nghĩa).
Hãy khai triển Q đầy đủ theo quy tắc đệ quy chính xác sau: gọi expand(t,S) là kết quả khai triển token t biết tập "đã sơn xanh" hiện tại là S — nếu t là tên một macro và t∈/S, kết quả là nối tiếp expand(ti,S∪{t}) cho từng token ti trong thân macro t (theo thứ tự); ngược lại (không phải macro, hoặc t∈S) kết quả là chính token t. Đáp số là expand(Q,∅).
Ví dụ: X có thân 1 + X. Khai triển X: vì X tham chiếu chính nó, khi gặp lại token X bên trong khai triển của chính nó thì giữ nguyên. Kết quả: 1 + X.
Dòng đầu tiên chứa số nguyên n (1≤n≤100). n dòng tiếp theo, mỗi dòng có dạng NAME t_1 t_2 \dots t_B (0≤B≤20, các tên macro và token chỉ gồm chữ/số/gạch dưới). Dòng cuối cùng chứa tên macro truy vấn Q, đảm bảo Q xuất hiện là tên của một trong n định nghĩa trên.
In ra một dòng là kết quả khai triển expand(Q,∅), các token cách nhau một khoảng trắng (dòng rỗng nếu kết quả không còn token nào).
Ví dụ:
Đầu vào:
2
A B end
B A start
A
Đầu ra:
A start end
Đầu vào:
2
X 1 + X
A A
X
Đầu ra:
1 + X
Đang tải editor...