programas programación programacion lenguaje funciones ejemplos comandos codigos c++ syntax grammar context-free-grammar context-sensitive-grammar

c++ - programacion - lenguaje de programación c



¿Es C++ libre de contexto o sensible al contexto? (19)

A menudo escucho afirmaciones de que C ++ es un lenguaje sensible al contexto. Tomemos el siguiente ejemplo:

a b(c);

¿Es esta una definición de variable o una declaración de función? Eso depende del significado del símbolo c . Si c es una variable , entonces ab(c); define una variable llamada b de tipo a . Se inicializa directamente con c . Pero si c es un tipo , entonces ab(c); declara una función llamada b que toma una c y devuelve una a .

Si busca la definición de lenguajes libres de contexto, básicamente le dirá que todas las reglas gramaticales deben tener lados izquierdos que consistan exactamente en un símbolo no terminal. Las gramáticas sensibles al contexto, por otro lado, permiten cadenas arbitrarias de símbolos terminales y no terminales en el lado izquierdo.

Al buscar en el Apéndice A de "El lenguaje de programación de C ++", no pude encontrar una sola regla gramatical que tuviera otra cosa además de un solo símbolo no terminal en su lado izquierdo. Eso implicaría que C ++ está libre de contexto. (Por supuesto, todo lenguaje libre de contexto también es sensible al contexto, en el sentido de que los lenguajes libres de contexto forman un subconjunto de los lenguajes sensibles al contexto, pero ese no es el punto).

Entonces, ¿es C ++ libre de contexto o sensible al contexto?


Meta-S "es un motor de análisis sensible al contexto de Quinn Tyler Jackson. No lo he usado, pero cuenta una historia impresionante. Echa un vistazo a sus comentarios en comp.compilers y visita rnaparse.com/MetaS%20defined.htm - Ira Baxter el 25 de julio a las 10:42.

El enlace correcto es analizar enigines.

Meta-S era propiedad de una compañía difunta llamada Thothic. Puedo enviar una copia gratuita del Meta-S a cualquier persona interesada y la he usado en investigaciones de análisis. Tenga en cuenta que la "gramática de pseudoknot" incluida en las carpetas de ejemplos fue escrita por un programador no bioinformático, no maduro y básicamente no funciona. Mis gramáticas tienen un enfoque diferente y funcionan bastante bien.


A continuación se encuentra mi demostración favorita (actual) de por qué el análisis de C ++ es (probablemente) Turing-complete , ya que muestra un programa que es sintácticamente correcto si y solo si un entero determinado es primo.

Así que afirmo que C ++ no es libre de contexto ni sensible al contexto .

Si permite secuencias de símbolos arbitrarias en ambos lados de cualquier producción, produce una gramática de Tipo 0 ("sin restricciones") en la jerarquía de Chomsky , que es más poderosa que una gramática sensible al contexto; Las gramáticas no restringidas son Turing-completas. Una gramática sensible al contexto (Tipo 1) permite múltiples símbolos de contexto en el lado izquierdo de una producción, pero el mismo contexto debe aparecer en el lado derecho de la producción (de ahí el nombre "sensible al contexto"). [1] Las gramáticas sensibles al contexto son equivalentes a las máquinas de Turing de límite lineal .

En el programa de ejemplo, el cálculo principal podría realizarse mediante una máquina de Turing de límite lineal, por lo que no demuestra la equivalencia de Turing, pero lo importante es que el analizador necesita realizar el cálculo para realizar el análisis sintáctico. Podría haber sido cualquier cálculo expresable como una creación de instancias de plantilla y hay razones para creer que la creación de instancias de plantillas de C ++ es Turing-complete. Ver, por ejemplo, el documento de 2003 de Todd L. Veldhuizen .

En cualquier caso, C ++ puede ser analizado por una computadora, por lo que ciertamente podría ser analizado por una máquina de Turing. En consecuencia, una gramática no restringida podría reconocerlo. En realidad, escribir una gramática así sería poco práctico, por lo que el estándar no trata de hacerlo. (Vea abajo.)

El problema con la "ambigüedad" de ciertas expresiones es principalmente una pista falsa. Para empezar, la ambigüedad es una característica de una gramática particular, no un lenguaje. Incluso si se puede probar que un lenguaje no tiene gramáticas no ambiguas, si puede ser reconocido por una gramática libre de contexto, es libre de contexto. Del mismo modo, si no puede ser reconocido por una gramática libre de contexto, pero sí puede ser reconocido por una gramática sensible al contexto, es sensible al contexto. La ambigüedad no es relevante.

Pero en cualquier caso, como la línea 21 (es decir, auto b = foo<IsPrime<234799>>::typen<1>(); ) en el programa a continuación, las expresiones no son ambiguas en absoluto; simplemente se analizan de forma diferente según el contexto. En la expresión más simple del problema, la categoría sintáctica de ciertos identificadores depende de cómo se hayan declarado (tipos y funciones, por ejemplo), lo que significa que el lenguaje formal debería reconocer el hecho de que dos cadenas de longitud arbitraria en Los mismos programas son idénticos (declaración y uso). Esto puede ser modelado por la gramática de "copia", que es la gramática que reconoce dos copias exactas consecutivas de la misma palabra. Es fácil demostrar con el lema de bombeo que este lenguaje no es libre de contexto. Es posible una gramática sensible al contexto para este lenguaje, y se proporciona una gramática de Tipo 0 en la respuesta a esta pregunta: https://math.stackexchange.com/questions/163830/context-sensitive-grammar-for-the-copy-language .

