Estou no processo de criar minha própria linguagem de programação, o que faço para fins de aprendizado. Eu já escrevi o lexer e um analisador de descida recursiva para um subconjunto da minha linguagem (atualmente, suporte expressões matemáticas, como + - * /
parênteses e). O analisador devolve uma Árvore de Sintaxe Abstrata, na qual chamo o Evaluate
método para obter o resultado da expressão. Tudo funciona bem. Aqui está aproximadamente minha situação atual (exemplos de código em C #, embora isso seja praticamente independente do idioma):
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;
}
}
No entanto, eu gostaria de desacoplar o algoritmo dos nós da árvore, porque quero aplicar o Princípio Aberto / Fechado, para não precisar reabrir todas as classes de nós quando desejar implementar a geração de código, por exemplo. Eu li que o Padrão do Visitante é bom para isso. Eu tenho um bom entendimento de como o padrão funciona e que usar o envio duplo é o caminho a seguir. Mas, devido à natureza recursiva da árvore, não tenho certeza de como devo abordá-la. Aqui está a aparência do meu 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
}
Então esse é o meu problema. Quero abordá-lo imediatamente, enquanto meu idioma não suporta muita funcionalidade para evitar problemas maiores posteriormente.
Não publiquei isso no StackOverflow porque não quero que você forneça uma implementação. Eu só quero que você compartilhe idéias e conceitos que eu possa ter perdido, e como devo abordar isso.