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

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

No se trata de lo que quieres comprar, sino de quién quieres ser. Aprovecha el precio especial.

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

13 Días
21 Hrs
57 Min
9 Seg

Declaración y ejecución de funciones

8/58
Recursos

Aportes 12

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

No se vale, el reto ya estaba resuelto xD Prácticamente el lexer ya es capaz de identificar la mayoría de tokens de nuestro lenguaje, ya solo era cuestión de escribir el test jajaja:

def test_function_call(self) -> None:
        
        source: str = """
            variable resultado = suma(dos, tres);
        """
        lexer: Lexer = Lexer(source)

        tokens: List[Token] = []

        for i in range(10):

            tokens.append(lexer.next_token())

        expected_tokens: List[Token] = [
            Token(TokenType.LET, "variable"),
            Token(TokenType.IDENT, "resultado"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.IDENT, "suma"),
            Token(TokenType.LPAREN, "("),
            Token(TokenType.IDENT, "dos"),
            Token(TokenType.COMMA, ","),
            Token(TokenType.IDENT, "tres"),
            Token(TokenType.RPAREN, ")"),
            Token(TokenType.SEMICOLON, ";"),
        ]

        self.assertEquals(tokens, expected_tokens)

Por cierto, en mi caso cambiaré el keyword “procedimiento” por el keyword “funcion”, a mi parecer la palabra “procedimiento” es una palabra más complicada de entender cuando estás aprendiendo a programar jajaja, la palabra “funcion” es más fácil uwu

Que curioso, las funciones en LPP no tienen un token para retorno, pero retornan.

cree esta función para optimizar mis test, para ahorrame las 4 lineas que siempre se repiten en todos los tests, y así solo me concentro en el listado de tokens que debe evaluar mi test.

    def validate_tes(self, source: str, expected_tokens: List[Token]) -> None:
        lexer: Lexer = Lexer(source)

        token: List[Token] = []
        for i in range(len(expected_tokens)):
            token.append(lexer.next_token())

        self.assertEquals(token, expected_tokens)

y en el test del reto se vería así:

    def test_function_call(self) -> None:
        source: str = """
            variable resultado = suma(dos, tres);
        """

        expected_tokens: List[Token] = [
            Token(TokenType.LET, 'variable'),
            Token(TokenType.IDENT, 'resultado'),
            Token(TokenType.ASSIGN, '='),
            Token(TokenType.IDENT, 'suma'),
            Token(TokenType.RPAREN, '('),
            Token(TokenType.IDENT, 'dos'),
            Token(TokenType.COMMA, ','),
            Token(TokenType.IDENT, 'tres'),
            Token(TokenType.LPAREN, ')'),
            Token(TokenType.SEMICOLON, ';'),
        ]

        self.validate_tes(source, expected_tokens) 

y al rescribir todo mi lexer_test.py me quedo de la siguiente forma:

from typing import List
from unittest import TestCase
from typing import List
from lpp.token import (
    Token,
    TokenType
)
from lpp.lexer import Lexer


class LexerTest(TestCase):

    def test_illegal(self) -> None:
        source: str = '¡¿@'

        expected_tokens: List[Token] = [
            Token(TokenType.ILLEGAL, '¡'),
            Token(TokenType.ILLEGAL, '¿'),
            Token(TokenType.ILLEGAL, '@')
        ]

        self.validate_tes(source, expected_tokens)

    def test_one_character_operator(self) -> None:
        source: str = '=+'

        expected_tokens: List[Token] = [
            Token(TokenType.ASSIGN, '='),
            Token(TokenType.PLUS, '+'),
        ]

        self.validate_tes(source, expected_tokens)

    def test_eof(self) -> None:
        source: str = '+'

        expected_tokens: List[Token] = [
            Token(TokenType.PLUS, '+'),
            Token(TokenType.EOF, ''),
        ]

        self.validate_tes(source, expected_tokens)

    def test_delimiters(self) -> None:
        source = '(){},;'

        expected_tokens: List[Token] = [
            Token(TokenType.RPAREN, '('),
            Token(TokenType.LPAREN, ')'),
            Token(TokenType.RBRACE, '{'),
            Token(TokenType.LBRACE, '}'),
            Token(TokenType.COMMA, ','),
            Token(TokenType.SEMICOLON, ';'),
        ]

        self.validate_tes(source, expected_tokens)

    def test_assignment(self) -> None:
        source = 'variable cinco = 5;'

        expected_tokens: List[Token] = [
            Token(TokenType.LET, 'variable'),
            Token(TokenType.IDENT, 'cinco'),
            Token(TokenType.ASSIGN, '='),
            Token(TokenType.INT, '5'),
            Token(TokenType.SEMICOLON, ';'),
        ]

        self.validate_tes(source, expected_tokens)

    def test_function_declaration(self) -> None:
        source = '''
            variable suma = procedimiento(x, y) {
                x + y;
            };
        '''

        expected_tokens: List[Token] = [
            Token(TokenType.LET, 'variable'),
            Token(TokenType.IDENT, 'suma'),
            Token(TokenType.ASSIGN, '='),
            Token(TokenType.FUNCTION, 'procedimiento'),
            Token(TokenType.RPAREN, '('),
            Token(TokenType.IDENT, 'x'),
            Token(TokenType.COMMA, ','),
            Token(TokenType.IDENT, 'y'),
            Token(TokenType.LPAREN, ')'),
            Token(TokenType.RBRACE, '{'),
            Token(TokenType.IDENT, 'x'),
            Token(TokenType.PLUS, '+'),
            Token(TokenType.IDENT, 'y'),
            Token(TokenType.SEMICOLON, ';'),
            Token(TokenType.LBRACE, '}'),
            Token(TokenType.SEMICOLON, ';'),
        ]

        self.validate_tes(source, expected_tokens)

    def test_function_call(self) -> None:
        source: str = """
            variable resultado = suma(dos, tres);
        """

        expected_tokens: List[Token] = [
            Token(TokenType.LET, 'variable'),
            Token(TokenType.IDENT, 'resultado'),
            Token(TokenType.ASSIGN, '='),
            Token(TokenType.IDENT, 'suma'),
            Token(TokenType.RPAREN, '('),
            Token(TokenType.IDENT, 'dos'),
            Token(TokenType.COMMA, ','),
            Token(TokenType.IDENT, 'tres'),
            Token(TokenType.LPAREN, ')'),
            Token(TokenType.SEMICOLON, ';'),
        ]

        self.validate_tes(source, expected_tokens)

    def validate_tes(self, source: str, expected_tokens: List[Token]) -> None:
        lexer: Lexer = Lexer(source)

        token: List[Token] = []
        for i in range(len(expected_tokens)):
            token.append(lexer.next_token())

        self.assertEquals(token, expected_tokens)
 

