Trình biên dịch xử lý tuần tự các lệnh:
BEGIN: mở một phạm vi mới lồng vào phạm vi hiện tại (phạm vi toàn cục có độ sâu 0; mỗi lệnh BEGIN làm độ sâu tăng thêm 1).END: đóng phạm vi trong cùng hiện tại, quay về phạm vi cha (độ sâu giảm đi 1).DECL <ten> <kieu>: khai báo biến <ten> với kiểu dữ liệu <kieu> (một chuỗi không chứa khoảng trắng, ví dụ int, float, bool, string) trong phạm vi hiện tại. Nếu <ten> đã tồn tại trong CHÍNH phạm vi hiện tại, khai báo mới sẽ GHI ĐÈ kiểu cũ (khai báo sau có hiệu lực).USE <ten>: tham chiếu tới biến <ten>. Trình biên dịch tìm <ten> bắt đầu từ phạm vi hiện tại, nếu không thấy thì tìm dần ra các phạm vi cha, ông, ... cho tới phạm vi toàn cục (đây chính là quy tắc phạm vi tĩnh — static/lexical scoping: biến ở phạm vi gần nhất được ưu tiên, có thể che khuất biến cùng tên ở phạm vi ngoài).Với mỗi lệnh USE <ten>, hãy in ra kết quả tra cứu:
<kieu>, in ra chuỗi <kieu>@<d> (không có khoảng trắng, nối trực tiếp bằng ký tự @).UNDEFINED.Ví dụ: với dữ liệu
6
DECL x int
BEGIN
USE x
DECL x string
USE x
END
Kết quả là:
int@0
string@1
(lệnh USE x đầu tiên ở độ sâu 1 chưa có x cục bộ nên tìm ra x ở phạm vi toàn cục — độ sâu 0, kiểu int; lệnh USE x thứ hai tìm thấy ngay x vừa khai báo cục bộ ở độ sâu 1, kiểu string, che khuất biến x toàn cục).
Dòng đầu chứa số nguyên n (0≤n≤2000) — số lệnh. n dòng tiếp theo, mỗi dòng là một trong bốn dạng lệnh: BEGIN, END, DECL <ten> <kieu>, USE <ten>. Dữ liệu đảm bảo số lệnh END không vượt quá số BEGIN chưa đóng tương ứng.
Với mỗi lệnh USE, in ra một dòng kết quả tra cứu theo định dạng <kieu>@<do_sau> hoặc UNDEFINED, theo đúng thứ tự xuất hiện của các lệnh USE trong dữ liệu vào. Nếu không có lệnh USE nào, không in gì.
Ví dụ:
Đầu vào:
0
Đầu ra:
Đầu vào:
3
USE x
DECL x int
USE x
Đầu ra:
UNDEFINED
int@0
Đang tải editor...