The interesting bit is the Expr class really:
using System;class ExprException: Exception{ public ExprException(string m): base(m) { }}abstract class Node{ public Node(){ } public abstract int Calc();}class LitNode: Node{ public int Value; public LitNode(int V){ Value=V; } public override int Calc(){ return Value; }}class AddNode: Node{ public Node Ln,Rn; public AddNode(Node L,Node R){ Ln=L; Rn=R; } public override int Calc() { return Ln.Calc()+Rn.Calc(); }}class SubNode: Node{ public Node Ln,Rn; public SubNode(Node L,Node R){ Ln=L; Rn=R; } public override int Calc() { return Ln.Calc()-Rn.Calc(); }}class MulNode: Node{ public Node Ln,Rn; public MulNode(Node L,Node R){ Ln=L; Rn=R; } public override int Calc() { return Ln.Calc()*Rn.Calc(); }}class DivNode: Node{ public Node Ln,Rn; public DivNode(Node L,Node R){ Ln=L; Rn=R; } public override int Calc() { return Ln.Calc()/Rn.Calc(); }}class NegNode: Node{ public Node Nn; public NegNode(Node N){ Nn=N; } public override int Calc() { return -Nn.Calc(); }}class Expr{ public static Node Norm(Parser P,bool Get) { Node N=Term(P,Get); while(true) { switch(P.Type) { case Parser.Types.Add: N=new AddNode(N,Term(P,true)); break; case Parser.Types.Sub: N=new SubNode(N,Term(P,true)); break; default: return N; } } } public static Node Term(Parser P,bool Get) { Node N=Prim(P,Get); while(true) { switch(P.Type) { case Parser.Types.Mul: N=new MulNode(N,Prim(P,true)); break; case Parser.Types.Div: N=new DivNode(N,Prim(P,true)); break; default: return N; } } } public static Node Prim(Parser P,bool Get) { Parser.Types T=P.Next(Get); Node N=null; switch(T) { case Parser.Types.Number: N=new LitNode(Convert.ToInt32(P.Text)); P.Next(true); return N; case Parser.Types.Lp: N=Norm(P,true); if(P.Type!=Parser.Types.Rp) throw new ExprException("right bracket expected - "+P.Text); P.Next(true); return N; case Parser.Types.Sub: return new NegNode(Prim(P,true)); default: throw new ExprException("primary expected - "+P.Text); } }}
Obviously this is something I've done a lot in C++ but I found it really easy to translate the idea into C#. It really is a very beautiful language.