Desarrollando un lenguaje dinámico


11

He creado varios compiladores escritos a mano para lenguajes muy simples, pero ahora quiero intentar desarrollar un lenguaje dinámico, similar a un Python o Ruby simplificado. Sin embargo, fue fácil para mí entender cómo funcionan los compiladores. Los compiladores primitivos solo traducen. Pero no puedo hacer esto si el lenguaje es dinámico. Tengo que escribir un intérprete o VM que haga un seguimiento de la información en tiempo de ejecución y me ponga mucho más trabajo.

En resumen, ¿hay algún recurso que deba consultar considerando que sé cómo funcionan los compiladores pero quiero migrar para crear un intérprete? Hay algunas máquinas virtuales para los lenguajes dinámicos, pero no tengo ningún problema con el mío. Todo esto es solo para mi experiencia personal.

Estoy buscando información sobre cómo pasar de un compilador a un intérprete. Si ya he hecho un compilador para el lenguaje X pero ahora qué escribir un intérprete, ¿qué hay que hacer? ¿Hay algún recurso que vaya sobre el proceso?

No quiero recursos amplios o abstractos que analicen cómo funcionan los compiladores o las máquinas virtuales. Tengo muchos libros de texto sobre el tema. Todos los recursos que encontré en línea suponen que tiene 0 experiencia y, por lo tanto, comienzan con un análisis léxico o sintáctico o son extremadamente abstractos. Tengo un compilador que funciona, pero ahora quiero convertir esto en un intérprete y agregar funciones dinámicas al lenguaje.

No pude encontrar recursos en este proceso, puede tener un alcance demasiado limitado o recursos en el "back end" de un intérprete sin ser demasiado teórico, por eso publiqué aquí.


1
Hay toneladas de recursos como este. Tenga en cuenta que la línea entre el compilador y el intérprete es más borrosa de lo que cree; el compilador C # 4.0 admite programación dinámica, al igual que otros compiladores.
Robert Harvey

@RobertHarvey Sí, lo que pido es recursos para hacer mi propio tiempo de ejecución / intérprete / máquina virtual. ¡El intérprete .Net es demasiado complicado para mí como para basar el mío!
Austin Henley


1
Y mira esta pregunta SO , hay un par de comentarios con referencias a otras preguntas que son bastante interesantes ...
Yannis

Respuestas:


4

Primero aprenda sobre la implementación de intérpretes. Recomiendo PLAI (Lenguajes de programación: aplicación e interpretación) . Llega a la carne de la interpretación rápidamente sin detenerse demasiado en la sintaxis.

Para su idioma, podrá reutilizar el front-end del compilador (analizador, en su mayoría) y la biblioteca de tiempo de ejecución (GC, estructuras de datos, operaciones primitivas, etc.).

Por supuesto, también puede implementar un lenguaje dinámico con un compilador que produce código que manipula (algunas de) las mismas estructuras de datos que usaría en un intérprete. Por ejemplo, en un intérprete puede implementar variables globales como una tabla hash indexada por cadenas. En un compilador, compilaría referencias de variables globales en el código que realiza la búsqueda utilizando la misma tabla. Por el contrario, podría compilar variables léxicas en una representación más eficiente (argumentos "nativos" y referencias de estructura de cierre).


5

Si desea aprender los conceptos básicos de la implementación de un intérprete para un lenguaje dinámico, no puedo imaginar un mejor lugar para comenzar que los orígenes del primer lenguaje de programación dinámico e interpretado: Lisp.

En su artículo original de 1960 , John McCarthy definió 5 funciones primitivas necesarias para un Lisp. Por supuesto, McCarthy solo pretendía que su artículo sobre Lisp fuera un ejercicio académico; Fue un estudiante de posgrado quien participó evalen la asamblea y creó el primer intérprete Lisp. Paul Graham identifica siete primitivas : cita, átomo, ecualización, contras, automóvil, cdr y cond.

La cuestión es que realmente puedes implementar Lisp en cualquier idioma; una vez que lo implementa eval, es fácil configurar un REPL y tiene un intérprete interactivo . Las personas se aburrieron o tuvieron la curiosidad de implementar Lisps en C, Java, Ruby, Python y muchos otros lenguajes. Y no siempre a propósito; Es importante recordar la Décima Regla de Greenspun :

Cualquier programa C o Fortran suficientemente complicado contiene una implementación ad hoc, especificada informalmente, llena de errores y lenta de la mitad de Common Lisp.

No digo que su objetivo final sea una implementación de Lisp; pero la homoiconicidad tiene sus beneficios al aprender a implementar un lenguaje dinámico; ¿Por qué lidiar con problemas de sintaxis cuando puede aprender en un idioma en el que la sintaxis idiomática es idéntica a la AST de un idioma que utiliza un lexer / parser?

De todos modos ... solo una sugerencia. Pero es con razón que la mayoría de los grandes lenguajes de programación desde C tienen al menos un poco de la naturaleza Lisp.


1
Desearía poder aceptar dos respuestas. Gracias, creo que realmente implementaré un intérprete Lisp. Es fácil de analizar, tiene mucha documentación y código existente, y debería darme una base para trabajar. Desafortunadamente, tomé una clase de pregrado que usó Scheme y me hizo arrancarme el pelo;)
Austin Henley

1
¡Ahora estoy tentado de compilar mi idioma en mi propio dialecto de Lisp!
Austin Henley

1

0

Puse esto (~ 600 líneas de C #) en el dominio público, que admite quote / list / apply / eval / test / etc, y permite personalizar fácilmente una sintaxis tipo Lisp y / o las funciones semánticas incorporadas:

https://repl.it/CdjV/3

P.ej:

        var factorial = (Lambda)language.
            Evaluate
            (@"
                ( => ( n ) (
                        ? ( != n 0 )
                        ( * n ( this ( - n 1 ) ) )
                        1
                    )
                )
            ");

        var sw = new System.Diagnostics.Stopwatch();
        var n = 12;
        var r = 0;
        int k;
        sw.Start();
        for (k = 0; k < 10000; k++)
        {
            r = (int)factorial.Invoke(null, n);
        }
        sw.Stop();
        Console.WriteLine("{0}! = {1}", n, r);
        Console.WriteLine();
        Console.WriteLine("in {0} ms (for {1} times)", sw.ElapsedMilliseconds, k.ToString("0,0"));

«HTH


0

Suponiendo que conoce un poco de Scheme (por ejemplo, si ha leído SICP ) o Lisp, le recomiendo el libro Lisp In Small Pieces de Queinnec . Explica varias variantes de intérpretes y compiladores similares a Lisp (incluso a bytecode o C).

Además, lea la Pragmática del lenguaje de programación de Scott , el último Libro del dragón , el manual de GC , los Tipos de Pierce y los lenguajes de programación .

Estoy buscando información sobre cómo pasar de un compilador a un intérprete.

Entonces, la evaluación parcial (y las proyecciones de Futamura) y el estilo de paso de continuación podrían ser relevantes.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.