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
4 Hrs
15 Min
3 Seg

Parseo de condicionales: testing y AST

31/58
Resources

How to parse conditionals in Platzi?

Parsing is a fundamental part of parsing in any programming language and the Platzi programming language is no exception. To parse an if statement, it is crucial to understand its structure. Let's see the importance of converting these elements into nodes within our abstract syntax tree (AST) and how to implement it in detail.

What should we consider in the structure of an if statement?

In the Platzi programming language, as in many others, an if statement starts with a keyword yes, followed by a condition. This condition is crucial since it will determine which code block, or sequence of statements, will be executed if true.

  • Code Block: If the condition is true, the subsequent code block is executed. Code blocks are essentially sequences of statements that are executed only if the if is true.
  • Alternative: Optionally, if the condition is false, an alternative code block can be executed. The possibility of not having an alternative makes the design flexible.

The power of conditionals in Platzi increases since they are considered expressions. This makes it possible, for example, to define a variable with an if expression that functions as a ternary operator:

variable foo equals if x greater than y returns x else y.

How do we test the implementation?

To evaluate whether an if expression is correctly implemented, specific tests are generated. These tests include:

  1. Tests without Alternates:
    • Implement a test that validates an if expression without having an alternative block.
    • Ensure that the first statement in the program is an expression statement that contains an if expression.

Example Python code for such a test would be:

def test_if_expressions(): lexer = Lexer(...) parser = Parser(lexer) program = parser.parse_program() # Check if the first statement is of type "expression" statement = program.statements[0] assert isinstance(statement, ExpressionStatement)
 if_expr = statement.expression assert isinstance(if_expr, IfExpression) # Check conditions assert if_expr.condition is not None # Check consequence assert isinstance(if_expr.consequence, BlockStatement) assert len(if_expr.consequence.statements) == 1 assert if_expr.alternative is None

Node design and implementation: blocks and conditionals

To allow the proper parsing of conditionals, the corresponding classes must be designed:

  • Block class: Represents a sequence of statements executed under a true condition. It includes methods to convert the sequence into a string.
class BlockStatement: def __init__(self, token, statements): self.token = token self.statements = statements
 def to_string(self): out = [statement.to_string() for statement in self.statements] return ''.join(out)
  • Class If (Conditional): An expression that contains a condition, a consequence, and potentially an alternative. The implementation of this class must allow for manageable syntax errors without compromising execution.
class IfExpression: def __init__(self, token, condition, consequence, alternative): self.token = token self.condition = condition self.consequence = consequence self.alternative = alternative
 def to_string(self): out = f'if {self.condition.to_string()}  {self .consequence.to_string()}' if self.alternative: out += f' else {self.alternative.to_string()}' return out

Both of these classes are fundamental to extending our parser's ability to understand and process conditionals correctly.

As you progress in understanding how conditionals and their structures work, it is vital to remember that robust test design is crucial to ensure that your parser handles expected use cases and potential syntax errors elegantly. Keep going, the learning path is full of exciting discoveries!

Contributions 1

Questions 0

Sort by:

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

Vale… estuve teniendo un error de:

Argument 1 to "_test_infix_expression" of "ParserTest" has incompatible type "Optional[Expression]"; expected "Expression"

Ahora entiendo por qué siempre ponemos el:

assert cualquier_cosa is not None

Porque efectivamente mypy se queja jaja, lo había escrito mal, y como esta función esperaba un Expression daba error al obtener un Optional[Expression], por lo que al poner el assert dejó de dar el error porque sabía que gracias al assert ya no podía llegar como None.
.
El problema era que el assert se lo había puesto al if_expression en lugar de al if_expression.condition jaja