ngôn ngữ với hai toán tử nhị phân có cùng mức độ ưu tiên, liên kết trái và liên kết phải


11

Có bất kỳ ngôn ngữ lập trình (hoặc kịch bản) (hoặc một số ngôn ngữ cụ thể của tên miền) có hai toán tử nhị phân oploprcùng mức độ ưu tiên với oplliên kết trái và liên kết oprphải không?

(Tôi không thể tìm thấy một ví dụ như vậy, nhưng tôi đang cố gắng viết mã một số trình phân tích cú pháp đủ để xử lý trường hợp kỳ lạ đó)

Làm thế nào các biểu thức có dạng x opl y opr z hoặc x opr y opl z được phân tích cú pháp? Và nói chung với nhiều toán hạng hơn?


4
Nếu nó đau, đừng làm điều đó.
CodeInChaos

1
Trong Haskell, bạn có thể định nghĩa các toán tử infix của riêng bạn với các ưu tiên riêng của chúng và bạn gặp lỗi trong trường hợp này; nếu bạn có x <@ y @> zbằng <@được trái kết hợp và @>là phải kết hợp, GHC mang đến cho bạn một "Precedence lỗi phân tích cú pháp": "không thể trộn lẫn ' <@' [infixl 0] và ' @>' [infixr 0] trong biểu thức trung tố cùng" (nơi tôi định nghĩa các toán tử này ở mức 0 chẳng hạn).
Antal Spector-Zabusky 22/2/2016

@ AntalSpector-Zabusky: Đó sẽ là một câu trả lời tuyệt vời!
Basile Starynkevitch

@ AntalSpector-Zabusky: Tương tự trong Swift. Tôi nghĩ rằng bạn thực sự có thể định nghĩa các toán tử, nhưng trong một biểu thức bạn phải sử dụng tất cả các toán tử liên kết trái hoặc tất cả các toán tử liên kết phải có cùng mức ưu tiên. Vì vậy, bạn có thể sử dụng x leftop y leftop z, hoặc x rightop y rightop z, nhưng không phải x leftop y rightop z.
gnasher729

@BasileStarynkevitch: Như bạn muốn! Vì bạn đã đề cập đến "trình phân tích cú pháp linh hoạt", tôi đã bao gồm một số ngôn ngữ khó hiểu hơn có trình phân tích cú pháp rất linh hoạt (từng muốn if_then_else_hoặc [1;2;3]được xác định trong thư viện?).
Antal Spector-Zabusky 22/2/2016

Câu trả lời:


10

Dưới đây là ba ngôn ngữ cho phép bạn xác định toán tử của riêng mình, chúng thực hiện hai điều rưỡi khác nhau ! Cả Haskell và Coq đều không cho phép các loại shenanigans này - nhưng khác nhau - trong khi Agda cho phép loại hỗn hợp này của sự kết hợp.


Đầu tiên, trong Haskell , bạn chỉ đơn giản là không được phép làm điều này. Bạn có thể xác định các toán tử của riêng bạn và ưu tiên cho chúng (từ 0 Lỗi9) và tính kết hợp của sự lựa chọn của bạn. Tuy nhiên, Báo cáo Haskell không cho phép bạn trộn lẫn các kết hợp :

Các toán tử không liên kết liên tiếp có cùng mức ưu tiên phải là liên kết trái hoặc phải để tránh lỗi cú pháp. [Báo cáo Haskell 2010, Ch. 3]

Vì vậy, trong GHC , nếu chúng ta xác định infixltoán tử liên kết trái ( ) <@và toán tử liên kết phải @>ở cùng mức ưu tiên - giả sử 0 - thì việc đánh giá x <@ y @> zsẽ đưa ra lỗi

Lỗi phân tích cú pháp ưu tiên
    không thể trộn ' <@' [ infixl 0] và ' @>' [ infixr 0] trong cùng một biểu thức infix

(Trên thực tế, bạn cũng có thể khai báo một toán tử là infix nhưng không liên kết, như ==vậy, đó x == y == zlà một lỗi cú pháp!)


Mặt khác, có ngôn ngữ / định lý ngôn ngữ được gõ phụ thuộc Agda (mà, thừa nhận, là ít chính thống hơn đáng kể). Agda có một số cú pháp dễ uốn nhất của bất kỳ ngôn ngữ nào tôi biết, hỗ trợ các toán tử mixfix : thư viện chuẩn chứa hàm

if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A

trong đó, khi được gọi, được viết

if b then t else f

với các đối số điền vào dấu gạch dưới! Tôi đề cập đến điều này bởi vì điều này có nghĩa là nó phải hỗ trợ phân tích cú pháp cực kỳ linh hoạt. Đương nhiên, Agda cũng có các khai báo tính cố định (mặc dù các mức độ ưu tiên của nó nằm trên các số tự nhiên tùy ý và thường ở 0 0100100) và Agda cho phép bạn kết hợp các toán tử có cùng mức ưu tiên nhưng các mức độ cố định khác nhau. Tuy nhiên, tôi không thể tìm thấy thông tin về điều này trong tài liệu, vì vậy tôi phải thử nghiệm.

