I've written a parser for a subset of the LISP programming language and would now like to write an interpreter. I've been told that the visitor pattern is desirable because it helps keep the syntax classes uncluttered with evaluation logic.
I'm having trouble writing the actual "accept" and "visit" methods, and in particular specifying the return type. In my syntax classes, everything is an IExpression
. Here are some of the expressions I parse the input to:
public interface IExpression
{
}
public class Number : IExpression
{
public Number(double x)
{
Val = x;
}
public readonly double Val;
}
public class Bool : IExpression
{
public Bool(bool b)
{
Val = b;
}
public readonly bool Val;
}
public class Definition : IExpression
{
public Definition(string name, IExpression expr)
{
Name = name; Expr = expr;
}
public readonly string Name;
public readonly IExpression Expr;
}
public class Conditional : IExpression
{
public Conditional(IExpression test,
IExpression trueBranch, IExpression falseBranch)
{
Test = test; TrueBranch = trueBranch; ElseBranch = falseBranch;
}
public readonly IExpression Test;
public readonly IExpression TrueBranch;
public readonly IExpression ElseBranch;
}
public class Add : NumericExpression
{
public Add(IExpression x, IExpression y)
{
X = x; Y = y;
}
public readonly IExpression X;
public readonly IExpression Y;
}
And here is the visitor interface.
public interface IVisitor
{
double Visit(Add add)
}
How should I now "visit" an Add
node? If I add public double Accept(IVisitor v)
to the IExpression
interface, everything has to implement
"accept" for doubles, even if the expression can never produce a double (take, for example, the case of my Bool
type). This doesn't seem correct, and I'm wondering if I'm missing an opportunity to use generics.