Espero les sirva, y cualquier aporte o comentario adicional , bienvenido sea 😃

tuvo bueno ` def test_function_call(``self``) -> None: source: ``str`` = 'bolado resultado = suma(dos, tres);'` ` lexer: Lexer = Lexer(source)` ` tokens: List[Token] = [] for i in range(10): tokens.append(lexer.next_token())` ` expected_tokens: List[Token] = [ Token(TokenType.LET, 'bolado'), Token(TokenType.IDENT, 'resultado'), Token(TokenType.ASSIGN, '='), Token(TokenType.IDENT, 'suma'), Token(TokenType.LPAREN, '('), Token(TokenType.IDENT, 'dos'), Token(TokenType.COMMA, ','), Token(TokenType.IDENT, 'tres'), Token(TokenType.RPAREN, ')'), Token(TokenType.SEMICOLON, ';'), ] ``self``.assertEqual(tokens, expected_tokens)`
tamalito
    # Challenge 2
    def test_function_call(self) -> None:
        source: str = 'variable resultado = suma(dos, tres);'
        lexer: Lexer = Lexer(source)
        
        tokens: List[Token] = []
        for i in range(10):
            tokens.append(lexer.next_token())
        
        expected_tokens: List[Token] = [
            Token(TokenType.LET, 'variable'),
            Token(TokenType.IDENT, 'resultado'),
            Token(TokenType.ASSIGN, '='),
            Token(TokenType.IDENT, 'suma'),
            Token(TokenType.LPAREN, '('),
            Token(TokenType.IDENT, 'dos'),
            Token(TokenType.COMMA, ','),
            Token(TokenType.IDENT, 'tres'),
            Token(TokenType.RPAREN, ')'),
            Token(TokenType.SEMICOLON, ';'),

        ]

        self.assertEquals(tokens, expected_tokens)

Mi solución

def test_function_call(self) -> None:
    source: str = 'variable resultado = suma(dos, tres);'
    lexer: Lexer = Lexer(source)

    tokens: List[Token] = []
    token = lexer.next_token()
    while token != Token(TokenType.EOF, ''):
        tokens.append(token)
        token = lexer.next_token()

    expected_tokens: List[Token] = [
        Token(TokenType.LET, 'variable'),
        Token(TokenType.IDENT, 'resultado'),
        Token(TokenType.ASSIGN, '='),
        Token(TokenType.IDENT, 'suma'),
        Token(TokenType.LPAREN, '('),
        Token(TokenType.IDENT, 'dos'),
        Token(TokenType.COMMA, ','),
        Token(TokenType.IDENT, 'tres'),
        Token(TokenType.RPAREN, ')'),
        Token(TokenType.SEMICOLON, ';'),
    ]
    self.assertEquals(tokens, expected_tokens)

De esta manera podemos evitar contar los tokens

	tokens: List[Token] = []
        token = lexer.next_token()
        while token != Token(TokenType.EOF, ''):
            tokens.append(token)
            token = lexer.next_token()

en lugar de

        tokens: List[Token] = []
        for i in range(5):
            tokens.append(lexer.next_token())

espero sea util

Bueno de lo fácil que era no estoy seguro de que esté bien

Reto

Agregando el Keyword procedimiento

Implementación del test test_function_declaration