Si uno intentara escribir una gramática sensible al contexto (o no restringida) para analizar C ++, posiblemente llenaría el universo con garabatos. Escribir una máquina de Turing para analizar C ++ sería una tarea igualmente imposible. Incluso escribir un programa en C ++ es difícil, y que yo sepa, ninguno ha demostrado ser correcto. Esta es la razón por la cual el estándar no intenta proporcionar una gramática formal completa, y por qué elige escribir algunas de las reglas de análisis en inglés técnico.

Lo que parece una gramática formal en el estándar de C ++ no es la definición formal completa de la sintaxis del lenguaje C ++. Ni siquiera es la definición formal completa del lenguaje después del preprocesamiento, lo que podría ser más fácil de formalizar. (Sin embargo, ese no sería el lenguaje: el lenguaje C ++ definido por el estándar incluye el preprocesador, y el funcionamiento del preprocesador se describe algorítmicamente, ya que sería extremadamente difícil de describir en cualquier formalismo gramatical. Es en esa sección de la norma donde se describe la descomposición léxica, incluidas las reglas donde se debe aplicar más de una vez.)

Las diversas gramáticas (dos gramáticas superpuestas para el análisis léxico, una que tiene lugar antes del preprocesamiento y la otra, si es necesario, después, más la gramática "sintáctica") se recogen en el Apéndice A, con esta importante nota (énfasis agregado):

Este resumen de la sintaxis de C ++ pretende ser una ayuda para la comprensión. No es una declaración exacta de la lengua . En particular, la gramática descrita aquí acepta un superconjunto de construcciones de C ++ válidas . Las reglas de desambiguación (6.8, 7.1, 10.2) deben aplicarse para distinguir expresiones de declaraciones. Además, el control de acceso, la ambigüedad y las reglas de tipo deben usarse para eliminar construcciones sintácticamente válidas pero sin sentido.

Finalmente, aquí está el programa prometido. La línea 21 es sintácticamente correcta si y solo si la N en IsPrime<N> es primordial. De lo contrario, typen es un número entero, no una plantilla, por lo que typen<1>() se analiza como (typen<1)>() que es sintácticamente incorrecto porque () no es una expresión sintácticamente válida.

