Este ejemplo exacto está cubierto en el borrador de la norma C99 (los mismos detalles en C11 ) sección 6.4 Elementos léxicos párrafo 4 que dice:
Si el flujo de entrada se ha analizado en tokens de preprocesamiento hasta un carácter determinado, el siguiente token de preprocesamiento es la secuencia más larga de caracteres que podría constituir un token de preprocesamiento. [...]
que también se conoce como la regla de munch máxima que se utiliza en el análisis léxico para evitar ambigüedades y funciona tomando tantos elementos como sea posible para formar un token válido.
el párrafo también tiene dos ejemplos, el segundo coincide exactamente con su pregunta y es el siguiente:
EJEMPLO 2 El fragmento de programa x +++++ y se analiza como x ++ ++ + y, lo que viola una restricción sobre los operadores de incremento, aunque el análisis x ++ + ++ y podría producir una expresión correcta.
que nos dice que:
a+++++b
se analizará como:
a ++ ++ + b
lo que viola las restricciones sobre el incremento posterior, ya que el resultado del primer incremento posterior es un valor r y el incremento posterior requiere un valor l. Esto se cubre en la sección 6.5.2.4
Operadores de incremento y decremento de Postfix que dice ( énfasis mío ):
El operando del operador de incremento o decremento sufijo tendrá un tipo real o puntero calificado o no calificado y será un valor modificable.
y
El resultado del operador postfix ++ es el valor del operando.
El libro C ++ Gotchas también cubre este caso en Gotcha #17
Maximal Munch Problems , es el mismo problema en C ++ y también da algunos ejemplos. Explica eso cuando se trata del siguiente conjunto de caracteres:
->*
el analizador léxico puede hacer una de estas tres cosas:
- Tratarlo como tres fichas:
-
, >
y*
- Trátelo como dos tokens:
->
y*
- Trátelo como una ficha:
->*
La regla de munch máximo le permite evitar estas ambigüedades. El autor señala que ( en el contexto de C ++ ):
resuelve muchos más problemas de los que causa, pero en dos situaciones comunes, es una molestia.
El primer ejemplo serían plantillas cuyos argumentos de plantilla también son plantillas ( que se resolvió en C ++ 11 ), por ejemplo:
list<vector<string>> lovos; // error!
^^
Lo que interpreta los corchetes angulares de cierre como el operador de cambio , por lo que se requiere un espacio para eliminar la ambigüedad:
list< vector<string> > lovos;
^
El segundo caso involucra argumentos predeterminados para punteros, por ejemplo:
void process( const char *= 0 ); // error!
^^
se interpretaría como *=
operador de asignación, la solución en este caso es nombrar los parámetros en la declaración.