Introducción al desarrollo de intérpretes y lenguajes de programación

1

Aprende a desarrollar lenguajes de programación con intérpretes

2

Desarrolla LPP o Lenguaje de Programación Platzi

Construcción del lexer o tokenizador

3

¿Qué es análisis léxico? Funcionamiento del lexer y tokens

4

Estructura y definición de tokens en Python

5

Lectura de caracteres y tokens

6

Tokens ilegales, operadores de un solo carácter y delimitadores

7

Reconocimiento y diferenciación entre letras y números

8

Declaración y ejecución de funciones

9

Extensión del lexer: condicionales, operaciones y booleanos

10

Operadores de dos caracteres

11

Primera versión del REPL con tokens

Construcción del parser o analizador sintáctico

12

¿Qué es un parser y AST?

13

Estructura y definición de nodos del AST en Python

14

Parseo del programa o nodo principal

15

Parseo de assignment statements

16

Parseo de let statements

17

Parseo de errores

18

Parseo del return statement

19

Técnicas de parsing y pratt parsing

20

Pruebas del AST

21

Implementación del pratt parser

22

Parseo de Identifiers: testing

23

Parseo de Identifiers: implementación

24

Parseo de enteros

25

Prefix operators: negación y negativos

26

Infix operators y orden de las operaciones: testing

27

Infix operators y orden de las operaciones: implementación

28

Parseo de booleanos

29

Desafío: testing de infix operators y booleanos

30

Parseo de expresiones agrupadas

31

Parseo de condicionales: testing y AST

32

Parseo de condicionales: implementación

33

Parseo de declaración de funciones: testing

34

Parseo de declaración de funciones: AST e implementación

35

Parseo de llamadas a funciones: testing y AST

36

Parseo de llamadas a funciones: implementación

37

Completando los TODOs o pendientes del lexer

38

Segunda versión del REPL con AST

Evaluación o análisis semántico

39

Significado de símbolos

40

Estrategias de evaluación para intérpretes de software

41

Representación de objetos

42

Evaluación de expresiones: enteros

43

Evaluación de expresiones: booleanos y nulos

44

Evaluación de expresiones: prefix

45

Evaluación de expresiones: infix

46

Evaluación de condicionales

47

Evaluación del return statement

48

Manejo de errores

49

Ambiente

50

Bindings

51

Evaluación de funciones

52

Llamadas a funciones

Mejora del intérprete

53

Implementación de strings

54

Operaciones con strings

55

Built-in functions: objeto y tests

56

Built-in functions: evaluación

Siguientes pasos

57

Retos para expandir tu intérprete

58

Continúa con el Curso de Creación de Compiladores de Software

You don't have access to this class

Keep learning! Join and start boosting your career

Aprovecha el precio especial y haz tu profesión a prueba de IA

Antes: $249

Currency
$209
Suscríbete

Termina en:

0 Días
2 Hrs
1 Min
37 Seg

Estrategias de evaluación para intérpretes de software

40/58
Resources

What are the evaluation strategies in programming languages?

When we talk about programming languages, we are confronted with a variety of strategies for evaluating code. This not only differs between languages, but also defines their performance, portability and ease of extension. This spectrum moves mainly along two main lines: interpreters and compilers. However, the reality is that between these two extremes there is a continuum of intermediate strategies that use hybrid methods. In the following, we will explore some of these key strategies.

How does a TreeWalking Interpreter work?

The TreeWalking Interpreter represents one of the simplest, but also the most extensible, strategies for evaluating programming languages. It involves traversing and evaluating each part of the Abstract Syntax Tree (AST). Many languages, such as JavaScript in its early days, started using this strategy before evolving to more sophisticated methods such as Just-In-Time Compilation (JIT).

In a TreeWalking Interpreter, source code is converted into tokens through a lexer, then transformed into an AST with a parser, and finally evaluated by traversing the tree. This strategy is particularly useful for new languages because it allows to modify and extend the language easily.

What is Just-In-Time Compilation and how does it work?

JIT Compilation, or Just-In-Time Compilation, is a technique that falls between interpretation and full compilation. JavaScript, for example, in its modern V8 implementation, uses JIT to convert "hot" functions - those that are executed frequently - directly into machine code, avoiding reanalyzing the tree each time it is executed.

This approach allows interpreted languages to reach performance levels close to compiled languages, as it combines the portability of interpretation with the speed of native compilation.

What is the bytecode strategy?

The bytecode strategy generates an intermediate representation that is then executed by a virtual machine. This method is used by languages such as Python and Java. In Python, the AST is transformed into bytecode that is executed by its virtual machine. In Java, the result of the compilation process is a bytecode that is executed in the Java Virtual Machine (JVM).

