Wygląda na to, że większość języków programowania nie pozwala na zadeklarowanie identyfikatora rozpoczynającego się cyfrą. Byłem ciekawy, dlaczego. Przeszukałem już sieć, ale nie znalazłem satysfakcjonującego wyjaśnienia.
Wygląda na to, że większość języków programowania nie pozwala na zadeklarowanie identyfikatora rozpoczynającego się cyfrą. Byłem ciekawy, dlaczego. Przeszukałem już sieć, ale nie znalazłem satysfakcjonującego wyjaśnienia.
Odpowiedzi:
W C / C ++ liczba, po której następuje litera, jest uważana za stałą numeryczną, a następujący po niej łańcuch określa jej typ. Na przykład (są to VC ++, nie jestem pewien, jak są one standardowe):
A) a) łatwiej jest leksykonowi, jak powiedział Daniel, ale także b) robi wyraźne rozróżnienie, ponieważ 0y może być zmienną, ale 0u nigdy nie będzie. Plus inne kwalifikatory, takie jak „i64” zostały dodane znacznie później niż „l” lub „u” i chcą pozostawić opcję dodawania większej liczby, jeśli to konieczne.
Wygoda osób wdrażających leksykon. (Nie, poważnie, o to chodzi. Różne języki mają inne powody, ale ostatecznie sprowadza się do tego.)
0flu
Był dosłowny i 0glu
był lokalnym identyfikatorem.
int 0u = 5; unsigned int x = 0u;
Jednak zdecydujesz się zdefiniować interpretację tego kodu (prawdopodobnie x == 0 lub x == 5), ludzie będą zdezorientowani z powodu niejasności. Nawet gdyby wdrożenie kompilatora w ten sposób było banalne, dobry projektant prawdopodobnie by tego nie zrobił.
Rozważ następujące 2 przypadki:
Załóżmy, że identyfikator może zaczynać się od liczby.
Tak więc zdanie takie jak poniżej byłoby prawidłowe (ponieważ identyfikator może mieć 1 lub więcej znaków):
int 3;
Kiedy spróbuję użyć powyższej zmiennej w programie, spowoduje to niejednoznaczność kompilatora:
int 3, a;
3 = 5;
a = 3;
W oświadczeniu a=3
jaka jest rola 3 (czy jest to zmienna o wartości 5, czy też jest liczbą 3)?
W przeciwieństwie do powyższego przykładu, załóżmy, że język faktycznie pozwalałby na identyfikatory zaczynające się od liczby, a jednocześnie nie pozwalał na używanie liczb jako identyfikatorów. Może to powodować następujące problemy:
Reguły językowe dotyczące zmiennej, która mówi, że zmienna może składać się z 1 lub więcej znaków, będą musiały zostać ponownie zdefiniowane do złożonej reguły, takiej jak: Zmienna może mieć jeden lub więcej znaków i musi być unikalna, jeśli nie zaczyna się na cyfrze nie może mieć długości jednego znaku, zaczynając od cyfry (itp.)
Kompilator będzie musiał sprawdzić i zgłosić przypadki błędów, gdy wszystkie nazwy (np. 333) i poprawne sufiksy alfabetu (np. 34L) są używane jako nazwy zmiennych. W luźno wpisanych językach, takich jak Python i JS, w których można używać zmiennych w locie bez ich deklarowania, może nawet być niemożliwe sprawdzenie specjalnych przypadków obejmujących wszystkie cyfry, np. if (33==5)
Tutaj 33 może być błędną niezadeklarowaną zmienną zadeklarowaną przez użytkownika. Ale kompilator nie będzie w stanie tego zidentyfikować i zgłosić błędu.
Wprowadzenie tego ograniczenia uniemożliwi programistom używanie numerów jako nazw identyfikatorów.
int char = float
byłoby?
int
jest słowem kluczowym, a nie identyfikatorem? Cóż, int
ma wyższy priorytet tak numical leksemy miałby.
int 3,a; 3=5; a=3;
w wyrażeniu a = 3, czy 3 jest interpretowane jako identyfikator czy jako liczba? To powoduje niejednoznaczność. Mam nadzieję, że to jasne.
W przeważającej części nie ma to nic wspólnego z ułatwieniem twórcom kompilatorów i wydajnością analizowania, ale bardziej z zaprojektowaniem składni, która zachęca do czytelnego i jednoznacznego kodu.
Projektanci języka uznali, że fajnie byłoby pisać literały liczbowe takie jak cyfra 1 jako zwykły 1 .
Byłoby całkiem możliwe zaprojektowanie składni języka, w której literały liczbowe były cytowane w jakiś sposób, na przykład tylda, więc literał liczbowy dla liczby pierwszej był zakodowany jako ~ 1 ~ i wszystko, co nie było słowem kluczowym i nie było zawarte w cudzysłowach, było traktowane jako nazwa zmiennej .
Abyś mógł kodować takie instrukcje, jak:
1 = ~2~
two = 1 * ~2~
Ale również:
2 = ~3~
six = 2 + 2
Niezależnie od wybranej składni niejednoznaczny i trudny do przestrzegania kod jest nieunikniony.
Język C i większość języków „nawiasów klamrowych” wywodzących się z C również uważało za dobry pomysł, aby umożliwić programistom bezpośrednie kodowanie literałów ósemkowych i szesnastkowych oraz, jeśli to ważne, określić typ literału. Więc
010 // Octal 10 = 8;
0x10 // Hexadecimal 10 = 16;
5l // long integer with decimal value 5
2.0d // double float with value 2
Więc nawet jeśli pozwolisz, aby nazwy zmiennych zaczynały się od liczby, po której następuje kombinacja liczb i litery zawierającej co najmniej jedną literę, chciałbyś programiście rozwiązać problem decydowania, czy dana grupa utworzy nazwę zmiennej, czy też literał liczbowy, więc
2lll = 22 // OK
2ll = 2 // compiler error
Taka dwuznaczność nie pomogłaby nikomu pisać lub czytać programu.
Jako ściśle powiązany przykład ze świata rzeczywistego można przyjrzeć się językowi PL / 1, którego projektanci uznali, że możliwość użycia słów kluczowych jako nazw zmiennych jest dobrym pomysłem, aby:
IF THEN THEN THEN = ELSE; ELSE ELSE = THEN;
IF IF THEN ELSE = IF; ELSE THEN = ELSE;
DO WHILE (WHILE = DO); END = WHILE + DO; END;
Jest poprawnym kodem, który się kompiluje i wykonuje.
Fortran miał ogromny wpływ na sposób projektowania późniejszych języków. Na początku (niektóre z tych problemów zostały już naprawione) Fortran nie miał prawie żadnych reguł ograniczających nazwę, którą można nadać identyfikatorowi. To bardzo utrudniało analizowanie języka zarówno dla kompilatorów, jak i dla programistów. Oto jeden klasyczny przykład:
if if .eq. then then = else else else = endif endif
K I K K I I K I I K
Tutaj zaznaczyłem „kluczowe słowa języka” za pomocą K i identyfikatorów (nazw zmiennych) I. Biorąc pod uwagę, że nie ma różnicy w pisowni, myślę, że prawdopodobnie możesz zrozumieć, jak może to być mylące. Oczywiście jest to skrajny przykład i jest mało prawdopodobne, aby ktokolwiek kiedykolwiek celowo napisał taki kod. Czasami ludzie nie „utylizacja” Język słów kluczowych jak nazwy identyfikatorów chociaż - iw wielu przypadkach prosty literówka mogą wyniknąć w kodzie, który spec język wymienionego powinien być analizowany w ten sposób, mimo że nie miała w ogóle. W innym dobrze znanym przykładzie porównaj to:
do 10 i = 1,10
do tego:
do 10 i = 1.10
Pierwsza to pętla do - iterująca blok kodu 10 razy. W drugim przypadku przecinek został zmieniony na przecinek dziesiętny, więc przypisuje wartość 1.10
do zmiennej o nazwie do 10 i
.
Oznaczało to również, że napisanie parsera Fortrana było stosunkowo trudne - nie można było być pewnym, że do
na początku wiersza było naprawdę kluczowe słowo, dopóki nie osiągnięto końca wiersza, i zweryfikowano, że wszystkie pozostałe elementy do
pętla była obecna. Parser generalnie musiał być gotowy do „cofnięcia się”, parsowania wiersza od początku, aby dojść do „poprawnej” (ale często niezamierzonej) odpowiedzi na to, co naprawdę tam było.
Po kilku latach projektanci języków (większość z nich i tak) poszli w kierunku skrajnej skrajności - ograniczając prawie wszystko w języku tak bardzo, jak to możliwe, bez zbytniego narzekania użytkowników .
Na przykład wczesny język BASIC w zasadzie powiedział, że nie można nawet użyć słowa kluczowego jako części identyfikatora - na przykład fora=1
zostałby przeanalizowany jako for a = 1
(tj. Początek for
pętli, a nie przypisanie). To najwyraźniej wywołało wystarczająco dużo skarg, że nie trwało to długo. Reguła dotycząca rozpoczynania identyfikatora cyfrą najwyraźniej nie spowodowała wielu skarg, więc nadal jest używana (przynajmniej w większości języków).
Prawdopodobnie konwencja ta ewoluowała od bardzo wczesnych decyzji dotyczących projektowania języka historycznego, ponieważ na wczesnych komputerach cały kompilator, w tym analiza leksykalna, musiał działać z kilkoma kWordami, mniej pamięci niż nawet pamięć podręczna danych procesora pierwszego poziomu na obecnych urządzeniach mobilnych, więc dozwolone nazwy zmiennych były bardzo ograniczone i musiały być łatwe do odróżnienia od stałych numerycznych w bardzo niewielu kodach operacyjnych.
W ten sposób konwencja stała się tym, do czego przyzwyczajone są pokolenia programistów.
Nie jest to logicznie wymagana reguła dla języka programowania, ale tylko konwencja stosowana przez wielu projektantów języków.
Potrafię zaprojektować radykalnie inny język, który pozwala na wszystkie znaki dla identyfikatorów. Dla wszystkich wierszy kodu pierwsze 20 znaków opisuje typ instrukcji, a następnie 20 znaków określa pierwszy symbol instrukcji, a kolejne 20 znaków jest operandem instrukcji. Ten język zostanie wykonany na procesorze stosu.
01234567890123456789 01234567890123456789 01234567890123456789
decl symbol 12345
assign value 12345 12345
decl symbol 99999
assign value 99999 12345
push 12345
push 99999
add
print top
Ten kod można przetłumaczyć na C jak poniżej:
int i12345 = 12345;
int i99999 = 12345;
printf("%d", i12345+i9999);
To wszystko. Jest bez znaczenia, a zasada braku numeru w identyfikatorach jest również bezcelowa z logicznego punktu widzenia.
Myślę, że oprócz „wygody dla leksera” warto również rozważyć „wygodę dla czytelnika”.
Czytając kod, musisz szybko i wielokrotnie identyfikować, które słowa są identyfikatorami, a które liczbami. Szukanie cyfry na początku jest łatwiejsze dzięki naszemu wizualnemu dopasowaniu wzorów; byłoby ciężkim obowiązkiem, gdybyśmy musieli dokładnie sprawdzić wszystkie postacie, aby się upewnić.
Odpowiedź na to pytanie leży w automatach, a dokładniej automatach skończonych, które definiują wyrażenie regularne. Zasada jest taka ... kompilatory potrzebują dokładnych algorytmów lub reguł, aby decydować przy każdym analizowanym znaku. Jeśli identyfikatory miałyby zaczynać się od liczby, to kompilator będzie w poprawce ... o charakterze nadchodzącego tokena ... czy będzie to liczba lub identyfikator ... i jako kompilatory nie mogą wrócić do wcześniejszych pozycji ... .so .. aby wyjaśnić kompilatorowi, że nadchodzący token jest dokładnie identyfikatorem lub liczbą ... to ograniczenie istnieje ... ponieważ ten ... kompilator wie, skanując pierwszy znak, że nadchodzący token jest identyfikatorem lub liczbą.