Tại sao định danh không nên bắt đầu bằng một số?


32

Hầu hết các ngôn ngữ lập trình dường như được thiết kế để không cho phép một người khai báo một mã định danh bắt đầu bằng một số. Tôi chỉ tò mò muốn biết lý do. Tôi đã tìm kiếm trên web, nhưng không thể tìm thấy một lời giải thích thỏa đáng.


4
Bạn có một ví dụ duy nhất về một tên biến trong đó nó sẽ có lợi ích cho sự rõ ràng và dễ đọc không?
Bảo mật

5
@Secure: 3dspline, 4seasonPizza, 2pdfConverter, 8bitInt, ...
người dùng chưa biết

6
Forth cho phép nó. Trong số các phần dựng sẵn: 2DUP, 2DROP, 2SWAP, 2> R, 2R @, 2R>, 0 =, v.v.
Peter Mortensen

cũng như TCL nhưng tôi không nghĩ bất kỳ lệnh TCL tiêu chuẩn nào bắt đầu bằng một số
jk.

Câu trả lời:


51

Trong C / C ++, một số được theo sau bởi một chữ cái được coi là hằng số và chuỗi theo sau, đủ điều kiện loại hằng. Vì vậy, ví dụ (đây là VC ++, không chắc chúng chuẩn như thế nào):

  • 0 - số nguyên đã ký
  • 0l - số nguyên dài ký
  • 0u - số nguyên không dấu
  • Số nguyên có chữ ký 0i64 - 64 bit

Vì vậy, a) dễ dàng hơn đối với người từ vựng như Daniel đã nói nhưng cũng b) nó tạo ra sự khác biệt rõ ràng vì 0y có thể là một biến nhưng 0u sẽ không bao giờ. Cộng với các vòng loại khác, như "i64" đã được thêm vào muộn hơn "l" hoặc "u" và họ muốn giữ tùy chọn mở thêm nhiều hơn nếu cần.


7
Ngoài ra, các số hex được viết dưới dạng 0xd + trong đó d + ​​là 1 chữ số hex khác 0-f - vì vậy 0xbeef là một "số" hoàn toàn hợp lệ.
tcrosley

20
Các bạn có nhận ra tôi không đi theo thông số ngôn ngữ, nhưng chỉ cung cấp một vài ví dụ để minh họa cho vấn đề này, phải không?
DXM

6
Re: "họ muốn giữ tùy chọn mở thêm nếu cần thêm": Và C ++ 11 thậm chí cho phép bạn thêm tùy chọn của mình; xem http://en.wikipedia.org/wiki/C++11#User-dained_literals .
ruakh

2
Tôi không nghĩ rằng đây là lời giải thích đúng. Quy tắc "định danh không thể bắt đầu bằng một chữ số" là đúng với Algol, Pascal và các ngôn ngữ khác không cho phép các hậu tố chữ cái cho các hằng số.
Larry Gritz

1
@LarryGritz: "Việc tách các từ một cách nhất quán bằng các khoảng trắng đã trở thành một phong tục chung về thế kỷ thứ mười sau Công nguyên, và kéo dài đến khoảng năm 1957, khi FORTRAN từ bỏ việc thực hành." Hướng dẫn tham khảo FORSAN FORSAN (từ wiki). Fortran có lý do đặc biệt của riêng mình vì họ quyết định không gian nói chung là tùy chọn. Ngôn ngữ HIỆN ĐẠI như khoảng trắng của chúng. Bạn đang ở một mình với Algol nhưng tôi cũng không phải là người hiện đại. Mặt khác, C / C ++ / C # / F # đều có hậu tố.
DXM

49

Sự tiện lợi của những người thực hiện lexer. (Không, nghiêm túc, đó là về nó. Các ngôn ngữ khác nhau có những lý do khác, nhưng cuối cùng nó lại xuất phát từ đó.)


