식별자가 숫자로 시작하지 않아야하는 이유는 무엇입니까?


32

대부분의 프로그래밍 언어는 숫자로 시작하는 식별자를 선언 할 수 없도록 설계되었습니다. 나는 그 이유를 알고 싶어했습니다. 이미 웹을 검색했지만 만족스러운 설명을 찾을 수 없습니다.


4
명확성과 가독성에 도움이되는 변수 이름의 단일 예가 있습니까?
보안

5
@Secure : 3dspline, 4seasonPizza, 2pdfConverter, 8bitInt, ...
사용자 알 수 없음

6
넷째 는 그것을 허용합니다. 2DUP, 2DROP, 2SWAP, 2> R, 2R @, 2R>, 0 = 등 : 내장 - 인
피터 모텐슨

TCL을 수행하지만 난 생각하지 않는 한 표준 TCL의 명령 중 하나는 숫자로 시작
JK합니다.

답변:


51

C / C ++에서 숫자 다음에 문자가 오는 것은 숫자 상수로 간주되며 다음에 오는 문자열은 상수 유형을 규정합니다. 예를 들어 (VC ++는 표준인지 확실하지 않습니다).

  • 0-부호있는 정수
  • 0l-부호있는 긴 정수
  • 0u-부호없는 정수
  • 0i64-64 비트 부호있는 정수

그것은 렉서 쉽게 임) 그래서 다니엘은 해당 제품이 사용 된 이후뿐만 아니라 B)가 명시 적으로 구분하지 말했듯이 있습니다 변수가 될하지만 0U은 결코 것입니다. 또한 "i64"와 같은 다른 한정자는 "l"또는 "u"보다 늦게 추가되었으며 필요한 경우 옵션을 더 추가 할 수있는 옵션을 유지하려고합니다.


7
또한 16 진 숫자는 0xd + 형식으로 작성됩니다. 여기서 d +는 1 개의 16 진 숫자 0-f입니다. 따라서 0xbeef는 완벽하게 유효한 "숫자"입니다.
tcrosley

20
너희들은 내가 언어 사양에 가지 않을 것이라는 것을 알고 있지만 요점을 설명하기 위해 몇 가지 예 만 제공했다.
DXM

6
Re : "필요한 경우 추가 옵션을 열어 놓고 옵션을 유지하고 싶습니다": 그리고 C ++ 11을 사용하면 자신 만의 옵션을 추가 할 수도 있습니다. http://en.wikipedia.org/wiki/C++11#User-defined_literals를 참조하십시오 .
ruakh

2
나는 이것이 올바른 설명이라고 생각하지 않습니다. "식별자는 숫자로 시작할 수 없습니다"규칙은 Algol, Pascal 및 숫자 상수에 알파벳 접미사를 허용하지 않는 다른 언어에 적용되었습니다.
래리 그 리츠

1
@LarryGritz : "일관 적으로 단어를 공백으로 분리하는 것은 AD 10 세기 경에 일반적인 관습이되었으며, FORTRAN이 연습을 포기한 1957 년까지 지속되었습니다." —Sun FORTRAN 참조 설명서 (wiki에서 제공). Fortran은 일반적으로 공간이 선택 사항이라고 결정했기 때문에 특별한 이유가있었습니다. 공백과 같은 현대 언어. 당신은 Algol과 함께 당신 자신에 있지만 나는 그 중 어느 것도 현대적이지 않습니다. 반면에 C / C ++ / C # / F #에는 모두 접미사가 있습니다.
DXM

49

렉서를 구현하는 사람들의 편의성. (아니오, 진지하게, 그것은 그것에 관한 것입니다. 다양한 언어에는 다른 이유가 있지만 궁극적으로 그에 따릅니다.)


2
PEG 또는 다른 최신 구문 분석 기술을 사용하여 숫자로 시작하는 정수 리터럴과 식별자를 쉽게 구별 할 수 있습니다. 프리미티브 렉서를 사용하는 컴파일러조차도 동일한 토큰 카테고리에 넣고 나중에 차별화 할 수 있습니다. 예를 들어 0flu리터럴이고 0glu로컬 식별자 인 경우 매우 어색합니다 .
다니엘 Lubarov

2
사람들이 그들을 구별하는 것은 절대적으로 가능 합니다. 결정은 기술적 요구 사항이 아닌 편의성 (또는 자선이 적을 경우 게으름)에 따라 결정됩니다.
다니엘 피트 맨

