Mengapa pengidentifikasi tidak dimulai dengan angka?

32

Sebagian besar bahasa pemrograman tampaknya dirancang untuk tidak memungkinkan seseorang mendeklarasikan pengenal yang dimulai dengan angka. Saya hanya ingin tahu alasannya. Saya sudah mencari di web, tetapi tidak dapat menemukan penjelasan yang memuaskan.

Sivasubramaniam Arunachalam
sumber
4
Apakah Anda memiliki satu contoh nama variabel di mana itu akan bermanfaat bagi kejelasan dan keterbacaan?
Amankan
5
@Keamanan: 3dspline, 4seasonPizza, 2pdfConverter, 8bitInt, ...
pengguna tidak diketahui
6
Keempat memungkinkan itu. Dari built-in: 2DUP, 2DROP, 2SWAP, 2> R, 2R @, 2R>, 0 =, dll.
Peter Mortensen
seperti halnya TCL tapi saya tidak berpikir salah satu perintah TCL standar dimulai dengan angka
jk.
1
Kemungkinan sama pada SO: stackoverflow.com/questions/342152/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

51

Dalam C / C ++, angka yang diikuti oleh huruf dianggap sebagai konstanta numerik dan string yang mengikuti, memenuhi syarat jenis konstanta. Jadi misalnya (ini VC ++, tidak yakin bagaimana standarnya):

  • 0 - bilangan bulat yang ditandatangani
  • 0l - bilangan bulat panjang yang ditandatangani
  • 0u - bilangan bulat tak bertanda
  • 0i64 - 64 bit integer bertanda tangan

Jadi a) lebih mudah bagi lexer seperti yang dikatakan Daniel tetapi juga b) ia membuat perbedaan eksplisit karena 0y mungkin variabel tetapi 0u tidak akan pernah. Ditambah kualifikasi lainnya, seperti "i64" ditambahkan lebih lambat dari "l" atau "u" dan mereka ingin menjaga opsi terbuka untuk menambahkan lebih banyak jika diperlukan.

DXM
sumber
7
juga, angka hex ditulis dalam bentuk 0xd + di mana d + adalah 1 digit hex lebih 0-f - jadi 0xbeef adalah "angka" yang benar-benar valid.
tcrosley
20
kalian benar-benar sadar bahwa saya tidak akan pergi untuk spec bahasa, tetapi hanya memberikan beberapa contoh untuk mengilustrasikan poin, kan?
DXM
6
Re: "mereka ingin menjaga opsi terbuka untuk menambahkan lebih banyak jika diperlukan": Dan C ++ 11 bahkan memungkinkan Anda menambahkan sendiri; lihat http://en.wikipedia.org/wiki/C++11#User-defined_literals .
ruakh
2
Saya kira ini bukan penjelasan yang tepat. Aturan "pengidentifikasi tidak dapat dimulai dengan angka" adalah benar untuk Algol, Pascal, dan bahasa lain yang tidak mengizinkan sufiks alfabet ke konstanta numerik.
Larry Gritz
1
@LarryGritz: "Secara konsisten memisahkan kata-kata dengan spasi menjadi kebiasaan umum tentang abad kesepuluh, dan berlangsung hingga sekitar tahun 1957, ketika FORTRAN meninggalkan praktik tersebut." —Sun Manual Referensi FORTRAN (dari wiki). Fortran memiliki alasan khusus sendiri karena mereka memutuskan ruang secara umum adalah opsional. Bahasa modern menyukai spasi putih mereka. Anda sendirian dengan Algol, tetapi saya juga tidak modern seperti itu. Di sisi lain C / C ++ / C # / F # semua memiliki akhiran.
DXM
49

Kenyamanan orang-orang yang mengimplementasikan lexer. (Tidak, serius, itu saja. Berbagai bahasa punya alasan lain, tetapi akhirnya sampai pada itu.)

