Jestem w trakcie tworzenia własnego języka programowania, który robię do celów edukacyjnych. Napisałem już leksyk i parser rekurencyjnego zapisu dla podzbioru mojego języka (obecnie obsługuję wyrażenia matematyczne, takie jak + - * /
i nawiasy). Analizator składni oddaje mi Streszczenie Drzewo Składni, w którym wywołuję Evaluate
metodę, aby uzyskać wynik wyrażenia. Wszystko dziala. Oto w przybliżeniu moja obecna sytuacja (przykłady kodu w języku C #, chociaż jest to w dużej mierze niezależne od języka):
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;
}
}
Chciałbym jednak oddzielić algorytm od węzłów drzewa, ponieważ chcę zastosować zasadę otwartej / zamkniętej, aby nie musieć ponownie otwierać każdej klasy węzła, gdy chcę na przykład zaimplementować generowanie kodu. Czytam, że Wzorzec Odwiedzających jest do tego odpowiedni. Dobrze rozumiem, w jaki sposób działa wzór, i że korzystam z podwójnej wysyłki. Ale ze względu na rekurencyjną naturę drzewa nie jestem pewien, jak mam do niego podejść. Oto jak wyglądałby mój gość:
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
}
To jest mój problem. Chcę rozwiązać ten problem natychmiast, podczas gdy mój język nie obsługuje wielu funkcji, aby uniknąć później większego problemu.
Nie wysłałem tego do StackOverflow, ponieważ nie chcę, abyś dostarczył implementację. Chcę tylko, abyś podzielił się pomysłami i koncepcjami, które mogłem przegapić, i tym, jak powinienem do tego podejść.