2
@DanielPittman : 어휘 분석기에서 할 수없는 신뢰할만한 명확성을 찾기 위해서는 의미 론적 분석이 필요합니다. 렉서에서 결정을 내리면 파서는 더 복잡해지고 어떤 이점이 있습니까? 비용 / 혜택이 매우 좋지 않은 상황 외에도 사례를 처리하는 좋은 방법은 없습니다. int 0u = 5; unsigned int x = 0u;그러나이 코드의 해석을 정의하도록 선택하면 (예 : x == 0 또는 x == 5) 사람들은 혼란스러워합니다. 모호성 때문에 이런 식으로 컴파일러를 구현하는 것이 사소한 일이지만 훌륭한 디자이너는 그렇게하지 않을 것입니다.
Joren

10
주요 편의는 언어를 만든 사람이 아니라 내 머릿속 파서입니다.
코드 InChaos

2
어휘 분석이 일반적으로 컴파일러 / 통역기의 가장 느린 단계에 큰 요인이라는 사실을 알고있는 것은 많은 사람들에게 여전히 놀라운 일입니다.
hippietrail

20

다음 두 가지 경우를 고려하십시오.

사례 1

식별자가 숫자로 시작할 수 있다고 가정합니다.

따라서 식별자는 1 문자 이상을 가질 수 있으므로 아래와 같은 문장이 유효합니다.

int 3;

프로그램에서 위의 변수를 사용하려고하면 컴파일러 모호성이 발생합니다.

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

진술 a=3에서 3의 역할은 무엇입니까 (값 5의 변수입니까, 아니면 숫자 3입니까)?

사례 2

위의 예와 달리, 언어는 숫자로 시작하는 식별자를 실제로 식별자로 사용하는 것을 허용하지 않고 숫자로 시작하는 식별자를 실제로 허용한다고 가정합니다. 다음과 같은 문제가 발생할 수 있습니다.

  • 변수에 대한 언어 규칙은 변수가 1 개 이상의 문자로 구성 될 수 있음을 나타내는 다음과 같은 복잡한 규칙으로 다시 정의되어야합니다. 변수는 하나 이상의 문자를 가질 수 있으며 변수가 숫자로 시작하지 않으면 고유해야합니다. 숫자 등으로 시작할 때 단일 문자 길이를 사용할 수 없습니다.

  • 컴파일러는 모든 숫자 (예 : 333)와 유효한 알파벳 접미사 (예 : 34L)를 변수 이름으로 사용하는 경우 오류 사례를 확인하고보고해야합니다. 변수를 선언하지 않고 즉석에서 변수를 사용할 수있는 Python 및 JS와 같이 느슨하게 입력 된 언어에서는 모든 숫자와 관련된 특수한 경우를 확인하는 것이 불가능할 수도 있습니다. 예를 들어 if (33==5), 33은 사용자가 선언 한 잘못된 선언되지 않은 변수 일 수 있습니다. 그러나 컴파일러는이를 식별하고 오류를보고 할 수 없습니다.

이 제한을 설정하면 프로그래머가 숫자를 식별자 이름으로 사용하지 못하게됩니다.


2
이 논리에서 식별자는 키워드와 모호하므로 문자를 포함 할 수 없습니다. 얼마나 재앙 int char = float이 될지 상상이 되십니까 ?
Pubby

4
@ Pubby : 나는 아직 이해할 수없는 완전히 말도 안되는 말을 외삽 할 수있는 방법을 모르겠습니다. 당신의 의견은 무엇을 의미합니까?
aml90

나는 당신이 문자 그대로 너무 질문을하고 렉싱 우선 순위를 사용하여 전혀 모호하지 않다고 말하고 있습니다. 예를 들어, 컴파일러 int는 식별자가 아닌 키워드를 어떻게 알 수 있습니까? 글쎄, int숫자 형 exemes와 마찬가지로 우선 순위가 높습니다.
Pubby

@Pubby : 모호성으로 인해 컴파일러가 변수 이름을 사용하는 컨텍스트 (어휘 우선 순위를 사용)를 알 수 없음을 의미했습니다. 예를 들어, 다음 코드를 고려 int 3,a; 3=5; a=3; 하십시오. a = 3 명령문에서 3은 식별자 또는 숫자로 해석됩니까? 모호함이 발생합니다. 그것이 분명하기를 바랍니다.
aml90

2
나는 또한이 주장이 약하다는 것을 안다. 숫자로 시작하지만 완전히 구성되지 않은 식별자를 받아 들일 수있는 어휘 분석기를 작성하는 것은 쉽지 않습니다.
Larry Gritz

11

