Estoy familiarizado con el hecho de que las gramáticas de C y C ++ son sensibles al contexto y , en particular, necesita un "truco lexer" en C. Por otro lado, tengo la impresión de que puede analizar Java con solo 2 señales de anticipación, a pesar de la considerable similitud entre los dos idiomas.
¿Qué tendría que cambiar acerca de C para que sea más manejable de analizar?
Lo pregunto porque todos los ejemplos que he visto de la sensibilidad al contexto de C son técnicamente permitidos pero terriblemente extraños. Por ejemplo,
foo (a);
podría estar llamando a la función void foo
con argumento a
. O bien, podría declarar a
ser un objeto de tipo foo
, pero podría deshacerse fácilmente de las paréntesis. En parte, esta rareza se produce porque la regla de producción del "declarador directo" para la gramática C cumple el doble propósito de declarar tanto funciones como variables.
Por otro lado, la gramática de Java tiene reglas de producción independientes para la declaración de variables y la declaración de funciones. Si tú escribes
foo a;
entonces sabrá que es una declaración de variable y foo
puede analizarse sin ambigüedades como un nombre de tipo. Es posible que este no sea un código válido si la clase foo
no se ha definido en algún lugar del alcance actual, pero ese es un trabajo para el análisis semántico que se puede realizar en una pasada del compilador posterior.
Lo he visto decir que C es difícil de analizar debido a typedef, pero también puede declarar sus propios tipos en Java. ¿Qué reglas gramaticales de C, además direct_declarator
, tienen fallas?
Respuestas:
Analizar C ++ se está volviendo difícil. Analizar Java se está volviendo tan difícil.
Vea esta respuesta SO que discute por qué C (y C ++) es "difícil" de analizar . El breve resumen es que las gramáticas C y C ++ son intrínsecamente ambiguas; le darán múltiples análisis y debe usar el contexto para resolver las ambigüedades. Entonces, la gente comete el error de asumir que tiene que resolver las ambigüedades mientras analiza; no es así, ver más abajo. Si insiste en resolver ambigüedades mientras analiza, su analizador se vuelve más complicado y mucho más difícil de construir; pero esa complejidad es una herida autoinfligida.
IIRC, la gramática "obvia" de LALR (1) de Java 1.4 no era ambigua, por lo que era "fácil" de analizar. No estoy tan seguro de que el Java moderno no tenga al menos ambigüedades locales de larga distancia; siempre existe el problema de decidir si "... >>" cierra dos plantillas o es un "operador de turno a la derecha". Sospecho que Java moderno ya no analiza con LALR (1) .
Pero se puede superar el problema del análisis sintáctico mediante el uso de analizadores potentes (o analizadores débiles y hacks de recopilación de contextos como lo hacen en la actualidad las interfaces de C y C ++), para ambos lenguajes. C y C ++ tienen la complicación adicional de tener un preprocesador; estos son más complicados en la práctica de lo que parecen. Una afirmación es que los analizadores de C y C ++ son tan difíciles que tienen que escribirse a mano. No es verdad; puede construir analizadores Java y C ++ muy bien con generadores de analizadores GLR.
Pero el análisis no es realmente el problema.
Una vez que analice, querrá hacer algo con el árbol AST / parse. En la práctica, es necesario saber, para cada identificador, cuál es su definición y dónde se usa ("resolución de nombre y tipo", descuidadamente, construyendo tablas de símbolos). Esto resulta ser MUCHO más trabajo que hacer que el analizador sea correcto, agravado por la herencia, las interfaces, la sobrecarga y las plantillas, y lo confuso por el hecho de que la semántica de todo esto está escrita en un lenguaje natural informal que se extiende a lo largo de decenas a cientos de páginas. del estándar de idioma. C ++ es realmente malo aquí. Java 7 y 8 se están volviendo bastante horribles desde este punto de vista. (Y las tablas de símbolos no son todo lo que necesita; vea mi biografía para un ensayo más largo sobre "La vida después del análisis").
La mayoría de las personas luchan con la parte del análisis puro (a menudo nunca termina; compruebe el SO mismo para ver las muchas, muchas preguntas sobre cómo crear analizadores que funcionan para idiomas reales), por lo que nunca ven la vida después del análisis. Y luego obtenemos teoremas populares sobre lo que es difícil de analizar y no hay señales sobre lo que sucede después de esa etapa.
Arreglar la sintaxis de C ++ no lo llevará a ninguna parte.
Con respecto a cambiar la sintaxis de C ++: encontrará que necesita parchear muchos lugares para ocuparse de la variedad de ambigüedades locales y reales en cualquier gramática de C ++. Si insiste, la siguiente lista podría ser un buen punto de partida . Sostengo que no tiene sentido hacer esto si usted no es el comité de estándares de C ++; si lo hicieras y construyeras un compilador usando eso, nadie en su sano juicio lo usaría. Se ha invertido demasiado en las aplicaciones C ++ existentes como para cambiarlas por conveniencia de los tipos que crean analizadores; además, su dolor ha terminado y los analizadores existentes funcionan bien.
Es posible que desee escribir su propio analizador. OK eso está bien; simplemente no espere que el resto de la comunidad le permita cambiar el idioma que deben usar para que sea más fácil para usted. Todos quieren que sea más fácil para ellos, y eso es usar el lenguaje tal como está documentado e implementado.
fuente