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] Giải quyết xung đột shift/reduce bằng độ ưu tiên và tính kết hợp

    Với văn phạm biểu thức nhị phân mơ hồ điển hình E→E op E∣idE \to E\ op\ E \mid \text{id}E→E op E∣id (nhiều toán tử opopop), bảng LR(0)/SLR(1) dựng trực tiếp sẽ có rất nhiều xung đột shift-reduce. Các công cụ sinh parser (như yacc/bison) giải quyết vấn đề này bằng cách khai báo cho mỗi toán tử một độ ưu tiên (precedence) — số nguyên, càng lớn càng liên kết chặt hơn — và một tính kết hợp (associativity) là trái (L) hoặc phải (R), rồi dùng quy tắc: khi có xung đột shift-reduce giữa việc rút gọn theo toán tử op1op_1op1​ (đang trên đỉnh ngăn xếp) và việc dịch chuyển toán tử op2op_2op2​ (đang chờ ở token hiện tại),

    • nếu prec(op1)>prec(op2)\text{prec}(op_1) > \text{prec}(op_2)prec(op1​)>prec(op2​): rút gọn;
    • nếu prec(op1)<prec(op2)\text{prec}(op_1) < \text{prec}(op_2)prec(op1​)<prec(op2​): dịch chuyển;
    • nếu bằng nhau: dịch chuyển nếu op1op_1op1​ (và op2op_2op2​, cùng độ ưu tiên nên cùng khai báo) có tính kết hợp R, ngược lại rút gọn nếu là L.

    Áp dụng quy tắc trên vào toàn bộ quá trình phân tích, kết quả tương đương với thuật toán phân tích biểu thức theo độ ưu tiên kinh điển (precedence climbing): với chuỗi các toán hạng và toán tử hai ngôi (không có toán tử một ngôi), có thể có dấu ngoặc đơn ( ), hãy xác định cách nhóm các phép toán mà một bộ phân tích LR dùng bảng khai báo độ ưu tiên nêu trên sẽ tạo ra, rồi in biểu thức đó dưới dạng đã đặt ngoặc đầy đủ (mỗi phép áp dụng toán tử nhị phân được bao trong một cặp ngoặc ( toán_hạng_trái op toán_hạng_phải )).

    Toán hạng là bất kỳ token nào không phải là một trong các toán tử được khai báo và không phải ( hoặc ) (ví dụ tên biến, hằng số); đề bài đảm bảo xâu vào là một biểu thức hợp lệ theo văn phạm (không cần xử lý lỗi cú pháp).

    Ví dụ: với 2 toán tử + 1 L và * 2 L, biểu thức a + b * c được nhóm thành ( a + ( b * c ) ) vì * có độ ưu tiên cao hơn +.

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

      Dòng đầu tiên là số nguyên kkk (0≤k≤100 \le k \le 100≤k≤10) — số toán tử được khai báo. kkk dòng tiếp theo, mỗi dòng dạng op prec assoc: op là ký hiệu toán tử (một token, không trùng nhau, không phải ( hay )), prec là số nguyên dương chỉ độ ưu tiên, assoc là L hoặc R. Dòng cuối cùng là biểu thức trung tố cần phân tích, các token cách nhau bởi dấu cách (toán hạng, các toán tử đã khai báo ở trên, và có thể có (, )).

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

      In ra một dòng duy nhất: biểu thức đã đặt ngoặc đầy đủ phản ánh đúng cách nhóm theo độ ưu tiên/tính kết hợp đã khai báo, các token (bao gồm cả dấu ngoặc thêm vào) cách nhau bởi đúng một dấu cách. Nếu biểu thức chỉ là một toán hạng đơn (không có toán tử nào), in ra chính toán hạng đó, không thêm ngoặc.

    Ví dụ:

    Đầu vào:

    3
    + 1 L
    - 1 L
    * 2 L
    a + b * c - d
    

    Đầu ra:

    ( ( a + ( b * c ) ) - d )
    

    Đầu vào:

    0
    x
    

    Đầu ra:

    x
    

    Đang tải editor...