This method offers excellent portability, since the bytecode is platform independent, allowing the same program to run on different architectures. Moreover, in some cases it is combined with JIT to optimize execution.

How to choose the right evaluation strategy?

Choosing an evaluation strategy depends on several factors:

  • Portability requirements: If we want our code to run on multiple platforms, virtual machines and bytecode are optimal.
  • Speed requirements: To maximize performance, you could opt for compilers that generate machine code directly.
  • Ease of extension and learning: If we are interested in learning and easy extension of a language, the TreeWalking Interpreter could be the best choice.

Verdict on TreeWalking Interpreter in Platzi

In the context of the Platzi programming language, the TreeWalking Interpreter has been chosen as the basic strategy. This is because it allows easy learning and eventual evolution to other types of evaluation. In addition, it addresses the transformation of ASTs into objects, a fundamental process in object-oriented languages such as Python and Ruby.

So, as you can see, evaluation strategies are key to the development and implementation of programming languages. I invite students to deepen their knowledge of algorithms and data structures to master these techniques, as they are essential for every programmer. Keep learning and exploring the fascinating world of programming languages!

Contributions 2

Questions 0

Sort by:

Want to see more contributions, questions and answers from the community?

Depth First, o Primero en Profundidad.

Existen dos estrategias para recorrer una estructura de árbol:
Depth First o Primero en anchura:
Se recorren primero las hojas hermanas, luego las hojas hijas, nivel por nivel.

Breath First o Primero en profundidad:
Se recorren primero las hojas hijas, rama por rama, hasta la más lejana a la raíz primero.

Ambas estrategias tienen sus ventajas y desventajas, pero para este evaluador, la mejor es ir primero en profundidad.

¿Porqué?
Porque así respetamos el órden correcto de los operadores.
En este caso, las hojas “6” y “7” se multiplican primero. Y luego el resultado es asignado a “x”.

En mi caso me gustaría hablar del motor V8 de JavaScript, y esto es algo que ya he hablado en otras clases, pero ahora que entiendo más todo este proceso me gustaría profundizar más en ello:
.
Este es un esquema que tomé del Curso Profesional de JavaScript
.

.
Este es otro que tomé del Curso de JavaScript Engine (V8) y el Navegador
.

.
Son los mismos, pero pongo ambos para que tengan dos visiones diferentes.
.
Todo inicia en el Source Code, justamente ese archivo de texto plano que termina en extensión .js, en nuestro caso, nuestro source code del Lenguaje de Programación Platzi es todo el programa que pasamos, es decir, lo que escribimos en sintaxis de LPP.
.
Podemos ver que JavaScript lo pasa por un parser, para generar su propio AST. El LPP también usa un parser para generar nuestro LPP. Muy seguramente el parser de JavaScript usa un Lexer interno que también genera tokens (de ahí el error Unexpected token... de JavaScript)
.
Recordemos que las computadoras solo entienden machine code, no entienden nada de lo que escribimos dentro de ese archivo que terminan en .js:
.

.
Entonces, para que nuestra computadora pueda entenderlo, hacemos uso del JavaScript Engine, existen demasiados pero el más conocido es V8 que es justamente el que te mostré en las primeras imagenes, básicamente V8 es el intérprete de JavaScript, es su evaluador, es ese motor que traduce todo el código a algo que la computadora puede entender:
.

.
Como se mencionó en la clase, JavaScript usa Just In Time Compiler, es decir, genera código máquina y bytecode al mismo tiempo, y los genera dependiendo de cómo se comporte el código que le pasemos:
.

.
Esto se puede apreciar mejor en este diagrama (la segunda imagen que te puse al inicio):
.

.
El interpreter traduce todo esto a bytecode (este es un código de bajo nivel que es leído por una máquina virtual que lo ejecuta), también podemos ver como el profiler se mantiene vigilando al interpreter en busca de cosas que optimizar para luego tomar la decisión de pasarlo directamente por un compilador y generar código máquina que puede leer la computadora, que por lo general es código mejor optimiazado.
.
La forma en la que el profiler decide esto es, si hay un pedazo de código que se ejecuta mucho (por ejemplom las llamadas a una función), entonces mejor lo optimiza y lo manda directamente a machine code.
.
Sin embargo, cuando una llamada a una función que estaba optimizada cambia y produce un resultado diferente al que solía producri, JavaScript dice: “Uy, esto ya cambio, mejor vamos a deoptimizar esto y mandemoslo a la máquina virtual”, es ahí donde se produce el proceso de deoptimización (primera imagen):
.

.
Es por eso que debemos cuidar nuestra programación en JavaScript para que el lenguaje tenga la posibilidad de echarnos una manita optimizando nuestro código. 😄