2
Thật dễ dàng để phân biệt giữa chữ và số nhận dạng tích phân bắt đầu bằng chữ số bằng cách sử dụng PEG hoặc các kỹ thuật phân tích cú pháp hiện đại khác. Ngay cả các trình biên dịch sử dụng các từ vựng nguyên thủy cũng có thể đặt chúng vào cùng một loại mã thông báo và phân biệt sau này. Sẽ rất khó xử nếu ví dụ như 0flumột nghĩa đen và 0glulà một định danh địa phương.
Daniel Lubarov

2
Mọi người hoàn toàn có thể phân biệt chúng. Quyết định được đưa ra dựa trên sự thuận tiện (hoặc, nếu bạn ít từ thiện, lười biếng) hơn là các yêu cầu kỹ thuật.
Daniel Pittman

2
@DanielPittman: Bạn sẽ cần phân tích ngữ nghĩa để thực hiện bất kỳ loại định hướng đáng tin cậy nào, do đó không thể thực hiện được trong từ vựng. Đẩy quyết định ra khỏi lexer làm cho trình phân tích cú pháp phức tạp hơn, và mang lại lợi ích gì? Bên cạnh tình huống chi phí / lợi ích rất kém, không có cách nào tốt để xử lý một trường hợp như int 0u = 5; unsigned int x = 0u;Tuy nhiên, bạn chọn xác định cách giải thích mã này (có thể là x == 0 hoặc x == 5), mọi người sẽ bị nhầm lẫn Vì sự mơ hồ. Ngay cả khi việc triển khai trình biên dịch theo cách này là không quan trọng, một nhà thiết kế giỏi có thể sẽ không làm điều đó.
Joren

10
Sự tiện lợi chính là cho trình phân tích cú pháp trong đầu của tôi chứ không phải cho người tạo ra ngôn ngữ.
CodeInChaos

2
Nhiều người vẫn ngạc nhiên khi biết rằng phân tích từ vựng thường là một yếu tố lớn, giai đoạn chậm nhất của trình biên dịch / trình thông dịch.
hà mã

20

Hãy xem xét 2 trường hợp sau:

Trường hợp 1

Giả sử rằng một định danh có thể bắt đầu bằng một số.

Vì vậy, một tuyên bố như dưới đây sẽ hợp lệ (vì một định danh có thể có 1 hoặc nhiều ký tự):

số 3;

Khi tôi cố gắng sử dụng biến trên trong một chương trình, nó sẽ dẫn đến sự mơ hồ của trình biên dịch:

int 3, a;
3 = 5;
a = 3;

Trong câu lệnh a=3, vai trò của 3 là gì (nó có phải là biến có giá trị 5 hay là số 3)?

Trường hợp 2

Trái ngược với ví dụ trên, giả sử rằng một ngôn ngữ thực sự cho phép các định danh bắt đầu bằng một số trong khi vẫn không cho phép các số được sử dụng làm định danh. Điều này có thể gây ra các vấn đề sau:

  • Các quy tắc ngôn ngữ liên quan đến biến nói rằng một biến có thể bao gồm 1 hoặc nhiều ký tự sẽ phải được xác định lại thành quy tắc phức tạp như: Một biến có thể có một hoặc nhiều ký tự và phải là duy nhất nếu nó không bắt đầu bằng một số trong khi nó không thể có độ dài một ký tự khi bắt đầu bằng một số (vv ..)

  • Trình biên dịch sẽ phải kiểm tra và báo cáo các trường hợp lỗi khi tất cả các chữ số (ví dụ 333) và hậu tố bảng chữ cái hợp lệ (ví dụ 34L) đang được sử dụng làm tên biến. Trong các ngôn ngữ được gõ lỏng lẻo như Python và JS, nơi bạn có thể sử dụng các biến một cách nhanh chóng mà không cần khai báo chúng, thậm chí có thể không thể kiểm tra các trường hợp đặc biệt liên quan đến tất cả các chữ số, ví dụ if (33==5)Ở đây, 33 có thể là một biến không được khai báo sai mà người dùng đã khai báo. Nhưng trình biên dịch sẽ không thể xác định điều này và báo cáo lỗi.

Thực hiện hạn chế này sẽ ngăn lập trình viên sử dụng số làm tên định danh.