Daniel Pittman
sumber
2
Akan mudah untuk membedakan antara literal integral dan pengidentifikasi dimulai dengan angka menggunakan PEG atau teknik penguraian modern lainnya. Bahkan kompiler yang menggunakan primitif lexer dapat menempatkan mereka dalam kategori token yang sama dan kemudian dibedakan. Akan sangat canggung jika eg 0fluadalah literal dan 0glupengenal lokal.
Daniel Lubarov
2
Sangat mungkin bagi orang untuk membedakan mereka. Keputusan dibuat berdasarkan kenyamanan (atau, jika Anda kurang amal, malas) daripada persyaratan teknis.
Daniel Pittman
2
@DanielPittman: Anda perlu analisis semantik untuk melakukan segala jenis disambiguasi yang andal, sehingga tidak dapat dilakukan di lexer. Mendorong keputusan keluar dari lexer membuat parser lebih kompleks, dan apa untungnya? Selain situasi biaya / manfaat yang sangat buruk, tidak ada cara yang baik untuk menangani kasus seperti int 0u = 5; unsigned int x = 0u;Namun Anda memilih untuk mendefinisikan interpretasi kode ini (kemungkinan baik x == 0 atau x == 5), orang akan menjadi bingung karena ambiguitas. Bahkan jika itu sepele untuk mengimplementasikan kompiler dengan cara ini, seorang desainer yang baik kemungkinan tidak akan melakukannya.
Joren
10
Kenyamanan utama adalah untuk pengurai di kepalaku, dan bukan untuk pencipta bahasa.
CodesInChaos
2
Masih mengejutkan bagi banyak orang untuk mengetahui bahwa analisis leksikal biasanya menjadi faktor besar tahap paling lambat dari kompiler / juru bahasa.
hippietrail
20

Pertimbangkan 2 kasus berikut:

Kasus 1

Mari kita asumsikan bahwa pengidentifikasi dapat dimulai dengan angka.

Jadi pernyataan seperti di bawah ini akan valid (karena pengidentifikasi dapat memiliki 1 atau lebih karakter):

int 3;

Ketika saya mencoba menggunakan variabel di atas dalam suatu program, itu akan menghasilkan ambiguitas kompiler:

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

Dalam pernyataan itu a=3apa peran 3 (apakah itu variabel dengan nilai 5 atau itu angka 3)?

Kasus 2

Berbeda dengan contoh di atas, mari kita asumsikan bahwa bahasa sebenarnya memungkinkan pengidentifikasi dimulai dengan angka sementara masih melarang angka digunakan sebagai pengidentifikasi. Ini dapat menyebabkan masalah berikut:

  • Aturan bahasa mengenai variabel yang mengatakan bahwa suatu variabel dapat terdiri dari 1 atau lebih karakter harus didefinisikan ulang menjadi aturan yang kompleks seperti: Sebuah variabel dapat memiliki satu atau lebih karakter dan harus unik jika tidak dimulai dengan angka sementara tidak boleh panjang karakter tunggal ketika mulai dengan angka (dll.)

  • Kompiler harus memeriksa dan melaporkan kasus kesalahan ketika semua angka (mis. 333) dan akhiran alfabet yang valid (mis. 34L) digunakan sebagai nama variabel. Dalam bahasa yang diketik secara longgar seperti Python dan JS di mana Anda dapat menggunakan variabel dengan cepat tanpa mendeklarasikannya, bahkan mungkin tidak mungkin untuk memeriksa kasus-kasus khusus yang melibatkan semua angka misalnya if (33==5)33. Tetapi kompiler tidak akan dapat mengidentifikasi ini dan melaporkan kesalahan.

Membuat batasan ini akan mencegah programmer menggunakan angka sebagai nama pengidentifikasi.

aml90
sumber
2
Di bawah logika ini, pengidentifikasi tidak dapat berisi karakter karena mereka akan ambigu dengan kata kunci. Bisakah Anda bayangkan betapa buruknya bencana int char = floatitu?
Pubby
4
@Ubby: Saya tidak melihat bagaimana Anda bisa meramalkan apa yang saya katakan kepada beberapa rasa tidak masuk akal yang saya belum tahu. Apa komentar Anda?
aml90
Saya mengatakan bahwa Anda mengambil pertanyaan terlalu harfiah dan itu sama sekali tidak ambigu dengan menggunakan prioritas lexing. Misalnya, bagaimana kompiler tahu intadalah kata kunci dan bukan pengidentifikasi? Nah, intmemiliki prioritas lebih tinggi seperti halnya leksem numikal.
Pubby
@Ubby: Dengan ambiguitas saya maksudkan bahwa kompiler tidak akan tahu dalam konteks apa saya menggunakan nama variabel (bahkan menggunakan lexical precedence). Untuk misalnya, pertimbangkan kode ini: int 3,a; 3=5; a=3; Dalam pernyataan a = 3, apakah 3 ditafsirkan sebagai pengidentifikasi atau sebagai angka? Ini menyebabkan ambiguitas. Semoga ini jelas.
aml90
2
Saya juga menemukan argumen ini lemah. Akan sepele untuk menulis lexer yang akan menerima pengidentifikasi yang dimulai dengan, tetapi tidak seluruhnya terdiri dari, angka.
Larry Gritz
11

Sebagian besar ini tidak ada hubungannya dengan membuatnya mudah bagi penulis kompiler dan efisiensi penguraian, tetapi, lebih berkaitan dengan merancang sintaks yang mendorong kode yang mudah dibaca dan tidak ambigu.

