Этот точный пример описан в проекте стандарта C99 (те же подробности в C11 ), раздел 6.4 Лексические элементы, параграф 4, в котором говорится:
Если входной поток был проанализирован на токены предварительной обработки до заданного символа, следующий токен предварительной обработки является самой длинной последовательностью символов, которая может составлять токен предварительной обработки. [...]
которое также известно как правило максимального пережевывания, которое используется в лексическом анализе, чтобы избежать двусмысленности, и работает, беря как можно больше элементов, чтобы сформировать действительный токен.
в абзаце также есть два примера, второй точно соответствует вашему вопросу и выглядит следующим образом:
ПРИМЕР 2 Фрагмент программы x +++++ y анализируется как x ++ ++ + y, что нарушает ограничение на операторы приращения, даже если синтаксический анализ x ++ + ++ y может дать правильное выражение.
что говорит нам, что:
a+++++b
будет проанализирован как:
a ++ ++ + b
что нарушает ограничения на приращение поста, так как результатом первого приращения поста является rvalue, а приращение поста требует lvalue. Это описано в разделе « 6.5.2.4
Операторы увеличения и уменьшения Postfix», в котором говорится ( выделено мной ):
Операнд постфиксного оператора увеличения или уменьшения должен иметь квалифицированный или неквалифицированный действительный или указательный тип и должен быть изменяемым lvalue.
а также
Результатом постфиксного оператора ++ является значение операнда.
Книга C ++ Gotchas также рассматривает этот случай в Gotcha #17
Максимальных задачах Мунка, это та же проблема в C ++, а также дает несколько примеров. Это объясняет, что при работе со следующим набором символов:
->*
лексический анализатор может делать одно из трех:
- Рассматривайте это как три лексемы:
-
, >
и*
- Рассматривайте это как два токена:
->
и*
- Рассматривайте это как один токен:
->*
Максимальное жуют правило позволяет избежать этих неясностей. Автор указывает, что это ( в контексте C ++ ):
решает гораздо больше проблем, чем вызывает, но в двух типичных ситуациях это раздражает.
Первым примером могут быть шаблоны, аргументы которых также являются шаблонами ( что было решено в C ++ 11 ), например:
list<vector<string>> lovos;
^^
Что интерпретирует закрывающие угловые скобки как оператор сдвига , и поэтому для устранения неоднозначности требуется пробел:
list< vector<string> > lovos;
^
Во втором случае используются аргументы по умолчанию для указателей, например:
void process( const char *= 0 );
^^
будет интерпретироваться как *=
оператор присваивания, решение в этом случае - указать параметры в объявлении.