template<bool V> struct answer { answer(int) {} bool operator()(){return V;}}; template<bool no, bool yes, int f, int p> struct IsPrimeHelper : IsPrimeHelper<p % f == 0, f * f >= p, f + 2, p> {}; template<bool yes, int f, int p> struct IsPrimeHelper<true, yes, f, p> { using type = answer<false>; }; template<int f, int p> struct IsPrimeHelper<false, true, f, p> { using type = answer<true>; }; template<int I> using IsPrime = typename IsPrimeHelper<!(I&1), false, 3, I>::type; template<int I> struct X { static const int i = I; int a[i]; }; template<typename A> struct foo; template<>struct foo<answer<true>>{ template<int I> using typen = X<I>; }; template<> struct foo<answer<false>>{ static const int typen = 0; }; int main() { auto b = foo<IsPrime<234799>>::typen<1>(); // Syntax error if not prime return 0; }

[1] Para ponerlo más técnicamente, cada producción en una gramática sensible al contexto debe tener la siguiente forma:

αAβ → αγβ

donde A es un no terminal y α , β son posiblemente secuencias vacías de símbolos gramaticales, y γ es una secuencia no vacía. (Los símbolos gramaticales pueden ser terminales o no terminales).

Esto se puede leer como A → γ solo en el contexto [α, β] . En una gramática libre de contexto (Tipo 2), α y β deben estar vacías.

Resulta que también puedes restringir las gramáticas con la restricción "monotónica", donde cada producción debe ser de la forma:

α → β donde |α| ≥ |β| > 0 |α| ≥ |β| > 0 |α| ≥ |β| > 0 ( |α| significa "la longitud de α ")

Es posible probar que el conjunto de idiomas reconocido por las gramáticas monotónicas es exactamente el mismo que el conjunto de idiomas reconocidos por las gramáticas sensibles al contexto, y es a menudo el caso que es más fácil basar las pruebas en las gramáticas monótonas. En consecuencia, es bastante común ver "sensible al contexto" usado como si significara "monótono".



C ++ se analiza con el analizador GLR. Eso significa que durante el análisis del código fuente, el analizador puede encontrar ambigüedad, pero debería continuar y decidir qué regla gramática se usará más adelante .

mira tambien

¿Por qué C ++ no se puede analizar con un analizador LR (1)?

Recuerde que la gramática libre de contexto no puede describir TODAS las reglas de una sintaxis de lenguaje de programación. Por ejemplo, la gramática de atributo se usa para verificar la validez de un tipo de expresión.

int x; x = 9 + 1.0;

No puede describir la siguiente regla con una gramática libre de contexto: el lado derecho de la tarea debe ser del mismo tipo que el lado izquierdo.



El caso más simple de la gramática no libre de contexto involucra analizar expresiones que involucran plantillas.

a<b<c>()

Esto puede analizar como

template | a < expr > () | < / / b c

O

expr | < / / a template | b < expr > () | c

Los dos AST solo se pueden desambiguar examinando la declaración de ''a'': el AST anterior si ''a'' es una plantilla, o el último si no.


Es posible que desee echar un vistazo a The Design & Evolution of C ++ , de Bjarne Stroustrup. En él describe sus problemas al tratar de usar yacc (o similar) para analizar una versión anterior de C ++, y deseando haber usado en su lugar un descenso recursivo.


Es sensible al contexto, como ab(c); Tiene dos declaraciones de parses válidas y variable. Cuando dices "Si c es un tipo", ese es el contexto, justo ahí, y has descrito exactamente cómo C ++ es sensible a él. Si no tuvieras ese contexto de "¿Qué es c ?" Usted no podría analizar esto sin ambigüedades.

Aquí, el contexto se expresa en la elección de tokens: el analizador lee un identificador como un token de nombre de tipo si nombra un tipo. Esta es la resolución más simple y evita gran parte de la complejidad de ser sensible al contexto (en este caso).

Edición: hay, por supuesto, más problemas de sensibilidad al contexto, simplemente me he centrado en el que has mostrado. Las plantillas son especialmente desagradables para esto.


Las producciones en el estándar de C ++ están escritas sin contexto, pero como todos sabemos realmente no definen el lenguaje con precisión. Parte de lo que la mayoría de las personas ve como ambigüedad en el lenguaje actual podría (creo) resolverse de manera inequívoca con una gramática sensible al contexto.

Para el ejemplo más obvio, consideremos el análisis más molesto: int f(X); . Si X es un valor, entonces esto define f como una variable que se inicializará con X Si X es un tipo, define f como una función que toma un solo parámetro de tipo X

Mirando eso desde un punto de vista gramatical, podríamos verlo así:

A variable_decl ::= <type> <identifier> ''('' initializer '')'' '';'' B function_decl ::= <type> <identifier> ''('' param_decl '')'' '';'' A ::= [declaration of X as value] B ::= [declaration of X as type]

Por supuesto, para ser totalmente correctos, deberíamos agregar algunas "cosas" adicionales para tener en cuenta la posibilidad de que intervengan declaraciones de otros tipos (es decir, A y B deberían ser "declaraciones que incluyan la declaración de X como ..." , o algo en ese orden).

Sin embargo, esto sigue siendo bastante diferente de un CSG típico (o al menos lo que recuerdo de ellos). Esto depende de que se construya una tabla de símbolos: la parte que reconoce X específicamente como un tipo o valor, no solo un tipo de declaración que precede a esto, sino el tipo correcto de declaración para el símbolo / identificador correcto.

Como tal, tendría que hacer algo para estar seguro, pero mi suposición inmediata es que esto realmente no califica como un CSG, al menos como el término se usa normalmente.


Ningún lenguaje similar a Algol está libre de contexto, porque tienen reglas que restringen las expresiones y las declaraciones en las que los identificadores pueden aparecer según su tipo, y porque no hay límite en el número de declaraciones que pueden ocurrir entre la declaración y el uso.

La solución habitual es escribir un analizador sin contexto que realmente acepte un superconjunto de programas válidos y colocar las partes sensibles al contexto en un código "semántico" ad hoc adjunto a las reglas.

C ++ va más allá de esto, gracias a su sistema de plantilla Turing-complete. Vea la pregunta 794015 de desbordamiento de pila .


Para responder a su pregunta, debe distinguir dos preguntas diferentes.

  1. La mera sintaxis de casi todos los lenguajes de programación es libre de contexto. Por lo general, se administra en forma de Backus-Naur extendida o gramar sin contexto.

  2. Sin embargo, incluso si un programa se ajusta a la gramar libre de contexto definida por el lenguaje de programación, no es necesariamente un programa válido . Hay muchas propiedades sin contexto que un programa tiene que satisfacer para ser un programa válido. Por ejemplo, la propiedad más simple es el alcance de las variables.

Para concluir, si C ++ está o no libre de contexto depende de la pregunta que haga.


Primero, observó correctamente que no hay reglas sensibles al contexto en la gramática al final del estándar de C ++, por lo que la gramática está libre de contexto.

Sin embargo, esa gramática no describe con precisión el lenguaje C ++, porque produce programas que no son C ++, como

int m() { m++; }

o

typedef static int int;

El lenguaje C ++ definido como "el conjunto de programas C ++ bien formados" no está exento de contexto (es posible mostrar que solo las variables exigentes para ser declaradas lo hacen). Dado que teóricamente puedes escribir programas completos de Turing en plantillas y hacer que un programa no se forme según su resultado, ni siquiera es sensible al contexto.

Ahora, las personas (ignorantes) (generalmente no los teóricos del lenguaje, sino los diseñadores de analizadores) normalmente usan "no libre de contexto" en algunos de los siguientes significados

  • ambiguo
  • no se puede analizar con Bison
  • no LL (k), LR (k), LALR (k) o cualquier clase de idioma definida por el analizador que eligieron

La gramática en la parte posterior de la norma no satisface estas categorías (es decir, es ambigua, no LL (k) ...) por lo que la gramática C ++ no es "libre de contexto" para ellos. Y en cierto sentido, tienen razón, es muy difícil producir un analizador C ++ que funcione.

Tenga en cuenta que las propiedades aquí utilizadas solo están débilmente conectadas a lenguajes sin contexto: la ambigüedad no tiene nada que ver con la sensibilidad al contexto (de hecho, las reglas sensibles al contexto generalmente ayudan a desambiguar las producciones), las otras dos son simplemente subconjuntos del contexto Idiomas libres. Y analizar lenguajes libres de contexto no es un proceso lineal (aunque sí lo es el análisis determinístico).


Sí, C ++ es sensible al contexto, muy sensible al contexto. No puede crear el árbol de sintaxis simplemente analizando el archivo usando un analizador sin contexto porque en algunos casos necesita conocer el símbolo de conocimiento previo para decidir (es decir, crear una tabla de símbolos mientras se analiza).

Primer ejemplo:

A*B;

¿Es esta una expresión de multiplicación?

O

¿Es esta una declaración de la variable B ser un puntero de tipo A ?

Si A es una variable, entonces es una expresión, si A es de tipo, es una declaración de puntero.

Segundo ejemplo:

A B(bar);

¿Es este un prototipo de función tomando un argumento de tipo bar ?

O

¿Esto es declarar la variable B del tipo A y llama al constructor de A con una bar constante como inicializador?

Debe saber de nuevo si la bar es una variable o un tipo de la tabla de símbolos.

Tercer ejemplo:

class Foo { public: void fn(){x*y;} int x, y; };

Este es el caso cuando construir una tabla de símbolos mientras el análisis no ayuda porque la declaración de x e y viene después de la definición de la función. Por lo tanto, primero debe escanear la definición de clase y observar las definiciones de método en una segunda pasada, para indicar que x * y es una expresión, y no una declaración de puntero o lo que sea.


Sí. La siguiente expresión tiene un orden de operaciones diferente según el contexto resuelto de tipo :

Edición: cuando el orden real de operación varía, hace que sea increíblemente difícil usar un compilador "normal" que analiza un AST sin decorar antes de decorarlo (propagando información de tipo). Otras cosas sensibles al contexto mencionadas son "bastante fáciles" en comparación con esto (no es que la evaluación de la plantilla sea del todo fácil).

#if FIRST_MEANING template<bool B> class foo { }; #else static const int foo = 0; static const int bar = 15; #endif

Seguido por:

static int foobar( foo < 2 ? 1 < 1 : 0 > & bar );


Tengo la sensación de que hay cierta confusión entre la definición formal de "sensible al contexto" y el uso informal de "sensible al contexto". El primero tiene un significado bien definido. Este último se usa para decir "se necesita contexto para analizar la entrada".

Esto también se pregunta aquí: sensibilidad al contexto frente a ambigüedad .

Aquí hay una gramática libre de contexto:

<a> ::= <b> | <c> <b> ::= "x" <c> ::= "x"

Es ambiguo, por lo que para analizar la entrada "x" necesita un poco de contexto (o vivir con la ambigüedad, o emitir "Advertencia: E8271 - La entrada es ambigua en la línea 115"). Pero ciertamente no es una gramática sensible al contexto.


Esta respuesta dice que C ++ no está libre de contexto ... hay una implicación (no por parte del respondedor) de que no se puede analizar, y la respuesta ofrece un ejemplo de código difícil que produce un programa de C ++ no válido si una determinada constante no es una número primo.

Como han observado otros, la pregunta sobre si el idioma es sensible al contexto / libre es diferente de la misma pregunta sobre una gramática específica.

Para establecer la pregunta sobre la facilidad de uso para el descanso, ofrezco evidencia empírica de que existen gramáticas libres de contexto para C ++, que se pueden usar para producir un AST para un análisis libre de contexto del texto de origen al analizarlo con un GLR existente -paso basado en la herramienta que es impulsado por una gramática explícita.

Sí, lo consigue "aceptando demasiado"; no todo lo que acepta es un programa válido de C ++, por lo que se complementa con verificaciones adicionales (verificaciones de tipo). Y sí, el comprobador de tipos puede tener problemas de computabilidad. En la práctica las herramientas no tienen este problema; Si la gente escribiera programas así, ninguno de ellos compilaría. (Creo que el estándar en realidad pone un límite a la cantidad de cómputo que puede hacer al desplegar una plantilla, por lo que en realidad el cómputo es finito pero probablemente bastante grande).

Si lo que quiere decir es, determine si el programa de origen es un miembro del conjunto de programas de origen de C ++ válidos , entonces estaré de acuerdo en que el problema es mucho más difícil. Pero no es analizar el problema.

La herramienta resuelve este problema aislando el análisis de la comprobación de tipo del programa analizado. (Cuando hay múltiples interpretaciones en ausencia de contexto, registra un nodo de ambigüedad en el árbol de análisis con varios análisis posibles; la comprobación de tipo decide cuál es la correcta y elimina los subárboles no válidos). Puede ver un árbol de análisis (parcial) en el siguiente ejemplo; todo el árbol es demasiado grande para caber en una respuesta SO. Tenga en cuenta que obtiene un árbol de análisis si se utiliza el valor 234797 o 234799.

La ejecución del resolutor de nombre / tipo de la herramienta sobre el AST con el valor original 234799 se realiza correctamente. Con el valor 234797, la resolución de nombres falla (como se esperaba) con el mensaje de error, "typen no es un tipo". y por lo tanto esa versión no es un programa válido de C ++.

967 tree nodes in tree. 15 ambiguity nodes in tree. (translation_unit@Cpp~GCC5=2#6b11a20^0 Line 1 Column 1 File C:/temp/prime_with_templates.cpp (declaration_seq@Cpp~GCC5=1021#6b06640^1#6b11a20:1 {10} Line 1 Column 1 File C:/temp/prime_with_templates.cpp (pp_declaration_seq@Cpp~GCC5=1022#6b049a0^1#6b06640:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp (declaration@Cpp~GCC5=1036#6b04980^1#6b049a0:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp |(template_declaration@Cpp~GCC5=2079#6b04960^1#6b04980:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp | (template_parameter_list@Cpp~GCC5=2082#6afbde0^1#6b04960:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp | (template_parameter@Cpp~GCC5=2085#6afbd80^1#6afbde0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp | (parameter_declaration@Cpp~GCC5=1611#6afbd40^1#6afbd80:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp | |(basic_decl_specifier_seq@Cpp~GCC5=1070#6afb880^1#6afbd40:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp | | (decl_specifier@Cpp~GCC5=1073#6afb840^1#6afb880:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp | | (trailing_type_specifier@Cpp~GCC5=1118#6afb7e0^1#6afb840:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp | | (simple_type_specifier@Cpp~GCC5=1138#6afb7a0^1#6afb7e0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | )trailing_type_specifier#6afb7e0 | | )decl_specifier#6afb840 | |)basic_decl_specifier_seq#6afb880 | |(ptr_declarator@Cpp~GCC5=1417#6afbc40^1#6afbd40:2 Line 1 Column 15 File C:/temp/prime_with_templates.cpp | | (noptr_declarator@Cpp~GCC5=1421#6afbba0^1#6afbc40:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp | | (declarator_id@Cpp~GCC5=1487#6afbb80^1#6afbba0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp | | (id_expression@Cpp~GCC5=317#6afbaa0^1#6afbb80:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp | | |(unqualified_id@Cpp~GCC5=319#6afb9c0^1#6afbaa0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp | | | (IDENTIFIER@Cpp~GCC5=3368#6afb780^1#6afb9c0:1[`V''] Line 1 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | |)unqualified_id#6afb9c0 | | )id_expression#6afbaa0 | | )declarator_id#6afbb80 | | )noptr_declarator#6afbba0 | |)ptr_declarator#6afbc40 | )parameter_declaration#6afbd40 | )template_parameter#6afbd80 | )template_parameter_list#6afbde0 | (declaration@Cpp~GCC5=1033#6b04940^1#6b04960:2 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | (block_declaration@Cpp~GCC5=1050#6b04920^1#6b04940:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | (simple_declaration@Cpp~GCC5=1060#6b04900^1#6b04920:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b048e0^1#6b04900:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | | (decl_specifier@Cpp~GCC5=1073#6b048c0^1#6b048e0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | | (type_specifier@Cpp~GCC5=1110#6b048a0^1#6b048c0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | | (class_specifier@Cpp~GCC5=1761#6b04880^1#6b048a0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | | |(class_head@Cpp~GCC5=1763#6afb980^1#6b04880:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp | | | (class_key@Cpp~GCC5=1791#6afbca0^1#6afb980:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp)class_key | | | (IDENTIFIER@Cpp~GCC5=3368#6afbcc0^1#6afb980:2[`answer''] Line 1 Column 25 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | | (optional_base_clause@Cpp~GCC5=1872#6afba60^1#6afb980:3 Line 1 Column 32 File C:/temp/prime_with_templates.cpp)optional_base_clause | | |)class_head#6afb980 | | |(member_specification@Cpp~GCC5=1794#6b042e0^1#6b04880:2 {2} Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b04060^1#6b042e0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | (member_declaration@Cpp~GCC5=1822#6b04040^1#6b04060:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | (function_definition@Cpp~GCC5=1632#6b04020^1#6b04040:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | |(function_head@Cpp~GCC5=1673#6afbec0^1#6b04020:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | (ptr_declarator@Cpp~GCC5=1417#6afbfe0^1#6afbec0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | (noptr_declarator@Cpp~GCC5=1422#6afbf80^1#6afbfe0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | (noptr_declarator@Cpp~GCC5=1421#6afbf60^1#6afbf80:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | |(declarator_id@Cpp~GCC5=1487#6afbea0^1#6afbf60:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | | (id_expression@Cpp~GCC5=317#6afbb40^1#6afbea0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | | (unqualified_id@Cpp~GCC5=319#6afbc80^1#6afbb40:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp | | | | | (IDENTIFIER@Cpp~GCC5=3368#6afbc20^1#6afbc80:1[`answer''] Line 1 Column 34 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | | | | )unqualified_id#6afbc80 | | | | | )id_expression#6afbb40 | | | | |)declarator_id#6afbea0 | | | | )noptr_declarator#6afbf60 | | | | (parameter_declaration_clause@Cpp~GCC5=1559#6afbd00^1#6afbf80:2 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | |(pp_parameter_declaration_list@Cpp~GCC5=1570#6afb940^1#6afbd00:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | | (pp_parameter_declaration_seq@Cpp~GCC5=1574#6afb800^1#6afb940:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | | (parameter_declaration@Cpp~GCC5=1610#6afb9a0^1#6afb800:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | | (basic_decl_specifier_seq@Cpp~GCC5=1070#6afbf40^1#6afb9a0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | | |(decl_specifier@Cpp~GCC5=1073#6afbfa0^1#6afbf40:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | | | (trailing_type_specifier@Cpp~GCC5=1118#6afbfc0^1#6afbfa0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp | | | | | | (simple_type_specifier@Cpp~GCC5=1140#6afb860^1#6afbfc0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | | | | | )trailing_type_specifier#6afbfc0 | | | | | |)decl_specifier#6afbfa0 | | | | | )basic_decl_specifier_seq#6afbf40 | | | | | )parameter_declaration#6afb9a0 | | | | | )pp_parameter_declaration_seq#6afb800 | | | | |)pp_parameter_declaration_list#6afb940 | | | | )parameter_declaration_clause#6afbd00 | | | | (function_qualifiers@Cpp~GCC5=1438#6afbce0^1#6afbf80:3 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)function_qualifiers | | | | )noptr_declarator#6afbf80 | | | | )ptr_declarator#6afbfe0 | | | |)function_head#6afbec0 | | | |(function_body@Cpp~GCC5=1680#6b04000^1#6b04020:2 Line 1 Column 46 File C:/temp/prime_with_templates.cpp | | | | (compound_statement@Cpp~GCC5=888#6afbee0^1#6b04000:1 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)compound_statement | | | |)function_body#6b04000 | | | )function_definition#6b04020 | | | )member_declaration#6b04040 | | | )member_declaration_or_access_specifier#6b04060 | | | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b042c0^1#6b042e0:2 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | (member_declaration@Cpp~GCC5=1822#6b04820^1#6b042c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | (function_definition@Cpp~GCC5=1632#6b04280^1#6b04820:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | |(function_head@Cpp~GCC5=1674#6b04220^1#6b04280:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b040e0^1#6b04220:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | | (decl_specifier@Cpp~GCC5=1073#6b040c0^1#6b040e0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | | (trailing_type_specifier@Cpp~GCC5=1118#6b040a0^1#6b040c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp | | | | |(simple_type_specifier@Cpp~GCC5=1138#6b04080^1#6b040a0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | | | )trailing_type_specifier#6b040a0 | | | | )decl_specifier#6b040c0 | | | | )basic_decl_specifier_seq#6b040e0 | | | | (ptr_declarator@Cpp~GCC5=1417#6b04200^1#6b04220:2 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | (noptr_declarator@Cpp~GCC5=1422#6b041e0^1#6b04200:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | (noptr_declarator@Cpp~GCC5=1421#6b041a0^1#6b041e0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | |(declarator_id@Cpp~GCC5=1487#6b04180^1#6b041a0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | | (id_expression@Cpp~GCC5=317#6b04160^1#6b04180:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | | (unqualified_id@Cpp~GCC5=320#6b04140^1#6b04160:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | | (operator_function_id@Cpp~GCC5=2027#6b04120^1#6b04140:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp | | | | | |(operator@Cpp~GCC5=2070#6b04100^1#6b04120:1 Line 1 Column 62 File C:/temp/prime_with_templates.cpp)operator | | | | | )operator_function_id#6b04120 | | | | | )unqualified_id#6b04140 | | | | | )id_expression#6b04160 | | | | |)declarator_id#6b04180 | | | | )noptr_declarator#6b041a0 | | | | (parameter_declaration_clause@Cpp~GCC5=1558#6afba40^1#6b041e0:2 Line 1 Column 65 File C:/temp/prime_with_templates.cpp)parameter_declaration_clause | | | | (function_qualifiers@Cpp~GCC5=1438#6b041c0^1#6b041e0:3 Line 1 Column 66 File C:/temp/prime_with_templates.cpp)function_qualifiers | | | | )noptr_declarator#6b041e0 | | | | )ptr_declarator#6b04200 | | | |)function_head#6b04220 | | | |(function_body@Cpp~GCC5=1680#6b04300^1#6b04280:2 Line 1 Column 66 File C:/temp/prime_with_templates.cpp | | | | (compound_statement@Cpp~GCC5=889#6b04760^1#6b04300:1 Line 1 Column 66 File C:/temp/prime_with_templates.cpp | | | | (pp_statement_seq@Cpp~GCC5=894#6b04780^1#6b04760:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp | | | | (statement@Cpp~GCC5=857#6b04440^1#6b04780:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp | | | | |(jump_statement@Cpp~GCC5=1011#6afba80^1#6b04440:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp | | | | | (pm_expression@Cpp~GCC5=551#6b04380^1#6afba80:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp | | | | | (cast_expression@Cpp~GCC5=543#6b04360^1#6b04380:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp | | | | | (unary_expression@Cpp~GCC5=465#6b04340^1#6b04360:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp | | | | | |(primary_expression@Cpp~GCC5=307#6b04320^1#6b04340:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp | | | | | | (id_expression@Cpp~GCC5=317#6b042a0^1#6b04320:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp | | | | | | (unqualified_id@Cpp~GCC5=319#6b04260^1#6b042a0:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp | | | | | | (IDENTIFIER@Cpp~GCC5=3368#6b04240^1#6b04260:1[`V''] Line 1 Column 74 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | | | | | )unqualified_id#6b04260 | | | | | | )id_expression#6b042a0 | | | | | |)primary_expression#6b04320 | | | | | )unary_expression#6b04340 | | | | | )cast_expression#6b04360 | | | | | )pm_expression#6b04380 | | | | |)jump_statement#6afba80 | | | | )statement#6b04440 | | | | )pp_statement_seq#6b04780 | | | | )compound_statement#6b04760 | | | |)function_body#6b04300 | | | )function_definition#6b04280 | | | )member_declaration#6b04820 | | | )member_declaration_or_access_specifier#6b042c0 | | |)member_specification#6b042e0 | | )class_specifier#6b04880 | | )type_specifier#6b048a0 | | )decl_specifier#6b048c0 | |)basic_decl_specifier_seq#6b048e0 | )simple_declaration#6b04900 | )block_declaration#6b04920 | )declaration#6b04940 |)template_declaration#6b04960 )declaration#6b04980 )pp_declaration_seq#6b049a0 (pp_declaration_seq@Cpp~GCC5=1022#6b06620^1#6b06640:2 Line 3 Column 1 File C:/temp/prime_with_templates.cpp (declaration@Cpp~GCC5=1036#6b06600^1#6b06620:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp |(template_declaration@Cpp~GCC5=2079#6b065e0^1#6b06600:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp | (template_parameter_list@Cpp~GCC5=2083#6b05460^1#6b065e0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | (template_parameter_list@Cpp~GCC5=2083#6b05140^1#6b05460:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | (template_parameter_list@Cpp~GCC5=2083#6b04ee0^1#6b05140:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | |(template_parameter_list@Cpp~GCC5=2082#6b04cc0^1#6b04ee0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | | (template_parameter@Cpp~GCC5=2085#6b04ca0^1#6b04cc0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | | (parameter_declaration@Cpp~GCC5=1611#6b04c80^1#6b04ca0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04a40^1#6b04c80:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | | |(decl_specifier@Cpp~GCC5=1073#6b04a20^1#6b04a40:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | | | (trailing_type_specifier@Cpp~GCC5=1118#6b04a00^1#6b04a20:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp | | | (simple_type_specifier@Cpp~GCC5=1138#6b049e0^1#6b04a00:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | | )trailing_type_specifier#6b04a00 | | |)decl_specifier#6b04a20 | | )basic_decl_specifier_seq#6b04a40 | | (ptr_declarator@Cpp~GCC5=1417#6b04c40^1#6b04c80:2 Line 3 Column 15 File C:/temp/prime_with_templates.cpp | | |(noptr_declarator@Cpp~GCC5=1421#6b04be0^1#6b04c40:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp | | | (declarator_id@Cpp~GCC5=1487#6b04bc0^1#6b04be0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp | | | (id_expression@Cpp~GCC5=317#6b04b60^1#6b04bc0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp | | | (unqualified_id@Cpp~GCC5=319#6b04ac0^1#6b04b60:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp | | | |(IDENTIFIER@Cpp~GCC5=3368#6b049c0^1#6b04ac0:1[`no''] Line 3 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | | )unqualified_id#6b04ac0 | | | )id_expression#6b04b60 | | | )declarator_id#6b04bc0 | | |)noptr_declarator#6b04be0 | | )ptr_declarator#6b04c40 | | )parameter_declaration#6b04c80 | | )template_parameter#6b04ca0 | |)template_parameter_list#6b04cc0 | |(template_parameter@Cpp~GCC5=2085#6b04ec0^1#6b04ee0:2 Line 3 Column 19 File C:/temp/prime_with_templates.cpp | | (parameter_declaration@Cpp~GCC5=1611#6b04ea0^1#6b04ec0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp | | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04b40^1#6b04ea0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp | | (decl_specifier@Cpp~GCC5=1073#6b04ba0^1#6b04b40:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp | | |(trailing_type_specifier@Cpp~GCC5=1118#6b04c60^1#6b04ba0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp | | | (simple_type_specifier@Cpp~GCC5=1138#6b04580^1#6b04c60:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | |)trailing_type_specifier#6b04c60 | | )decl_specifier#6b04ba0 | | )basic_decl_specifier_seq#6b04b40 | | (ptr_declarator@Cpp~GCC5=1417#6b04e60^1#6b04ea0:2 Line 3 Column 24 File C:/temp/prime_with_templates.cpp | | (noptr_declarator@Cpp~GCC5=1421#6b04e40^1#6b04e60:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp | | |(declarator_id@Cpp~GCC5=1487#6b04de0^1#6b04e40:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp | | | (id_expression@Cpp~GCC5=317#6b04d80^1#6b04de0:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp | | | (unqualified_id@Cpp~GCC5=319#6b04ce0^1#6b04d80:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp | | | (IDENTIFIER@Cpp~GCC5=3368#6b04560^1#6b04ce0:1[`yes''] Line 3 Column 24 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | | )unqualified_id#6b04ce0 | | | )id_expression#6b04d80 | | |)declarator_id#6b04de0 | | )noptr_declarator#6b04e40 | | )ptr_declarator#6b04e60 | | )parameter_declaration#6b04ea0 | |)template_parameter#6b04ec0 | )template_parameter_list#6b04ee0 | (template_parameter@Cpp~GCC5=2085#6b05120^1#6b05140:2 Line 3 Column 29 File C:/temp/prime_with_templates.cpp | |(parameter_declaration@Cpp~GCC5=1611#6b05100^1#6b05120:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp | | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04d20^1#6b05100:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp | | (decl_specifier@Cpp~GCC5=1073#6b04dc0^1#6b04d20:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp | | (trailing_type_specifier@Cpp~GCC5=1118#6b04e80^1#6b04dc0:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp | | |(simple_type_specifier@Cpp~GCC5=1140#6b046e0^1#6b04e80:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | )trailing_type_specifier#6b04e80 | | )decl_specifier#6b04dc0 | | )basic_decl_specifier_seq#6b04d20 | | (ptr_declarator@Cpp~GCC5=1417#6b05080^1#6b05100:2 Line 3 Column 33 File C:/temp/prime_with_templates.cpp | | (noptr_declarator@Cpp~GCC5=1421#6b05020^1#6b05080:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp | | (declarator_id@Cpp~GCC5=1487#6b05000^1#6b05020:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp | | |(id_expression@Cpp~GCC5=317#6b04fa0^1#6b05000:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp | | | (unqualified_id@Cpp~GCC5=319#6b04f00^1#6b04fa0:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp | | | (IDENTIFIER@Cpp~GCC5=3368#6b046c0^1#6b04f00:1[`f''] Line 3 Column 33 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | | )unqualified_id#6b04f00 | | |)id_expression#6b04fa0 | | )declarator_id#6b05000 | | )noptr_declarator#6b05020 | | )ptr_declarator#6b05080 | |)parameter_declaration#6b05100 | )template_parameter#6b05120 | )template_parameter_list#6b05140 | (template_parameter@Cpp~GCC5=2085#6b05440^1#6b05460:2 Line 3 Column 36 File C:/temp/prime_with_templates.cpp | (parameter_declaration@Cpp~GCC5=1611#6b05420^1#6b05440:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp | |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b05160^1#6b05420:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp | | (decl_specifier@Cpp~GCC5=1073#6b04fe0^1#6b05160:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp | | (trailing_type_specifier@Cpp~GCC5=1118#6b050e0^1#6b04fe0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp | | (simple_type_specifier@Cpp~GCC5=1140#6b050c0^1#6b050e0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp)simple_type_specifier | | )trailing_type_specifier#6b050e0 | | )decl_specifier#6b04fe0 | |)basic_decl_specifier_seq#6b05160 | |(ptr_declarator@Cpp~GCC5=1417#6b053e0^1#6b05420:2 Line 3 Column 40 File C:/temp/prime_with_templates.cpp | | (noptr_declarator@Cpp~GCC5=1421#6b053c0^1#6b053e0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp | | (declarator_id@Cpp~GCC5=1487#6b05360^1#6b053c0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp | | (id_expression@Cpp~GCC5=317#6b05280^1#6b05360:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp | | |(unqualified_id@Cpp~GCC5=319#6b051a0^1#6b05280:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp | | | (IDENTIFIER@Cpp~GCC5=3368#6b046a0^1#6b051a0:1[`p''] Line 3 Column 40 File C:/temp/prime_with_templates.cpp)IDENTIFIER | | |)unqualified_id#6b051a0 | | )id_expression#6b05280 | | )declarator_id#6b05360 | | )noptr_declarator#6b053c0 | |)ptr_declarator#6b053e0 | )parameter_declaration#6b05420 | )template_parameter#6b05440 | )template_parameter_list#6b05460


Obviamente, si toma la pregunta literalmente, casi todos los idiomas con identificadores son sensibles al contexto.

Es necesario saber si un identificador es un nombre de tipo (un nombre de clase, un nombre introducido por typedef, un parámetro de plantilla de nombre de tipo), un nombre de plantilla o algún otro nombre para poder utilizar correctamente el identificador. Por ejemplo:

x = (name)(expression);

es una conversión si namees un nombre de tipo y una llamada de función si namees un nombre de función. Otro caso es el llamado "análisis más desconcertante" donde no es posible diferenciar la definición de variable y la declaración de función (hay una regla que dice que es una declaración de función).

Esa dificultad ha introducido la necesidad de typenamey templatecon nombres dependientes. El resto de C ++ no es sensible al contexto por lo que yo sé (es decir, es posible escribir una gramática libre de contexto para él).


C ++ no es libre de contexto. Lo aprendí hace algún tiempo en la conferencia de compiladores. Una búsqueda rápida proporcionó este enlace, donde la sección "Sintaxis o semántica" explica por qué C y C ++ no están libres de contexto:

Wikipedia Talk: gramática libre de contexto

Saludos,
Ovanes


Se ha demostrado que las plantillas de C ++ son muy potentes. Aunque no es una referencia formal, aquí hay un lugar para mirar en ese sentido:

http://cpptruths.blogspot.com/2005/11/c-templates-are-turing-complete.html

Voy a aventurar una conjetura (tan antigua como una prueba de CACM folkoric y concisa que muestra que ALGOL en los años 60 no puede ser representada por un CFG) y decir que C ++ no puede ser analizada correctamente solo por un CFG. CFG, junto con varios mecanismos de TP, ya sea en un pase de árbol o durante eventos de reducción, esta es otra historia. En un sentido general, debido al problema de detención, existe un programa de C ++ que no se puede demostrar que sea correcto / incorrecto, pero aún así es correcto / incorrecto.

{PS- Como el autor de Meta-S (mencionado por varias personas arriba) - Ciertamente puedo decir que Thothic no está ni desaparecido, ni el software está disponible de forma gratuita. Tal vez haya redactado esta versión de mi respuesta de manera que no me borre ni vote a favor de -3.}