2013-07-11 18 views
11

Zastanawiam się dlaczego w C# poniższych jest w porządku:Dlaczego jest x ++ - + - ++ x legal, ale x +++ - +++ x nie jest?

int y = x++-+-++x; 

Ale

int y = x+++-+++x; 

nie? Dlaczego istnieje odchylenie od +?

+8

Lepsze pytanie brzmi: dlaczego chcesz tego użyć? – Sayse

+0

To zależy od kompilatora (.Net 4.5 na VS 2012 narzeka) –

+0

Potrzebujemy szczegółów na temat używanego kompilatora, na jakie .NET kierujesz swoje reklamy, itp. – tnw

Odpowiedz

16

Pozostałe dwie odpowiedzi są poprawne; Dodam do nich, że to ilustruje pewne podstawowe zasady analizy leksykalnej:

  • Analizator leksykalny jest krótkowzroczne - ma minimalny „look-ahead”
  • Analizator leksykalny jest chciwy - próbuje zrobić najdłuższy token, który teraz może .
  • Analizator leksykalny nie śledzi prób znalezienia alternatywnych rozwiązań w przypadku awarii.

Zasady te oznaczają, że +++x będą lexed jak ++ + x a nie + ++ x.

Parser następnie analizować ++ + x jako ++(+x) i (+x) nie jest zmienny, to jest wartość, a więc nie może być zwiększony.

Zobacz także: http://blogs.msdn.com/b/ericlippert/archive/2010/10/11/10070831.aspx

+0

+1, chociaż mogłoby to uczynić go nieparzystym że Mono może skompilować ten sam kod. Albo specyfikacja jest nieco "otwarta" po tej stronie, albo jeden z kompilatorów nie jest do końca zgodny. –

+2

@JoachimIsaksson: Mono ma mały błąd; Podejrzewam, że znajduje się on w analizatorze semantycznym, a nie w analizatorze leksykalnym. Oznacza to, że nie jest ** przypadkiem, że Mono porównuje '+++ x' jako' + ++ x'. Raczej podejrzewam, że jest to poprawnie poprawne jako '++ + x', następnie analizator semantyczny traktuje' + x' jako 'x', ale zapominając, że' + x' jest wartością, a nie zmienną, a zatem nie kwalifikuje się jako operand inkrementacji. –

+0

@JoachimIsaksson: Rzeczywiście. Kompilator Microsoft C# zawierał wiele tego rodzaju błędów w C# 2.0; Usunąłem ich dużo w C# 3.0. Kilku, których zatrzymaliśmy, ponieważ byli nieszkodliwi i podjęcie przełomowej zmiany byłoby destrukcyjne. –

5

Używam VS 2012. Jest to interesujące.

Pierwszy z nich może być analizowany w:

int y = (x++) - (+(-(++x))); 

nie zmieniając wynik końcowy. Więc możesz zobaczyć, dlaczego byłaby ważna.

Drugi ma jednak problem z +++x, ponieważ (domyślam się) widzi dwie ++ i próbuje zastosować ten jednoargumentowy operator do wartości r, która jest kolejnym + (a nie poprawna wartość r). Można grupa go na różne sposoby, aby to działało, choć:

int y = (x++)+(-(+(++x))); 

jest prawidłowy.

Jestem pewien, że Jon Skeet lub Eric Lippert lub ktoś pojawi się i wskaże odpowiednią część specyfikacji C#. Nie jestem nawet pewien, od czego zacząć. Ale po ogólnym analizowaniu tokenu od lewej do prawej widać, gdzie dusi się na drugim.

+0

FYI cała gramatyka znajduje się na końcu specyfikacji w dodatku. –

+0

Nie widać nic poza "jednym z" gramatyki operatora, czy preferować '+' lub '++' na dowolnym etapie wydaje się niejasne. –

+0

@JoachimIsaksson: Sekcja 2.3 specyfikacji mówi: "Gdy kilka leksykalnych przedstawień gramatycznych pasuje do sekwencji znaków w pliku źródłowym, przetwarzanie leksykalne zawsze stanowi najdłuższy możliwy element leksykalny." * –

2

Kompilator szuka zmiennej lub właściwości po drugim ++ w int y = x+++-+++x i nie może tego ustalić bez spacji lub nawiasów.

można zrobić coś takiego:

int y = x+++-+(++x); 

lub

int y = x++ + -+ ++x; 

jeśli chciałeś.

Powód, dla którego pierwszy wymieniony przykład zadziałał, jest taki, że kompilator może określić, że +- z ++x; podczas gdy w drugim przykładzie nie może on ustalić, gdzie oddzielić +++ i naturalnie oczekuje zmiennej po przeczytaniu pierwszego ++; tak w skrócie, kompilator próbuje użyć +x jako zmiennej, która jest nieprawidłowa.

Obie są prawdopodobnie poprawne przy użyciu innego kompilatora. To zależy od semantyki.