domingo, 20 de diciembre de 2009

Haciendo un intérprete de LISP (IX)

Hasta ahora hemos usado los entornos sin definir claramente cómo son. Ahora lo haremos.

Entornos

Un entorno no es más que un mapa de las cadenas (nombres) a las celdas de un montículo. Adicionalmente, los entornos deben poder usar nombres de entornos ya creados. Entornos padres.

class Environment
{
public:
Environment(Cell* parent) : m_Parent(parent) {}

Cell& FindBond(STRING name)const;
Cell& Bind(Heap& heap, std::wstring const& name, NATIVE native);
Cell& Bind(Heap& heap, std::wstring const& name, Cell& cell);

void Print(std::wostream& o, std::wstring const& indent, int depth=10)const;

public:
Cell* m_Parent;
typedef std::map<string, Cell*> BONDMAP;
BONDMAP m_Bonds;
};

Hemos usado un pequeño atajo para incluir funciones nativas.

Cell& Environment::Bind(Heap& heap, std::wstring const& name, NATIVE native)
{
Cell& r=heap.CreateNative(native);
m_Bonds[heap.GetStringFromPool(name)]=&r;
return r;
}

Cell& Environment::Bind(Heap& heap, std::wstring const& name, Cell& cell)
{
m_Bonds[heap.GetStringFromPool(name)]=&cell;
return cell;
}

Buscando en el entorno padre

La búsqueda en un entorno no debe fallar si no se encuentra el nombre deseado. En ese caso hemos de recurrir al entorno padre. Esta es una forma de extender el entorno padre de manera sencilla.

Cell& Environment::FindBond(STRING name)const
{
BONDMAP::const_iterator i=m_Bonds.find(name);
if(i==m_Bonds.end() || i->second==NULL)
{
if(m_Parent==NULL)
throw std::runtime_error("Unknown symbol");

return m_Parent->GetEnvironment().FindBond(name);
}

return *i->second;
}

El resultado es una función de búsqueda recursiva, pero sin mayor dificultad.

0 comentarios:

Publicar un comentario