Para desainer bahasanya berpikir akan lebih baik untuk dapat menulis literal angka seperti angka 1 sebagai sekadar 1 .

Sangat mungkin untuk merancang sintaksis bahasa di mana literal numerik dikutip dalam beberapa cara misalnya tildas sehingga literal numerik untuk nomor satu dikodekan sebagai ~ 1 ~ dan segala sesuatu yang bukan kata kunci dan tidak dilampirkan dalam kutipan diperlakukan sebagai nama variabel .

Jadi Anda bisa membuat kode pernyataan seperti:

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

Tetapi juga:

2 = ~3~
six = 2 + 2

Sintaks apa pun yang Anda pilih ambigu dan sulit diikuti kode tidak dapat dihindari.

Bahasa C dan sebagian besar bahasa "kurung keriting" diturunkan dari C juga menganggap itu ide yang baik untuk memungkinkan programmer untuk kode Oktal dan Hexadecimal literal secara langsung, dan, untuk menentukan jenis literal jika ini penting. Begitu

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

Jadi, bahkan jika Anda mengizinkan nama variabel dimulai dengan angka diikuti dengan kombinasi angka dan huruf yang menyertakan setidaknya satu huruf, Anda akan memberikan masalah pada programmer untuk memutuskan apakah suatu kelompok tertentu membentuk nama variabel atau literal numerik sehingga

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

Ambiguitas seperti itu tidak akan membantu siapa pun menulis atau membaca program.

Untuk contoh dunia nyata yang berhubungan dekat, Anda dapat melihat bahasa PL / 1 yang perancangnya berpikir bahwa menggunakan kata kunci sebagai nama variabel adalah ide yang bagus sehingga:

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

Adalah kode yang valid yang mengkompilasi dan mengeksekusi.

James Anderson
sumber
C dirancang sebagai rakitan portabel untuk Unix. Unix pada awalnya dirancang untuk mesin 18-bit, di mana oktal cocok untuk dicetak dengan cara yang sama hex juga cocok untuk mencetak nilai mesin 8/16/32-bit. Karena itu mereka benar-benar membutuhkan oktal.
Juga untuk bit twiddling (OR, XOR, AND, NOT) dan mengimplementasikan driver perangkat penting untuk menentukan ukuran literal dan nilai yang tepat!
James Anderson
10

Fortran memiliki efek besar pada bagaimana bahasa dirancang nanti. Sejak awal (beberapa dari masalah ini telah diperbaiki) Fortran hampir tidak memiliki aturan yang membatasi nama apa yang dapat Anda berikan kepada pengidentifikasi. Ini membuat bahasa ini sangat sulit untuk diurai baik untuk kompiler maupun untuk programmer. Inilah satu contoh klasik:

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

Di sini saya telah menandai "kata kunci bahasa" dengan K dan pengidentifikasi (nama variabel) I. Mengingat bahwa tidak ada perbedaan dalam pengejaan, saya pikir Anda mungkin dapat memahami betapa membingungkannya hal ini. Tentu saja, ini adalah contoh ekstrem, dan tidak mungkin ada yang pernah menulis kode seperti ini dengan sengaja. Kadang-kadang orang melakukan "mendaur ulang" kata kunci bahasa sebagai nama pengidentifikasi - dan dalam banyak kasus kesalahan ketik sederhana dapat menghasilkan kode yang spek bahasa katakan harus diuraikan dengan cara ini, meskipun itu tidak dimaksudkan sama sekali. Untuk contoh terkenal lainnya, bandingkan ini:

do 10 i = 1,10

untuk ini:

do 10 i = 1.10

Yang pertama adalah do loop - mengulangi blok kode 10 kali. Namun, yang kedua telah mengubah koma ke titik desimal, sehingga memberikan nilai 1.10ke variabel bernama do 10 i.

Ini juga berarti bahwa menulis parser Fortran relatif sulit - Anda tidak dapat memastikan bahwa dopada awal baris benar-benar kata kunci sampai Anda mencapai akhir baris, dan memverifikasi bahwa semua elemen lain dari sebuah dolingkaran hadir. Pengurai umumnya harus siap untuk "mundur", mem-parsing ulang garis dari awal untuk sampai pada jawaban yang "benar" (tetapi sering tidak disengaja) dari apa yang benar-benar ada.

Setelah beberapa tahun ini, perancang bahasa (kebanyakan dari mereka) pergi ke arah yang berlawanan - membatasi hampir semua hal tentang bahasa sebanyak mungkin tanpa pengguna mengeluh terlalu banyak.

