Pular para conteúdo

Interpretador de Lisp

Aqui temos um interpretador de lisp, feito em python e de forma rápida e simples. Isto é, há jeitos melhores de se fazer.

  • Você pode navegar no repositório e ver a pasta "LISP", onde vai ter os arquivos originais. Repositório
# pyproject.toml
from typing import Any
from dataclasses import dataclass
import math
import operator

type AST = list
type IR = list | callable | float


FUNCTIONS = {
    "sqrt": math.sqrt, 
    "cos": math.cos, 
    "sin": math.sin, 
    "*": operator.mul,
    "+": operator.add,
    "-": operator.sub,
    "/": operator.truediv,
    "%": operator.mod,
}

@dataclass
class Token:
    text: str
    kind: str
    value: Any = None

def lex(source: str) -> list[Token]:
    """
    Realiza a análise léxica do código fonte.
    """
    source = source.replace("(", " ( ")
    source = source.replace(")", " ) ")
    lexemes = source.split()
    tokens = []

    for substr in lexemes:
        if substr == "(":
            token = Token(substr, "LPAR")
        elif substr == ")":
            token = Token(substr, "RPAR")
        elif substr in FUNCTIONS:
            impl = FUNCTIONS[substr]
            token = Token(substr, "FUNCTION", impl)
        else:
            value = float(substr)
            token = Token(substr, "NUMBER", value)
        tokens.append(token)

    return tokens


def parse(tokens: list[Token]) -> AST:
    """
    Realiza a análise sintática do código.
    """
    curr = None
    stack = []

    for token in tokens:
        if token.kind == "LPAR":
            curr = []
            stack.append(curr)
        elif token.kind == "RPAR":
            lst = stack.pop()
            if not stack:
                return lst
            stack[-1].append(lst)
        else:
            curr.append(token.value)

    raise RuntimeError


def analysis(ast: AST) -> IR:
    """
    Análise semântica.
    """ 
    ir = ast
    return ir

def emit(ir: IR) -> str:
    """
    Emite código
    """
    raise NotImplementedError("PARA CASA ;)")

def interpret(ir: IR) -> Any:
    """
    Interpreta uma árvore sintática/IR.   
    """
    if isinstance(ir, float) or callable(ir):
        return ir
    elif isinstance(ir, list):
        func, *args = map(interpret, ir)
        return func(*args)
    else:
        raise RuntimeError("Tipo errado")

def run(source: str) -> Any:
    tokens = lex(source)
    ast = parse(tokens)
    ir = analysis(ast)
    value = interpret(ir)

    print("=", value)

def run_shell():
    while True:
        try:
            source = input("lisp> ")
        except EOFError:
            break
        if not source:
            break
        run(source)

if __name__ == "__main__":
    import sys

    if len(sys.argv) == 2:
        filename = sys.argv[1]
        with open(filename) as fd:
            source = fd.read()
        run(source)
    else:
        run_shell()