2
Theo logic này, các định danh không thể chứa các ký tự vì chúng sẽ mơ hồ với các từ khóa. Bạn có thể tưởng tượng thảm họa int char = floatsẽ như thế nào ?
Pubby

4
@Pubby: Tôi không thấy cách bạn có thể ngoại suy những gì tôi đã nói với một số người hoàn toàn vô nghĩa mà tôi chưa thể tìm ra. Nhận xét của bạn có ý nghĩa gì?
aml90

Tôi đang nói rằng bạn đang đặt câu hỏi quá đúng theo nghĩa đen và nó hoàn toàn không mơ hồ bằng cách sử dụng quyền ưu tiên. Ví dụ, làm thế nào trình biên dịch biết intlà một từ khóa và không phải là một định danh? Vâng, intcó quyền ưu tiên cao hơn giống như các từ vựng số sẽ có.
Pubby

@Pubby: Theo sự mơ hồ, tôi có nghĩa là trình biên dịch sẽ không biết trong bối cảnh nào tôi đang sử dụng tên biến (thậm chí sử dụng quyền ưu tiên từ vựng). Ví dụ: xem xét mã này: int 3,a; 3=5; a=3; Trong câu lệnh a = 3, 3 được hiểu là định danh hay là số? Điều này gây ra sự mơ hồ. Hy vọng nó rõ ràng.
aml90

2
Tôi cũng thấy lập luận này yếu. Sẽ là tầm thường khi viết một từ vựng chấp nhận các định danh bắt đầu bằng, nhưng không hoàn toàn bao gồm các chữ số.
Larry Gritz

11

Đối với hầu hết các phần, điều này không liên quan gì đến việc giúp người viết trình biên dịch dễ dàng và hiệu quả phân tích cú pháp, nhưng, nhiều hơn để làm với việc thiết kế một cú pháp khuyến khích mã rõ ràng dễ đọc và rõ ràng.

Các nhà thiết kế ngôn ngữ của nó nghĩ rằng thật tuyệt khi có thể viết các chữ số như số 1 chỉ đơn giản là 1 .

Hoàn toàn có thể thiết kế một cú pháp ngôn ngữ trong đó các chữ số được trích dẫn theo một cách nào đó ví dụ như dấu ngã, vì vậy chữ số cho số một được mã hóa là ~ 1 ~ và bất cứ thứ gì không phải là từ khóa và không được đặt trong dấu ngoặc kép đều được coi là một tên biến .

Vì vậy, bạn có thể mã các câu lệnh như:

1 = ~2~
two = 1 * ~2~

Nhưng cũng:

2 = ~3~
six = 2 + 2

Bất cứ cú pháp nào bạn chọn mơ hồ và khó theo dõi mã là không thể tránh khỏi.

Ngôn ngữ C và hầu hết các ngôn ngữ "ngoặc nhọn" xuất phát từ C cũng nghĩ rằng nên cho phép các lập trình viên viết mã trực tiếp các chữ Octal và Hexadecimal, và, chỉ định loại chữ nếu điều này quan trọng. Vì thế

010  // Octal 10 = 8;
0x10 // Hexadecimal 10 = 16;
5l   // long integer with decimal value 5
2.0d // double float with value 2

Vì vậy, ngay cả khi bạn cho phép các tên biến bắt đầu bằng một số theo sau là sự kết hợp của các số và chữ cái bao gồm ít nhất một chữ cái, bạn sẽ đưa ra cho lập trình viên vấn đề quyết định xem một nhóm nhất định có tạo thành một tên biến hay một chữ số không

2lll = 22 // OK
2ll  = 2  // compiler error

Sự mơ hồ như vậy sẽ không giúp được ai viết hay đọc một chương trình.

Đối với một ví dụ trong thế giới thực có liên quan chặt chẽ, bạn có thể xem ngôn ngữ PL / 1 mà các nhà thiết kế nghĩ rằng có thể sử dụng từ khóa làm tên biến là một ý tưởng hay để:

IF THEN THEN THEN = ELSE; ELSE ELSE = THEN;
IF IF THEN ELSE = IF; ELSE THEN = ELSE;
DO WHILE (WHILE = DO); END = WHILE + DO; END;

Là mã hợp lệ biên dịch và thực thi.


C được thiết kế dưới dạng lắp ráp di động cho Unix. Unix ban đầu được thiết kế cho máy 18 bit, trong đó bát phân phù hợp để in theo cách tương tự hex là phù hợp để in các giá trị máy 8/16/32 bit. Do đó họ thực sự cần bát phân.

Ngoài ra đối với việc vặn bit (OR, XOR, AND, KHÔNG) và triển khai trình điều khiển thiết bị, điều quan trọng là chỉ định kích thước chính xác của một chữ cũng như giá trị!
James Anderson

10

Fortran có ảnh hưởng rất lớn đến cách các ngôn ngữ sau này được thiết kế. Ngay từ sớm (một số vấn đề đã được khắc phục) Fortran gần như không có quy tắc nào giới hạn tên bạn có thể đặt cho một định danh. Điều này làm cho ngôn ngữ cực kỳ khó phân tích cả cho trình biên dịch và lập trình viên. Đây là một ví dụ kinh điển:

if if .eq. then then = else else else = endif endif
K  I   K   K    I      I    K    I      I     K

Ở đây tôi đã đánh dấu "từ khóa ngôn ngữ" bằng K và số nhận dạng (tên biến) I. Cho rằng không có sự khác biệt về chính tả, tôi nghĩ bạn có thể hiểu điều này có thể gây nhầm lẫn như thế nào. Tất nhiên, đây là một ví dụ cực đoan và không có ai từng viết mã khá giống như thế này. Đôi khi, mọi người đã "tái chế" các từ khóa ngôn ngữ làm tên định danh - và trong nhiều trường hợp, một lỗi đánh máy đơn giản có thể dẫn đến mã mà thông số ngôn ngữ nói nên được phân tích theo cách này, mặc dù nó hoàn toàn không có ý định. Đối với một ví dụ nổi tiếng khác, hãy so sánh điều này:

do 10 i = 1,10

đến đây:

do 10 i = 1.10

Đầu tiên là một vòng lặp do - lặp lại một khối mã 10 lần. Tuy nhiên, dấu phẩy thứ hai đã thay đổi dấu phẩy thành dấu thập phân, do đó, nó gán giá trị 1.10cho một biến có tên do 10 i.

Điều này cũng có nghĩa là việc viết một trình phân tích cú pháp Fortran tương đối khó khăn - bạn không thể chắc chắn rằng doở đầu dòng thực sự là một từ khóa cho đến khi bạn đạt đến cuối dòng và xác minh rằng tất cả các yếu tố khác của một dovòng lặp đã có mặt. Trình phân tích cú pháp nói chung phải sẵn sàng "quay lui", phân tích lại dòng từ đầu để đi đến câu trả lời "chính xác" (nhưng thường không có chủ ý) về những gì thực sự ở đó.

Sau một vài năm, các nhà thiết kế ngôn ngữ (hầu hết trong số họ dù sao) đã đi về phía cực đoan - hạn chế gần như mọi thứ về ngôn ngữ càng nhiều càng tốt mà không khiến người dùng phàn nàn quá nhiều.

Chẳng hạn, BASIC ban đầu, về cơ bản cho biết bạn thậm chí không thể sử dụng một từ khóa như một phần của mã định danh - ví dụ, fora=1sẽ được phân tích cú pháp dưới dạng for a = 1(nghĩa là bắt đầu một forvòng lặp, không phải là một bài tập). Điều đó rõ ràng đã tạo ra đủ khiếu nại mà nó không kéo dài rất lâu. Quy tắc về việc bắt đầu một mã định danh bằng một chữ số dường như không tạo ra nhiều khiếu nại, vì vậy nó tiếp tục được sử dụng (ít nhất là trong hầu hết các ngôn ngữ).


