Các lượt nộp
    Danh sách bài
    Trang chủ
    Báo lỗi

    solution

    Đề bài: [Trình biên dịch] Phạm vi biến theo thụt lề dòng

    Trong nhiều ngôn ngữ (như Python), phạm vi (scope) của một khối lệnh được xác định bởi mức thụt lề (indentation) thay vì cặp dấu ngoặc { }. Bạn cần xây dựng một bộ phân giải tên (name resolver) đơn giản mô phỏng bảng ký hiệu (symbol table) theo cơ chế này.

    Chương trình gồm nnn dòng lệnh. Mỗi dòng lệnh có thể được thụt vào một số chẵn khoảng trắng ở đầu dòng; gọi level=(soˆˊ khoảng tra˘ˊng đaˆˋu doˋng)/2level = (\text{số khoảng trắng đầu dòng}) / 2level=(soˆˊ khoảng tra˘ˊng đaˆˋu doˋng)/2 là mức phạm vi của dòng đó (dòng không thụt lề có level=0level = 0level=0, tức phạm vi toàn cục).

    Có hai loại lệnh (sau phần thụt lề):

    • let <name> = <value>: khai báo biến name (giá trị nguyên value, có thể âm) tại scope ứng với levellevellevel của dòng này.
    • print <name>: in ra giá trị của name, được phân giải bằng cách tìm từ scope ở levellevellevel hiện tại lùi dần về scope toàn cục (level=0level=0level=0), lấy giá trị ở scope gần nhất (level cao nhất) có khai báo name. Nếu không tìm thấy ở scope nào, in undefined.

    Quy tắc quản lý scope theo mức thụt lề: Hãy hình dung một ngăn xếp các scope, ngăn xếp luôn có ít nhất 1 phần tử (scope toàn cục ở đáy, index 0). Khi xử lý một dòng có mức level=Llevel = Llevel=L:

    • Nếu LLL lớn hơn mức cao nhất đang có trên ngăn xếp, hãy mở thêm các scope rỗng mới cho đến khi ngăn xếp có đúng L+1L+1L+1 scope.
    • Nếu LLL nhỏ hơn mức cao nhất đang có, hãy đóng (loại bỏ hoàn toàn, kể cả các khai báo bên trong) tất cả các scope có level >L> L>L.
    • Sau đó thực hiện lệnh của dòng tại scope mức LLL.

    Ví dụ (n=6n=6n=6):

    let x = 1
      let y = 2
      print x
        let x = 5
        print x
    print x
    

    Kết quả:

    1
    5
    1
    

    (Dòng print x ở level 1 không thấy y, tìm x ở level 0 ra 1; dòng print x ở level 2 thấy x=5 khai báo ngay tại level 2; dòng print x cuối cùng ở level 0 làm đóng toàn bộ các scope level 1, 2 nên chỉ còn x=1 ở level 0).

    • Định dạng đầu vào:

      Dòng đầu tiên: số nguyên nnn (0≤n≤20000 \le n \le 20000≤n≤2000) — số lệnh. nnn dòng tiếp theo, mỗi dòng là một lệnh let <name> = <value> hoặc print <name>, có thể có một số chẵn khoảng trắng ở đầu dòng để thể hiện mức thụt lề. name gồm chữ cái thường và chữ số, value là số nguyên trong khoảng [−106,106][-10^6, 10^6][−106,106].

    • Định dạng đầu ra:

      Với mỗi lệnh print <name>, in ra một dòng: giá trị nguyên tìm được, hoặc undefined nếu không tìm thấy khai báo nào khả kiến. Nếu n=0n=0n=0, không in gì cả.

    Ví dụ:

    Đầu vào:

    0

    Đầu ra:

    
    

    Đầu vào:

    6
    let x = 1
      let y = 2
      print x
        let x = 5
        print x
    print x

    Đầu ra:

    1
    5
    1
    

    Đang tải editor...