대부분의 경우 이것은 컴파일러 작성자와 구문 분석 효율성을 쉽게 만드는 것과는 관련이 없지만 명확하고 읽기 쉽고 명확한 코드를 장려하는 구문을 설계하는 것과 관련이 있습니다.

언어 디자이너는 숫자 1과 같은 숫자 리터럴을 평범한 1 로 쓸 수 있으면 좋을 것이라고 생각했습니다 .

숫자 리터럴이 tildas와 같은 방식으로 인용되는 언어 구문을 설계하는 것이 가능하므로 숫자 1의 숫자 리터럴은 ~ 1 ~ 로 인코딩되고 키워드가 아니며 따옴표로 묶지 않은 것은 변수 이름으로 취급됩니다 .

따라서 다음과 같은 명령문을 코딩 할 수 있습니다.

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

또한 :

2 = ~3~
six = 2 + 2

모호하고 따르기 어려운 구문을 선택하는 것은 피할 수 없습니다.

C 언어와 C의 하위 "대괄호"언어는 프로그래머가 8 진 및 16 진 리터럴을 직접 코딩하고 이것이 중요한 경우 리터럴 유형을 지정할 수 있도록하는 것이 좋습니다. 그래서

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

따라서 변수 이름이 숫자로 시작하고 하나 이상의 문자를 포함하는 숫자와 문자의 조합으로 시작하더라도 프로그래머가 주어진 그룹이 변수 이름 또는 숫자 리터럴을 형성하는지 여부를 결정하는 문제를 제시하게됩니다.

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

이러한 모호성은 프로그램을 쓰거나 읽는 사람에게는 도움이되지 않습니다.

밀접하게 관련된 실제 예를 들어, 디자이너가 키워드를 변수 이름으로 사용할 수 있다고 생각한 PL / 1 언어를 보면 다음과 같습니다.

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

컴파일하고 실행하는 유효한 코드입니다.


C는 Unix 용 휴대용 어셈블리로 설계되었습니다. Unix는 원래 8 비트가 8/16/32 비트 기계 값을 인쇄하기에 적합한 것과 같은 방식으로 8 진수가 인쇄에 적합한 18 비트 기계를 위해 설계되었습니다. 그러므로 그들은 실제로 8 진이 필요했습니다.

또한 비트 트위들 링 (OR, XOR, AND, NOT) 및 장치 드라이버 구현의 경우 리터럴의 정확한 크기와 값을 지정하는 것이 중요합니다!
제임스 앤더슨

10

포트란은 후기 언어가 어떻게 설계되었는지에 큰 영향을 미쳤다. 초기에 (이러한 문제 중 일부는 수정되었으므로) Fortran에는 식별자에 부여 할 수있는 이름을 제한하는 규칙 이 거의 없었습니다. 이로 인해 컴파일러와 프로그래머 모두 언어를 구문 분석하기가 매우 어려워졌습니다. 전형적인 예가 하나 있습니다 :

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

여기서는 "언어 키워드"를 K와 식별자 (변수 이름)로 표시했습니다. 철자에 차이가없는 것을 감안할 때, 이것이 어떻게 혼동 될 수 있는지 이해할 수있을 것입니다. 물론 이것은 극단적 인 예이며, 의도적으로 이와 같은 코드를 작성한 사람은 거의 없습니다. 때때로 사람들 식별자 이름으로 언어 키워드를 "재활용"했습니다. 많은 경우에 간단한 오타로 인해 언어 사양이 전혀 의도되지 않았더라도 이러한 방식으로 구문 분석되어야한다는 코드가 생성 될 수 있습니다. 다른 잘 알려진 예를 보려면 다음을 비교하십시오.

do 10 i = 1,10

이에:

do 10 i = 1.10

첫 번째는 do 루프입니다. 코드 블록을 10 번 반복합니다. 그러나 두 번째는 쉼표가 소수점으로 바뀌 었으므로 값 1.10을 변수에 할당합니다 do 10 i.

이것은 또한 포트란 파서를 작성하는 것이 상대적으로 어렵다는 것을 의미했습니다 do. 줄의 시작 부분이 줄의 끝에 도달 할 때까지 실제로 핵심 단어 임을 확신 할 수 없었 습니다. do루프가 존재했습니다. 파서는 일반적으로 처음부터 줄을 다시 파싱하여 실제로 존재했던 것에 대한 "올바른"(그러나 종종 의도하지 않은) 대답에 도달하도록 "역 추적"할 준비가되어 있어야했습니다.

이 몇 년 후, 언어 디자이너는 (그들의 대부분 어쨌든) 반대의 극단으로 갔다 - 불평하는 사용자없이 가능한 한만큼 언어에 대한 거의 모든 제한 이 너무 많이.

