using System; using System.Collections.Generic; namespace ExpressionEvaluator { interface IOperatorExpressionType { string OperatorToken { get; } OperatorExpression CreateInstance(); } interface IValueExpressionType { bool CanAcceptToken(string token); ValueExpression CreateInstance(string token); } abstract class Expression { private static Dictionary knownOperatorTypes = new Dictionary(); private static List knownValueTypes = new List(); static Expression() { // // Register well-known operators // RegisterExpressionType(PlusExpression.ExpressionType); RegisterExpressionType(MinusExpression.ExpressionType); RegisterExpressionType(MultiplyExpression.ExpressionType); RegisterExpressionType(DivideExpression.ExpressionType); RegisterExpressionType(UnaryMinusExpression.ExpressionType); // // Register well-known value types // RegisterExpressionType(ConstantExpression.ExpressionType); } public static bool RegisterExpressionType(IOperatorExpressionType type) { if (knownOperatorTypes.ContainsKey(type.OperatorToken)) { return false; } knownOperatorTypes.Add(type.OperatorToken, type); return true; } public static bool RegisterExpressionType(IValueExpressionType type) { if (knownValueTypes.Contains(type)) { return false; } knownValueTypes.Add(type); return true; } public static Expression ParsePrefixExpression(string exprString) { string[] tokens = exprString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Expression result = null; Stack unresolved = new Stack(); foreach (string token in tokens) { if (result != null) { // We correctly parsed the whole tree, but there was at least one more unprocessed token left. // This implies incorrect input, thus return null. return null; } IOperatorExpressionType operatorType; if (knownOperatorTypes.TryGetValue(token, out operatorType)) { // Token is a known operator unresolved.Push(operatorType.CreateInstance()); } else { // Token is not a known operator. Let's ask all value expression types, if any of them is able to accept the token. bool tokenAccepted = false; foreach (IValueExpressionType valueType in knownValueTypes) { if (valueType.CanAcceptToken(token)) { tokenAccepted = true; Expression expr = valueType.CreateInstance(token); while (unresolved.Count > 0) { OperatorExpression oper = unresolved.Peek(); if (oper.AddOperand(expr)) { unresolved.Pop(); expr = oper; } else { expr = null; break; } } if (expr != null) { result = expr; } break; } } if (!tokenAccepted) { return null; } } } return result; } public abstract int Evaluate(); } abstract class ValueExpression : Expression { public abstract int Value { get; } public sealed override int Evaluate() { return Value; } } sealed class ConstantExpression : ValueExpression { private int value; private ConstantExpression(int value) { this.value = value; } public override int Value { get { return this.value; } } public static IValueExpressionType ExpressionType { get { return Factory.Instance; } } private class Factory : IValueExpressionType { public static readonly Factory Instance = new Factory(); // We typically expect a CreateInstance method call immediately after a CanAcceptToken method call. // To speed up such a scenario we cache parsed value of the token passed to previous CanAcceptToken method call. private string lastToken = null; private int lastTokenValue; private bool lastTokenValid = false; private Factory() { } public bool CanAcceptToken(string token) { lastToken = token; return (lastTokenValid = int.TryParse(token, out lastTokenValue)); } public ValueExpression CreateInstance(string token) { // Token caching is a speed optimization, so we want the following check to have as little overhead as possible. // No need to compare the two strings, as ReferenceEquals is sufficient in this case. if (!object.ReferenceEquals(token, lastToken)) { CanAcceptToken(token); } if (!lastTokenValid) { return null; } return new ConstantExpression(lastTokenValue); } } } abstract class OperatorExpression : Expression { public abstract bool AddOperand(Expression op); protected class Factory : IOperatorExpressionType where T : OperatorExpression, new() { public static readonly Factory Instance = new Factory(); private Factory() { } public string OperatorToken { get; // Implements getter of IOperatorExpressionType.OperatorToken read-only property. set; // Setter is Factory class specific and is not part of the IOperatorExpressionType interface. } public OperatorExpression CreateInstance() { return new T(); } } } abstract class UnaryExpression : OperatorExpression { protected Expression op; public Expression Op { get { return op; } set { op = value; } } public override bool AddOperand(Expression op) { if (this.op == null) { this.op = op; } return true; } public sealed override int Evaluate() { return Evaluate(op.Evaluate()); } protected abstract int Evaluate(int opValue); } abstract class BinaryExpression : OperatorExpression { protected Expression op0, op1; public Expression Op0 { get { return op0; } set { op0 = value; } } public Expression Op1 { get { return op1; } set { op1 = value; } } public override bool AddOperand(Expression op) { if (op0 == null) { op0 = op; return false; } else if (op1 == null) { op1 = op; } return true; } public sealed override int Evaluate() { return Evaluate(op0.Evaluate(), op1.Evaluate()); } protected abstract int Evaluate(int op0Value, int op1Value); } sealed class PlusExpression : BinaryExpression { protected override int Evaluate(int op0Value, int op1Value) { return checked(op0Value + op1Value); } static PlusExpression() { Factory.Instance.OperatorToken = "+"; } public static IOperatorExpressionType ExpressionType { get { return Factory.Instance; } } } sealed class MinusExpression : BinaryExpression { protected override int Evaluate(int op0Value, int op1Value) { return checked(op0Value - op1Value); } static MinusExpression() { Factory.Instance.OperatorToken = "-"; } public static IOperatorExpressionType ExpressionType { get { return Factory.Instance; } } } sealed class MultiplyExpression : BinaryExpression { protected override int Evaluate(int op0Value, int op1Value) { return checked(op0Value * op1Value); } static MultiplyExpression() { Factory.Instance.OperatorToken = "*"; } public static IOperatorExpressionType ExpressionType { get { return Factory.Instance; } } } sealed class DivideExpression : BinaryExpression { protected override int Evaluate(int op0Value, int op1Value) { return (op0Value / op1Value); } static DivideExpression() { Factory.Instance.OperatorToken = "/"; } public static IOperatorExpressionType ExpressionType { get { return Factory.Instance; } } } sealed class UnaryMinusExpression : UnaryExpression { protected override int Evaluate(int opValue) { return checked(-opValue); } static UnaryMinusExpression() { Factory.Instance.OperatorToken = "~"; } public static IOperatorExpressionType ExpressionType { get { return Factory.Instance; } } } class Program { static void Main(string[] args) { Expression expr = Expression.ParsePrefixExpression(Console.ReadLine()); if (expr == null) { Console.WriteLine("Format Error"); return; } try { Console.WriteLine(expr.Evaluate().ToString()); } catch (DivideByZeroException) { Console.WriteLine("Divide Error"); } catch (OverflowException) { Console.WriteLine("Overflow Error"); } } } }