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] Kiểm chứng dãy hành động Shift-Reduce

    Cho một văn phạm phi ngữ cảnh (CFG) với các luật sinh được đánh số 1,2,…,k1, 2, \ldots, k1,2,…,k, một chuỗi token đầu vào, và một dãy hành động được đề xuất gồm các bước SHIFT hoặc REDUCE i. Hãy mô phỏng một máy Shift-Reduce dùng ngăn xếp (stack) để kiểm chứng xem dãy hành động này có được thực hiện hợp lệ hay không.

    Máy có một ngăn xếp ban đầu rỗng và một con trỏ đọc, ban đầu trỏ vào token đầu tiên của chuỗi input. Các hành động được thực hiện tuần tự:

    • SHIFT: lấy token tiếp theo mà con trỏ đang trỏ tới, đẩy nó vào đỉnh stack, di chuyển con trỏ sang phải 1 vị trí. Nếu không còn token nào để lấy (đã đọc hết input) → hành động này không hợp lệ.
    • REDUCE i: luật sinh iii có dạng A→X1X2…XmA \to X_1 X_2 \ldots X_mA→X1​X2​…Xm​ (nếu luật rỗng, m=0m = 0m=0, ứng với A→εA \to \varepsilonA→ε). Xét mmm ký hiệu trên cùng của stack (theo đúng thứ tự từ dưới lên trên phải bằng X1,X2,…,XmX_1, X_2, \ldots, X_mX1​,X2​,…,Xm​). Nếu stack có ít hơn mmm phần tử, hoặc không khớp thứ tự X1…XmX_1 \ldots X_mX1​…Xm​ → hành động này không hợp lệ. Nếu khớp, lấy (pop) mmm ký hiệu đó ra và đẩy AAA vào đỉnh stack (nếu m=0m=0m=0 thì không pop gì cả, chỉ đẩy AAA).

    Nếu tại bước thứ jjj (1-indexed) gặp một hành động không hợp lệ, dừng ngay lập tức và báo lỗi tại bước đó — các bước sau không được xét tới.

    Nếu toàn bộ dãy hành động đều hợp lệ, kiểm tra thêm: input đã được đọc hết (con trỏ đã vượt qua token cuối) và trên stack chỉ còn đúng 1 ký hiệu, đúng bằng ký hiệu bắt đầu S0S_0S0​ của văn phạm hay không — nếu đúng thì dãy hành động này đã phân tích chấp nhận (ACCEPT) chuỗi input, ngược lại chỉ là một dãy hành động hợp lệ nhưng chưa hoàn tất phân tích (REJECT).

    Ví dụ: văn phạm S→(S)∣εS \to (S) \mid \varepsilonS→(S)∣ε (luật 1, luật 2), input ( ), dãy hành động SHIFT, REDUCE 2, SHIFT, REDUCE 1 mô phỏng: stack lần lượt là [(], [(, S], [(, S, )], rồi reduce luật 1 khớp ( S ) cho ra [S]. Toàn bộ input đã đọc hết, stack chỉ còn S = S_0$ → kết quả ACCEPT.

    • Định dạng đầu vào:
      • Dòng 1: hai giá trị kkk và S0S_0S0​ cách nhau bởi khoảng trắng — kkk là số luật sinh, S0S_0S0​ là ký hiệu bắt đầu (không chứa khoảng trắng).
      • kkk dòng tiếp theo: mỗi dòng có dạng A -> X1 X2 ... Xm (các ký hiệu cách nhau bởi khoảng trắng); nếu luật rỗng, ghi A -> ε.
      • Dòng tiếp theo: số nguyên nnn (số token của input, 0≤n≤10000 \le n \le 10000≤n≤1000).
      • Dòng tiếp theo: nnn token cách nhau bởi khoảng trắng (nếu n=0n = 0n=0, đây là một dòng trống — vẫn phải đọc dòng này).
      • Dòng tiếp theo: số nguyên ttt (số hành động, 0≤t≤20000 \le t \le 20000≤t≤2000).
      • ttt dòng tiếp theo: mỗi dòng là SHIFT hoặc REDUCE i (với 1≤i≤k1 \le i \le k1≤i≤k).
    • Định dạng đầu ra:

      Nếu tại bước jjj gặp hành động không hợp lệ đầu tiên: in đúng một dòng INVALID j rồi dừng (không in gì thêm).

      Nếu toàn bộ ttt hành động đều hợp lệ: in dòng đầu tiên VALID, rồi in dòng thứ hai là ACCEPT nếu điều kiện chấp nhận (đọc hết input và stack chỉ còn đúng S0S_0S0​) được thoả mãn, ngược lại in REJECT.

    Ví dụ:

    Đầu vào:

    2 S
    S -> ( S )
    S -> ε
    1
    (
    3
    SHIFT
    REDUCE 2
    REDUCE 1
    

    Đầu ra:

    INVALID 3
    

    Đầu vào:

    2 S
    S -> ( S )
    S -> ε
    2
    ( )
    4
    SHIFT
    REDUCE 2
    SHIFT
    REDUCE 1
    

    Đầu ra:

    VALID
    ACCEPT
    

    Đang tải editor...