IMHO này là gần nhất với lý do thực sự. Các ngôn ngữ ban đầu như Fortran, theo một cách nào đó, quá không có cấu trúc, dẫn đến khó khăn trong việc viết các trình biên dịch mạnh mẽ và khó khăn cho con người để phân tích chính xác mã nguồn. "Do10i = ..." là một ví dụ cổ điển và nổi tiếng. Khi ngôn ngữ phát triển, một số quy tắc đã được thắt chặt. Algol có lẽ là ông nội của "định danh bắt đầu bằng chữ cái và sau đó có thể có chữ cái hoặc số" theo quy tắc ngón tay cái.
Larry Gritz

FF Điều này đã được thực hiện mà không có bất kỳ phân tích cú pháp. Sau đó, khi chạy chương trình, trình thông dịch sẽ giả sử bất kỳ chữ cái nào được tìm thấy là một phần của tên biến.
supercat

1

Có khả năng quy ước này đã phát triển từ các quyết định thiết kế ngôn ngữ lịch sử rất sớm, vì trên các máy đầu tiên, toàn bộ trình biên dịch, bao gồm phân tích từ vựng, phải chạy trong một vài từ, ít bộ nhớ hơn cả bộ đệm dữ liệu của bộ xử lý cấp đầu tiên trên các thiết bị di động hiện tại, vì vậy các tên biến được phép rất hạn chế và phải dễ phân biệt với các hằng số trong rất ít mã op.

Do đó, quy ước đã trở thành những gì các thế hệ lập trình viên được sử dụng.


1

Đây không phải là quy tắc bắt buộc về ngôn ngữ lập trình mà chỉ là quy ước được nhiều nhà thiết kế ngôn ngữ sử dụng.

Tôi có thể thiết kế ngôn ngữ hoàn toàn khác nhau cho phép tất cả các ký tự cho định danh. Đối với tất cả các dòng mã, 20 ký tự đầu tiên sẽ mô tả loại câu lệnh, sau đó 20 ký tự tiếp theo sẽ xác định ký hiệu đầu tiên cho câu lệnh và 20 ký tự tiếp theo là toán hạng cho câu lệnh. Ngôn ngữ này sẽ được thực thi trên bộ xử lý ngăn xếp.

01234567890123456789 01234567890123456789 01234567890123456789

decl symbol          12345                
assign value         12345                12345
decl symbol          99999                
assign value         99999                12345
push                 12345
push                 99999
add
print top

Mã này có thể được dịch bằng C như sau:

int i12345 = 12345;
int i99999 = 12345;
printf("%d", i12345+i9999);

Đó là tất cả. Điều đó là vô nghĩa và quy tắc không có số định danh cũng vô nghĩa trong nền tảng logic.


0

Ngoài "sự tiện lợi cho người từ chối", tôi nghĩ nó cũng đáng để xem xét "sự tiện lợi cho người đọc".

Khi đọc mã, bạn cần nhanh chóng và liên tục xác định từ nào là định danh và số nào là số. Tìm kiếm một chữ số ở đầu dễ dàng hơn trong việc khớp mẫu trực quan của chúng tôi; Sẽ là một việc vặt nếu chúng ta phải kiểm tra cẩn thận tất cả các nhân vật để đảm bảo.


0

Câu trả lời cho câu hỏi này nằm ở automata hoặc chính xác hơn là automata hữu hạn xác định biểu thức chính quy. Quy tắc là ... trình biên dịch cần các thuật toán hoặc quy tắc chính xác để quyết định tại mọi ký tự mà chúng phân tích. Nếu số nhận dạng được cho phép bắt đầu bằng một số thì trình biên dịch sẽ ở trạng thái sửa chữa..bạn bản chất của mã thông báo sắp tới ... nó sẽ là số hoặc số nhận dạng ... và vì trình biên dịch không thể quay lại vị trí trước đó .. .so..để làm rõ cho trình biên dịch rằng mã thông báo sắp tới chính xác là mã định danh hoặc số ... hạn chế này là có ... vì trình biên dịch này biết chỉ bằng cách quét ký tự đầu tiên mà mã thông báo sắp tới là một định danh hoặc một số.

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.