Hãy sử dụng lại của chúng tôi <@@>từ trên cao. Trong hai trường hợp đơn giản, chúng ta có

  • x <@ y @> zphân tích cú pháp như x <@ (y @> z); và
  • x @> y <@ zphân tích cú pháp như (x @> y) <@ z.

Tôi nghĩ những gì Agda làm là nhóm dòng thành các phần "liên kết bên trái" và "liên kết bên phải", và - trừ khi tôi nghĩ về những điều sai trái - phần liên kết bên phải được "ưu tiên" trong việc nắm bắt các lập luận liền kề. Vì vậy, nó mang lại cho chúng tôi

a <@ b <@ c @> d @> e @> f <@ g

phân tích như

(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g

hoặc là

Cây phân tích của <code> (((a <@ b) <@ (c @> (d </ code> @> (e @> f)))) <@ g

Tuy nhiên, mặc dù thử nghiệm của tôi, tôi đã đoán sai lần đầu tiên tôi viết nó ra, điều này có thể mang tính hướng dẫn :-)

.


Cuối cùng, có Coq ngôn ngữ prover-prover / gõ phụ thuộc , có cú pháp linh hoạt hơn Agda vì các phần mở rộng cú pháp của nó thực sự được thực hiện bằng cách đưa ra các đặc tả cho các cấu trúc cú pháp mới và sau đó viết lại chúng thành ngôn ngữ cốt lõi (giống như macro một cách mơ hồ , Tôi giả sử). Trong Coq, cú pháp danh sách [1; 2; 3]là nhập tùy chọn từ thư viện chuẩn. Cú pháp mới thậm chí có thể liên kết các biến!

Một lần nữa, trong Coq, chúng ta có thể xác định các toán tử infix của riêng mình và cung cấp cho chúng các mức độ ưu tiên (từ 0, 99, chủ yếu) và các kết hợp. Tuy nhiên, trong Coq, mỗi cấp độ ưu tiên chỉ có thể có một kết hợp . Vì vậy, nếu chúng ta xác định <@là liên kết trái và sau đó cố gắng xác định @>là liên kết phải ở cùng cấp - giả sử, 50 - chúng ta nhận được

Lỗi: Cấp 50 đã được khai báo kết hợp bên trái trong khi hiện tại dự kiến ​​sẽ là liên kết bên phải

Hầu hết các nhà khai thác trong Coq đều ở mức chia hết cho 10; nếu tôi gặp vấn đề về sự kết hợp (những sự kết hợp cấp độ này là toàn cầu), thì tôi thường chỉ vượt qua cấp độ một trong hai hướng (thường là lên).


2
(Gee, thật là một lựa chọn ngôn ngữ kỳ quặc. Bạn có thể nói tôi học lý thuyết ngôn ngữ lập trình không? :-P)
Antal Spector-Zabusky 22/2/2016

Cảm ơn rất nhiều cho câu trả lời chi tiết của bạn. BTW, bạn đã vẽ bức tranh như thế nào (với công cụ gì graphviz?)
Basile Starynkevitch 22/2/2016

BTW, tại sao "cố định" thay vì "ưu tiên"?
Basile Starynkevitch

@BasileStarynkevitch: Điều đó phụ thuộc vào ý của bạn. Nếu bạn có ý nghĩa trong phần Coq, đó chỉ là một lỗi :-) (Và một lỗi hiện đã được sửa!)
Antal Spector-Zabusky 22/2/2016

1
@BasileStarynkevitch: Ngoài ra, tôi đã bỏ lỡ câu hỏi của bạn về bức ảnh! Tôi đã vẽ nó với gói LaTeX qtree và kết xuất nó trong LaTeXit , một trình kết xuất đoạn trích LaTeX cho máy Mac. Mã nguồn có liên quan là \ttfamily \Tree[.<@ [.<@ [.<@ a b ] [.@> c [.@> d [.@> e f ]]]] g ].
Antal Spector-Zabusky

2

Kể từ khi chúng được phổ biến bởi Douglas Crockford, Pratt Parsers (hoặc Trình phân tích cú pháp ưu tiên toán tử từ trên xuống) đã bắt đầu trở nên phổ biến hơn. Các trình phân tích cú pháp này hoạt động từ một bảng ưu tiên và tính kết hợp của toán tử, thay vì có các quy tắc được xây dựng trong một ngữ pháp cố định, vì vậy chúng hữu ích cho các ngôn ngữ cho phép người dùng xác định toán tử của riêng họ.

Chúng có chức năng phân tích cú pháp hoạt động bằng cách phân tích cú pháp đầu tiên bên trái của biểu thức, sau đó ràng buộc đệ quy các toán tử mới và các thuật ngữ tay phải miễn là chúng liên kết một cách thích hợp. Các toán tử liên kết bên trái sẽ liên kết các thuật ngữ tay phải có quyền ưu tiên và bao gồm cùng mức ưu tiên, trong khi các toán tử liên kết phải chỉ liên kết với mức ưu tiên của chúng, nhưng không bao gồm nó. Tôi tin rằng kết quả này trong cùng một cây phân tích như đối với Agda, được trích dẫn ở trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.