¿Por qué hay tan pocos intérpretes de C++?

programación


Personalmente, conozco solo 1 intérprete de C++, que utiliza Root (CINT, desarrollado en el CERN). Me hizo preguntarme por qué hay tan pocos, y la respuesta obvia es que C++ es un lenguaje muy complejo de analizar. Nadie en su sano juicio se molestaría en escribir un analizador de C++ desde cero…

Sin embargo, existen analizadores de C++ como parte de los compiladores, algunos de los cuales son de código abierto. Se me ocurrió que podría ser posible interpretar el código ensamblador que emite el analizador sobre la marcha. Esto sería como un compilador JIT que emite código de bytes para ser interpretado por una máquina virtual. Un problema que me viene a la mente es el uso de diferentes archivos fuente que, de otro modo, darían lugar a varios archivos objeto que deberían vincularse. De hecho, esto es una limitación, pero no muy grave si me preguntas.

Aún así, parece que nadie ha hecho esto, lo que normalmente significa que no es tan fácil como parece (no es que mi idea sea trivial, pero aún así). Me preguntaba cuáles serían los problemas con mi idea… ¿Alguien quiere comentar?

Solución 1

Consulte los comentarios a la pregunta, de bling (buena idea sobre C++/CLI) y de mí.

El hecho es: CINT no es un intérprete de C++. CINT no es un intérprete de C++. Esto se dice claramente aquí:

[^].

El lenguaje es un lenguaje simplificado basado en C y C++.

Ver también: http://root.cern.ch/drupal/content/cling[^].

¿Qué tal una alternativa mencionada en el artículo de Wikipedia mencionado anteriormente, “Ch”? Este no es exactamente un intérprete de C++, es un intérprete de algún lenguaje especial:
http://en.wikipedia.org/wiki/Ch_%28computer_programming%29[^],

[^].

¿Algo más? “Pike”, también basado únicamente en C y C++ (Wikipedia incluso dice “influenciado por”):
http://en.wikipedia.org/wiki/Pike_%28programming_language%29[^],

[^].

En cuanto al lenguaje C++ “real”, algunos creo que no es adecuado para un intérprete; El tema es demasiado complejo para discutir mis consideraciones en un Rápido Preguntas y respuestas. No puedo probarlo aquí y no estoy 100% seguro, por lo que tiendo a pensar que es posible probarlo. Me sorprendería bastante si alguien demostrara que estoy equivocado.

-SA

Solución 3

Cita:

Personalmente, conozco solo 1 intérprete de C++, que utiliza Root (CINT, desarrollado en el CERN). Me hizo preguntarme por qué hay tan pocos, y la respuesta obvia es que C++ es un lenguaje muy complejo de analizar. Nadie en su sano juicio se molestaría en escribir un analizador de C++ desde cero…

Aquí hay algunas preguntas importantes: ¿Cuál es su objetivo y por qué un intérprete de C/C++ sería la mejor solución (o al menos razonablemente buena) para ese problema? “¿Cuál es tu objetivo?” y “¿Por qué X es una buena solución?” Por lo general, son muy buenas primeras preguntas que se deben hacer antes de perder un tiempo valioso en implementar una solución.

C/C++ no es práctico como lenguaje interpretado basado en consola por muchas razones y a la gente generalmente no le gusta perder el tiempo implementando herramientas que no son prácticas (bueno, tal vez aquellos que tienen mucho tiempo para divertirse y aprender y/o aquellos que no pueden prever los aspectos poco prácticos).

Implementar un intérprete para un lenguaje dinámico (como Python) con variables escritas dinámicamente y “funciones vinculadas dinámicamente” es mucho más fácil y menos propenso a errores que hacer lo mismo con C/C++. Escribir todo el analizador, compilador e intérprete para un lenguaje dinámico simple es bastante fácil y rápido. El intérprete en sí no tiene que ser muy eficaz porque generalmente se usa solo para ejecutar código adhesivo de lógica de alto nivel. Si algo es crítico para el rendimiento, puede implementarlo como un módulo C/C++ nativo para su intérprete y vincularlo al lenguaje interpretado dinámicamente. En mi opinión, no has pensado realmente en los problemas que surgirían con los intérpretes de C/C++. Podría escribir una novela sobre ellos. Estos son los problemas más interesantes que son lo suficientemente grandes:

