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] Máy ảo ngăn xếp có lệnh rẽ nhánh và vòng lặp

    Để sinh mã cho các cấu trúc điều khiển (if, while, ...), trình biên dịch cần thêm các lệnh nhảy (jump) vào máy ảo ngăn xếp. Cho một máy ảo với ngăn xếp, một mảng bộ nhớ gồm mmm ô (đánh số 0..m−10..m-10..m−1, khởi tạo 000), và một chương trình gồm nnn lệnh được đánh số từ 000 đến n−1n-1n−1 (con trỏ lệnh — program counter — bắt đầu tại 000). Các lệnh gồm:

    • PUSH x: đẩy hằng số xxx.
    • LOAD i / STORE i: đọc/ghi ô nhớ iii (như đẩy/pop đỉnh ngăn xếp).
    • DUP: nhân đôi phần tử ở đỉnh ngăn xếp (đẩy thêm một bản sao).
    • ADD, SUB, MUL, DIV: pop bbb (đỉnh), aaa (kế đỉnh), đẩy lại a op ba \ \text{op} \ ba op b (DIV lấy phần nguyên hướng về 0).
    • JZ t: pop đỉnh ngăn xếp; nếu giá trị pop ra bằng 000 thì con trỏ lệnh nhảy đến chỉ số ttt, ngược lại con trỏ lệnh tăng lên 1 như bình thường.
    • JMP t: con trỏ lệnh nhảy đến chỉ số ttt vô điều kiện.
    • HALT: dừng chương trình ngay lập tức.

    Sau mỗi lệnh không phải là lệnh nhảy, con trỏ lệnh tăng thêm 1. Chương trình cũng dừng khi con trỏ lệnh đi ra ngoài đoạn [0,n−1][0, n-1][0,n−1] (kể cả khi nhảy đến đúng vị trí t=nt=nt=n, coi như kết thúc bình thường). Vì chương trình đầu vào có thể chứa vòng lặp không bao giờ dừng, hãy giới hạn số lệnh được thực thi tối đa là 2 000 0002\,000\,0002000000 lệnh; nếu vượt quá giới hạn này, in ra TIMEOUT và dừng ngay (không in gì khác).

    Nếu chương trình dừng bình thường (không vượt giới hạn), hãy in ra toàn bộ nội dung ngăn xếp cuối cùng, theo thứ tự từ đáy lên đỉnh (có thể rỗng).

    Ví dụ: chương trình dưới đây tính tổng 1+2+⋯+51+2+\cdots+51+2+⋯+5 bằng vòng lặp, dùng ô nhớ 0 làm biến đếm và ô nhớ 1 làm tổng tích lũy:

    0: PUSH 5      6: LOAD 1      12: SUB
    1: STORE 0     7: LOAD 0      13: STORE 0
    2: PUSH 0      8: ADD         14: JMP 4
    3: STORE 1     9: STORE 1
    4: LOAD 0      10: LOAD 0
    5: JZ 15       11: PUSH 1
    

    Sau khi thực thi, vòng lặp dừng khi ô nhớ 0 (bộ đếm) về 000, ô nhớ 1 chứa tổng 151515, ngăn xếp cuối cùng rỗng — chương trình in ra một dòng trống.

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

      Dòng đầu tiên chứa hai số nguyên nnn và mmm (1≤n≤20001 \le n \le 20001≤n≤2000, 0≤m≤1000 \le m \le 1000≤m≤100). nnn dòng tiếp theo, mỗi dòng là lệnh thứ 0,1,…,n−10, 1, \ldots, n-10,1,…,n−1 theo đúng cú pháp nêu trên; các đích nhảy ttt của JZ/JMP thỏa 0≤t≤n0 \le t \le n0≤t≤n. Dữ liệu đảm bảo ngăn xếp luôn đủ phần tử khi cần pop và chỉ số ô nhớ hợp lệ.

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

      Nếu chương trình vượt quá 2 000 0002\,000\,0002000000 lệnh thực thi, in ra đúng một dòng TIMEOUT. Ngược lại, in ra một dòng chứa nội dung ngăn xếp cuối cùng (các số nguyên cách nhau khoảng trắng, theo thứ tự từ đáy lên đỉnh), hoặc một dòng trống nếu ngăn xếp rỗng.

    Ví dụ:

    Đầu vào:

    1 0
    JMP 0

    Đầu ra:

    TIMEOUT
    

    Đầu vào:

    15 2
    PUSH 5
    STORE 0
    PUSH 0
    STORE 1
    LOAD 0
    JZ 15
    LOAD 1
    LOAD 0
    ADD
    STORE 1
    LOAD 0
    PUSH 1
    SUB
    STORE 0
    JMP 4

    Đầu ra:

    
    

    Đang tải editor...