BASIC awal, misalnya, pada dasarnya mengatakan Anda bahkan tidak bisa menggunakan kata kunci sebagai bagian dari pengidentifikasi - misalnya, fora=1akan diuraikan sebagai for a = 1(yaitu, awal dari sebuah forloop, bukan tugas). Yang tampaknya menimbulkan cukup banyak keluhan yang tidak berlangsung lama. Aturan tentang memulai pengidentifikasi dengan digit tampaknya belum menghasilkan banyak keluhan, jadi terus digunakan (setidaknya dalam sebagian besar bahasa).

Jerry Coffin
sumber
IMHO ini paling dekat dengan alasan sebenarnya. Bahasa-bahasa awal seperti Fortran, dalam beberapa hal, terlalu tidak terstruktur, menyebabkan kesulitan menulis kompiler yang kuat dan kesulitan bagi manusia untuk secara benar mengurai kode sumber secara visual. "Do10i = ..." adalah contoh klasik dan terkenal. Seiring perkembangan bahasa, beberapa aturan diperketat. Algol mungkin adalah kakek dari standar "pengidentifikasi mulai dengan huruf dan setelah itu dapat memiliki huruf atau angka" aturan praktis.
Larry Gritz
FYI, interpreter Microsoft BASIC yang membentuk dasar dari versi Microcomputer BASIC yang paling populer (termasuk Applesoft Basic dan Commodore Basic) menggunakan tokenizer serakah untuk mengubah urutan karakter apa pun yang cocok dengan token bahasa menjadi nilai byte dengan bit set tinggi. Ini dilakukan tanpa analisis sintaksis. Kemudian, ketika menjalankan program, penerjemah akan menganggap huruf apa pun yang ditemukannya merupakan bagian dari nama variabel.
supercat
1

Kemungkinan konvensi ini telah berevolusi dari keputusan desain bahasa sejarah yang sangat awal, seperti pada mesin awal seluruh kompiler, termasuk analisis leksikal, harus dijalankan dalam beberapa kWords, lebih sedikit memori daripada hanya cache data prosesor tingkat pertama pada perangkat seluler saat ini, jadi nama variabel yang diizinkan sangat terbatas, dan harus mudah dibedakan dari konstanta numerik dalam kode op yang sangat sedikit.

Dengan demikian, konvensi menjadi generasi generasi programmer yang biasa.

hotpaw2
sumber
1

Ini bukan aturan logis yang diperlukan untuk bahasa pemrograman tetapi hanya konvensi yang digunakan oleh banyak perancang bahasa.

Saya dapat merancang bahasa yang sangat berbeda yang memungkinkan semua karakter untuk pengidentifikasi. Untuk semua baris kode, 20 karakter pertama akan menjelaskan tipe pernyataan lalu 20 karakter berikutnya akan menentukan simbol pertama untuk pernyataan, dan 20 karakter berikutnya adalah operan untuk pernyataan. Bahasa ini akan dieksekusi pada prosesor tumpukan.

01234567890123456789 01234567890123456789 01234567890123456789

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

Kode ini dapat diterjemahkan dalam C seperti di bawah ini:

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

Itu saja. Ini tidak ada artinya dan aturan no-number-in-identifiers juga tidak ada gunanya secara logis.

9dan
sumber
0

Selain "kenyamanan untuk lexer", saya pikir itu juga layak dipertimbangkan "kenyamanan bagi pembaca".

Saat membaca kode, Anda perlu dengan cepat dan berulang kali mengidentifikasi kata mana yang merupakan pengidentifikasi, dan mana yang angka. Mencari digit di awal lebih mudah pada pencocokan pola visual kami; itu akan menjadi tugas jika kita harus hati-hati memeriksa semua karakter untuk memastikan.

datang badai
sumber
0

Jawaban atas pertanyaan ini terletak pada automata atau automata terbatas yang mendefinisikan ekspresi reguler. Aturannya adalah ... kompiler membutuhkan algoritma atau aturan yang tepat untuk memutuskan pada setiap karakter yang diuraikan. Jika pengidentifikasi diizinkan untuk memulai dengan angka maka kompiler akan dalam perbaikan..tentang sifat token yang akan datang ... apakah itu berupa angka atau pengidentifikasi ... dan sebagai kompiler tidak dapat mundur ke posisi sebelumnya .. .so..untuk memperjelas kepada kompiler bahwa token yang datang tepat merupakan pengidentifikasi atau angka ... pembatasan ini ada ... karena ini ... compiler tahu hanya dengan memindai karakter pertama bahwa token yang akan datang adalah pengidentifikasi atau angka.

Waquas
sumber