Estoy en el proceso de crear mi propio lenguaje de programación, lo cual hago para aprender. Ya escribí el lexer y un analizador de descenso recursivo para un subconjunto de mi lenguaje (actualmente soporto expresiones matemáticas, como + - * /
y paréntesis). El analizador me devuelve un Árbol de sintaxis abstracta, en el que llamo al Evaluate
método para obtener el resultado de la expresión. Todo funciona bien Aquí está aproximadamente mi situación actual (ejemplos de código en C #, aunque esto es bastante independiente del lenguaje):
public abstract class Node
{
public abstract Double Evaluate();
}
public class OperationNode : Node
{
public Node Left { get; set; }
private String Operator { get; set; }
private Node Right { get; set; }
public Double Evaluate()
{
if (Operator == "+")
return Left.Evaluate() + Right.Evaluate();
//Same logic for the other operators
}
}
public class NumberNode : Node
{
public Double Value { get; set; }
public Double Evaluate()
{
return Value;
}
}
Sin embargo, me gustaría desacoplar el algoritmo de los nodos del árbol porque quiero aplicar el Principio Abierto / Cerrado para no tener que volver a abrir cada clase de nodo cuando quiero implementar la generación de código, por ejemplo. Leí que el patrón de visitante es bueno para eso. Tengo una buena comprensión de cómo funciona el patrón y que usar el envío doble es el camino a seguir. Pero debido a la naturaleza recursiva del árbol, no estoy seguro de cómo debería abordarlo. Así es como se vería mi visitante:
public class AstEvaluationVisitor
{
public void VisitOperation(OperationNode node)
{
// Here is where I operate on the operation node.
// How do I implement this method?
// OperationNode has two child nodes, which may have other children
// How do I work the Visitor Pattern around a recursive structure?
// Should I access children nodes here and call their Accept method so they get visited?
// Or should their Accept method be called from their parent's Accept?
}
// Other Visit implementation by Node type
}
Entonces este es mi problema. Quiero abordarlo de inmediato mientras mi idioma no admite muchas funcionalidades para evitar tener un problema mayor más adelante.
No publiqué esto en StackOverflow porque no quiero que proporciones una implementación. Solo quiero que comparta ideas y conceptos que podría haber pasado por alto, y cómo debería abordar esto.