Sono in procinto di creare il mio linguaggio di programmazione, che faccio per scopi di apprendimento. Ho già scritto il lexer e un parser di discesa ricorsivo per un sottoinsieme del mio linguaggio (attualmente sostengo espressioni matematiche, come + - * /
e parentesi). Il parser mi restituisce un Abstract Syntax Tree, sul quale chiamo il metodo Evaluate
per ottenere il risultato dell'espressione. Tutto funziona bene Ecco approssimativamente la mia situazione attuale (esempi di codice in C #, anche se questo è praticamente indipendente dalla lingua):
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;
}
}
Tuttavia, vorrei disaccoppiare l'algoritmo dai nodi dell'albero perché voglio applicare Principio Aperto / Chiuso, quindi non devo riaprire ogni classe di nodo quando voglio implementare la generazione del codice, per esempio. Ho letto che il pattern Visitor è buono per quello. Ho una buona comprensione di come funziona il modello e che usare la doppia spedizione è la strada da percorrere. Ma a causa della natura ricorsiva dell'albero, non sono sicuro di come dovrei affrontarlo. Ecco come appare il mio visitatore:
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
}
Quindi questo è il mio problema. Voglio affrontarlo immediatamente mentre il mio linguaggio non supporta molte funzionalità per evitare di avere un problema più grande in seguito.
Non l'ho postato su StackOverflow perché non desidero che tu fornisca un'implementazione. Voglio solo che tu condivida idee e concetti che potrei aver perso e come dovrei avvicinarmi a questo.