예를 들어 초기 BASIC은 기본적으로 키워드의 일부 를 식별자의 일부로 사용할 수 없다고 말했습니다. 예를 들어, 할당이 아닌 루프 의 시작과 fora=1같이 구문 분석됩니다 . 그것은 오래 가지 못했던 충분한 불만을 제기 한 것 같습니다. 숫자로 식별자를 시작하는 규칙은 많은 불만을 발생시키지 않았으므로 계속 사용됩니다 (적어도 대부분의 언어에서).for a = 1for


IMHO 이것은 실제 이유에 가장 가깝습니다. 포트란과 같은 초기 언어는, 어떤 방법으로, 한 너무 정확하게 시각적으로 소스 코드를 구문 분석에 인간에 대한 강력한 컴파일러와 어려움을 쓰기의 어려움에 이르는 비정형. "do10i = ..."는 고전적이고 유명한 예입니다. 언어가 발전함에 따라 일부 규칙이 강화되었습니다. Algol은 아마도 표준 "식별자는 문자로 시작하여 문자 나 숫자를 가질 수있다"라는 규칙의 할아버지 일 것이다.
래리 그 리츠

참고로, BASIC의 가장 인기있는 마이크로 컴퓨터 버전 (Applesoft Basic 및 Commodore Basic 포함)을 기반으로하는 Microsoft BASIC 인터프리터 인 FYI는 탐욕스러운 토크 나이저를 사용하여 언어 토큰과 일치하는 모든 문자 시퀀스를 높은 비트 세트의 바이트 값으로 변환했습니다. 이것은 구문 분석없이 수행되었습니다. 그런 다음 프로그램을 실행할 때 인터프리터는 찾은 문자가 변수 이름의 일부라고 가정합니다.
supercat

1

어휘 분석을 포함한 전체 컴파일러는 현재 모바일 장치의 첫 번째 수준의 프로세서 데이터 캐시보다 메모리가 적은 몇 kWord에서 실행되어야했기 때문에이 규칙은 초기 언어 설계 결정에서 매우 초기에 발전했을 것입니다. 따라서 허용되는 변수 이름은 매우 제한적이며 매우 적은 op 코드에서 숫자 상수와 쉽게 구별 할 수 있어야했습니다.

따라서,이 협약은 세대의 프로그래머들이 익숙한 것이되었습니다.


1

프로그래밍 언어에는 논리적으로 필요한 규칙이 아니라 많은 언어 디자이너가 사용하는 규칙 일뿐입니다.

식별자에 모든 문자를 허용하는 완전히 다른 언어를 디자인 할 수 있습니다. 모든 코드 행에서 처음 20 자 문자는 명령문 유형을 설명하고 다음 20 자 문자는 명령문의 첫 번째 기호를 정의하며 다음 20 자 문자는 명령문의 피연산자입니다. 이 언어는 스택 프로세서에서 실행됩니다.

01234567890123456789 01234567890123456789 01234567890123456789

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

이 코드는 다음과 같이 C로 번역 될 수 있습니다.

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

그게 다야. 의미가없고 번호가없는 수 규칙도 논리적으로 무의미합니다.


0

"렉서의 편의성"외에도 "독자의 편의성"도 고려할 가치가 있다고 생각합니다.

코드를 읽을 때 어떤 단어가 식별자이고 어떤 단어가 숫자인지 신속하고 반복적으로 식별해야합니다. 시각적 패턴 일치에서 처음에 숫자를 찾는 것이 더 쉽습니다. 모든 문자를주의 깊게 확인해야한다면 문제가 될 것입니다.


0

이 질문에 대한 답은 오토마타 또는 정규식을 정의하는보다 정확한 유한 오토마타에 있습니다. 규칙은 ... 컴파일러가 구문 분석하는 모든 문자를 결정하기 위해 정확한 알고리즘이나 규칙이 필요하다는 것입니다. 식별자가 숫자로 시작하도록 허용되면 컴파일러는 토큰의 성격에 대해 수정됩니다. 숫자 또는 식별자가 될 것입니다. 컴파일러는 이전 위치로 되돌릴 수 없습니다. .so .. 다가오는 토큰이 정확하게 식별자 또는 숫자라는 것을 컴파일러에게 분명히하기 위해 ...이 제한이 있습니다 ... 이것의 coz ... 컴파일러는 다가오는 토큰이라는 첫 문자를 스캔하여 알 수 있습니다. 식별자 또는 숫자입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.