C/C++ requiere declaraciones directas. En un lenguaje interpretado práctico no hay declaraciones directas ni declaraciones/definiciones separadas. Pero esto es sólo una pequeña parte de un problema más serio: C/C++ es poco práctico para ser utilizado como lenguaje interpretado. Este es un conjunto de problemas que involucran tanto problemas de diseño del lenguaje como problemas prácticos de usabilidad como lenguaje interpretado. En Python puedo definir fácilmente una función X que llama a una función Y inexistente y puedo definir esta función Y más adelante. Luego puedo ejecutar X. Más tarde, si quiero, puedo cambiar completamente la definición de Y (tal vez con algunos nuevos parámetros inicializados por defecto para que sean compatibles con la definición anterior) y otra ejecución de X usa inmediatamente la nueva definición de Y. Puedo ejecutar X incluso si llama a una función Z que aún no se ha definido y esto no es un problema si la ejecución de X con los parámetros de entrada reales no se ejecuta en la rama que llamaría a Z. En un Intérprete de C++, ¿qué sucede si cambio la definición de una plantilla muy básica (por ejemplo, una matriz dinámica) que utilizan muchas funciones previamente definidas (por ejemplo, como funciones integradas)? ¿Cómo puede saber qué bloques de código necesitan ser recompilados dentro de su intérprete para poder utilizar las nuevas funciones en línea? ¿Qué pasa si la recopilación de algunas de estas funciones falla con la nueva definición? No tienes problemas serios como este con lenguajes dinámicos como Python. Tratar con tales escenarios en un intérprete no dinámico sería un gran problema, y ​​estos fueron sólo dos problemas “simples/básicos”, esto es sólo la punta del iceberg. He estado programando C/C++ durante más de una década y nunca sentí la necesidad de un intérprete de C/C++.

Cita:

Sin embargo, existen analizadores de C++ como parte de los compiladores, algunos de los cuales son de código abierto. Se me ocurrió que podría ser posible interpretar el código ensamblador que emite el analizador sobre la marcha. Esto sería como un compilador JIT que emite código de bytes para ser interpretado por una máquina virtual. Un problema que me viene a la mente es el uso de diferentes archivos fuente que, de otro modo, darían lugar a varios archivos objeto que deberían vincularse. De hecho, esto es una limitación, pero no muy grave si me preguntas.

Comencé a escribir una respuesta, pero se volvió demasiado larga y compleja ya que analizaba su problema en muchas secciones transversales diferentes. En lugar de eso, escribo aquí sólo algunas de mis conclusiones.

Deberías responder las preguntas que publiqué en el párrafo anterior. Por tu pregunta creo que tal vez tu objetivo sea simplemente crear A Intérprete de C++ con la menor cantidad de trabajo invertido: supongo que esto se debe a que desea reutilizar elementos (unidades de compilación, archivos de objetos) de compiladores existentes. Mi problema con esto es que la gente hace algo con “menos trabajo invertido” cuando tiene que hacer algo que no le gusta. Por otro lado, si hacen algo sólo por diversión, como pasatiempo o con un propósito específico, normalmente no les importa trabajar mucho. En el caso de un intérprete de C/C++, todas las soluciones parecen implicar mucho trabajo.

Dependiendo del compilador y de su configuración, los archivos objeto pueden contener algo más de lo que necesita. No están estandarizados e incluso el mismo compilador puede colocarles basura completamente inútil con algunas configuraciones (como LTCG). En mi opinión, sería más práctico escribir un backend para emitir lo que necesita en lugar de intentar analizarlo desde archivos objeto.

Solución 4

Mi razón especulativa: parece que nadie ha tenido la necesidad ni el esfuerzo de hacerlo. Es decir, podrías construir una Torre Eiffel en tu jardín, suponiendo que tengas el espacio, el material, la gente, el terreno suficientemente bueno, etc. y que puedas hacerlo para tu propio placer. 😉

La diferencia de C a C++ es la indicada en el estándar C++:

Además de las funciones proporcionadas por C, C++ proporciona tipos de datos adicionales, clases, plantillas, excepciones, espacios de nombres, sobrecarga de operadores, sobrecarga de nombres de funciones, referencias, operadores de gestión de tiendas gratuitos y funciones de biblioteca adicionales.

Si va a C++ 11, puede agregar expresiones lambda y varias otras partes, todas principalmente azúcar sintáctica en el sentido de que abstraen algo que está principalmente relacionado con el analizador y que también podría hacerse (si no es tedioso) por otros medios.

Los resultados como elementos de tiempo de ejecución al analizar las características anteriores son
– tipos de datos adicionales: algunos tipos de caracteres/numéricos más integrados
– clase: funciones de instancia extendidas con this parámetro
– clase: herencia con clase base como subobjeto de una clase derivada
– clase: llamadas a funciones implícitas especiales (ctor, dtor, etc.)
– clase: vtable para llamadas a funciones virtuales
– clase: el orden de las definiciones (en su mayoría) no importa en las clases – sólo se ve afectada la búsqueda de nombres
– plantillas: clases o funciones generadas basadas en tipos o valores integrales constantes
– excepciones: flujo de control adicional y especialmente código de limpieza y contabilidad
– espacios de nombres: “azúcar sintáctico” (los tipos, objetos y funciones únicos se definen y llaman)
– sobrecarga: “azúcar sintáctico” (el analizador crea llamadas a las funciones correctas)
– referencias: “azúcar sintáctico”, da como resultado punteros o ningún código de tiempo de ejecución
– nuevo/eliminar: memoria de bajo nivel malloc/gratis más llamadas ctor/dtor
– bibliotecas: colección de elementos que se basan en características del lenguaje
– expresión lambda: “azúcar sintáctico” (clase de funtor implícita)
-…

Hay problemas de detalles desagradables que superar, pero técnicamente puede considerarse como un C mucho más extendido.

Entonces, si tiene una interfaz C++ que logra traducirse a C funcionalmente equivalente, entonces llegó al nivel de CINT. Problemas como múltiples archivos y referencias a bibliotecas y archivos de objetos no son exclusivos de C++, sino que son un hecho común con todos los lenguajes C*. Entonces, puedes reutilizar estos conceptos del intérprete de esos idiomas (¿CINT?).

Pero, una vez más, justificar el esfuerzo depende en gran medida de la posible “ganancia”.

Salud
Y yo

Solución 5

Porque C++ es un lenguaje de programación masivo. Es demasiado complicado. Los intérpretes se crean para lenguajes como Python y JavaScript, no solo porque son simples, sino que están destinados a ser interpretados, son dinámicos. La primera implementación de Python fue un intérprete; no un compilador. No sólo ésta es la razón. Ya se sabe que C++ es más rápido que los lenguajes interpretados cuando se “compila”. Pero no siempre se puede esperar lo mismo de un intérprete de C++. C++ es sensible al contexto; C++ es enorme; C++ contiene genéricos. Por tanto, la complejidad del lenguaje contribuye al lento procesamiento del código fuente. Por ejemplo, consulte las velocidades de compilación de C++. ¿Qué pasará si interpretas la fuente? Dicho esto, es posible que un programa clásico de “hola mundo” no lleve mucho tiempo. ¿Pero piensa en un programa con un uso intensivo de técnicas genéricas?

Pero aún quedan algunos intérpretes como CINT, Cap. Vea la siguiente página:

[^]

Solución 2

Es realmente difícil “resolver” esta pregunta; puede haber sido mejor en un foro, pero aquí está mi 2c.

La definición del lenguaje realmente no excluye la creación de un intérprete, pero C++ realmente fue diseñado como un lenguaje de bajo nivel que puede usarse para código extremadamente eficiente. El lenguaje es extremadamente complejo, pero no imposible de analizar (que yo sepa, realmente requiere un analizador GLR o un analizador escrito a mano). Dicho esto, la mayor parte de las bondades de C++ proviene del hecho de que puede usarse para código eficiente, que se ejecuta cerca de la máquina. Los intérpretes se utilizan normalmente para tareas de alto nivel, donde la iteración rápida durante el desarrollo es más importante que la velocidad de ejecución.

En resumen, sería muchísimo trabajo y correría como un perro.

コメント

タイトルとURLをコピーしました