Tại sao ngữ pháp BNF của C cho phép khai báo với một chuỗi trống khai báo?


28

Khi xem qua ngữ pháp BNF của C, tôi nghĩ thật kỳ lạ khi quy tắc sản xuất cho một tuyên bố trông như thế này (theo https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of% 20C% 20in% 20Backus-Naur% 20form.htm ):

<declaration> ::=  {<declaration-specifier>}+ {<init-declarator>}* ;

Tại sao sử dụng một bộ *định lượng (có nghĩa là không hoặc nhiều lần xuất hiện) cho init-declarator? Điều này cho phép các câu lệnh như int;hoặc void;có giá trị cú pháp, mặc dù chúng không hợp lệ về mặt ngữ nghĩa. Họ không thể chỉ sử dụng một bộ +định lượng (một hoặc nhiều lần xuất hiện) thay vì *trong quy tắc sản xuất?

Tôi đã thử biên dịch một chương trình đơn giản để xem trình biên dịch xuất ra cái gì và tất cả những gì nó làm là đưa ra cảnh báo.

Đầu vào:

int main(void) {
    int;
}

Đầu ra:

test.c: In function main’:
test.c:2:5: warning: useless type name in empty declaration
     int;
     ^~~

2
Sự khác biệt là BNF chỉ xác định cú pháp. Khá nhiều thứ được cho phép về mặt cú pháp nhưng vẫn không hợp lệ (hoặc vô lý) C. Mặc dù vậy, tìm thấy tốt đẹp!
larkey

7
À, và vui lòng sử dụng intlàm kiểu trả về mainvà không sử dụng ()làm danh sách loại tham số trong các hàm mà (void)thay vào đó.
larkey

1
Về mặt khái niệm , không có gì thực sự sai với điều này ngoại trừ việc nghe có vẻ hơi buồn cười: về cơ bản nó đang hỏi máy tính "Tôi muốn các biến số không, xin vui lòng, tên: [blankset].". Rốt cuộc, bạn có thể hỏi ai đó về những quả táo bằng không (mặc dù nó có thể sẽ gợi ra một phản ứng thú vị hơn một chút so với yêu cầu, nhưng đó không phải là một tuyên bố vô nghĩa vốn có). Do đó tại sao nó phải là phi ngôn ngữ trong C? Không có gì sai với loại ngữ pháp này.
The_Sympathizer

Rất thường mọi thứ hoạt động tốt hơn rất nhiều khi chúng ta bao gồm trường hợp trống (hoặc có lẽ, chân không?), Dù sao đi nữa.
The_Sympathizer

Đôi khi nó không phải là một người viết một chương trình, mà là một chương trình khác. Một chương trình như vậy đôi khi có thể muốn in "int" theo sau là một danh sách được phân tách bằng dấu phẩy o fth evarnames chúng ta cần, theo sau là ";" và vui mừng không cần kiểm tra nếu danh sách nói là trống trước.
Hagen von Eitzen

Câu trả lời:


29

declaration-specifierbao gồm type-specifier, bao gồm enum-specifier. Một cấu trúc như

enum stuff {x, y};

là hợp lệ declarationvới không init-declarator.

Các cấu trúc như int;được loại trừ bởi các ràng buộc ngoài ngữ pháp :

Một khai báo khác với khai báo static_assert sẽ khai báo ít nhất một khai báo (trừ các tham số của hàm hoặc các thành viên của cấu trúc hoặc liên kết), thẻ hoặc các thành viên của bảng liệt kê.

Tôi đoán rằng có những lý do tương thích ngược đằng sau trình biên dịch của bạn chỉ đưa ra cảnh báo.


14

Một khai báo không có người khai báo init:

<declaration> ::=  {<declaration-specifier>}+ {<init-declarator>}* ;

là vô hại đối với các danh sách chỉ định khai báo không phải là một enum/ struct/ unionspecifier và nó phù hợp một cách hữu ích với các danh sách đó.

Trong mọi trường hợp, ngữ pháp được trình bày cũng sẽ khớp sai các khai báo như int struct foo x;hoặc double _Bool y;(nó cho phép nhiều bộ xác định để khớp với những thứ như long long int), nhưng tất cả những thứ này có thể được phát hiện sau đó, trong một kiểm tra ngữ nghĩa.

Bản thân ngữ pháp BNF sẽ không loại bỏ tất cả các cấu trúc bất hợp pháp.

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.