Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

//This is a C# question and I am super stuck on this, please any help with explenation would be highly appreciated...THANK YOU!! using System; using

//This is a C# question and I am super stuck on this, please any help with explenation would be highly appreciated...THANK YOU!!

using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions;

namespace Formulas { ///

/// Represents formulas written in standard infix notation using standard precedence /// rules. Provides a means to evaluate Formulas. Formulas can be composed of /// non-negative floating-point numbers, variables, left and right parentheses, and /// the four binary operator symbols +, -, *, and /. (The unary operators + and - /// are not allowed.) ///

public class Formula {

private bool lpPattern;

///

/// Creates a Formula from a string that consists of a standard infix expression composed /// from non-negative floating-point numbers (using C#-like syntax for double/int literals), /// variable symbols (a letter followed by zero or more letters and/or digits), left and right /// parentheses, and the four binary operator symbols +, -, *, and /. White space is /// permitted between tokens, but is not required. /// /// Examples of a valid parameter to this constructor are: /// "2.5e9 + x5 / 17" /// "(5 * 2) + 8" /// "x*y-2+35/9" /// /// Examples of invalid parameters are: /// "_" /// "-5.3" /// "2 5 + 3" /// /// If the formula is syntacticaly invalid, throws a FormulaFormatException with an /// explanatory Message. ///

public Formula(String formula) { //converts formula string to lowercase. formula = formula.ToLower(); //makes a stack to hold values and operators Stack valStack = new Stack(); Stack OpeStack = new Stack();

//The sequence "\\" matches "\" and "\(" matches "(". //tokenizing and splitting it //string[] token = Regex.Split(formula, "(\\()|(\\))|(-)|(\\+)|(\\*)|(/)");

// starts to store tokens according to GetTokens string[] token = GetTokens(formula).ToArray();

//first check to see if its empty or not valid if (token == null || token.Length == 0) { throw new FormulaFormatException("Not valid"); } if (IsOperator(token[0])) { if (!"(".Equals(token[0])) { //Starting w/ invalid token throw new FormulaFormatException("Only operator formula may start with is '('"); } } foreach (String token in tokens) { int value; if (" ".Equals(token) || "".Equals(token)) { continue; //ignore blank space } if (IsNumeric(token, out value)) { if (OpeStack.Count != 0 && ("*".Equals(OpeStack.Peek()) || "/".Equals(OpeStack.Peek()))) { //multiplication or division, time to evaluate and push result valStack.Push(PerformEvaluation(valStack.Pop(), value, OpeStack.Pop())); } else { //Just a value, no division or mult, just push to stack valStack.Push(value); } }

}

bool IsOperator(string tokenn) { return "*".Equals(tokenn) || "+".Equals(tokenn) || "-".Equals(tokenn) || "/".Equals(tokenn) || "(".Equals(tokenn) || ")".Equals(tokenn); }

bool IsNumeric(String tokenz, out int value) { value = 0; return int.TryParse(tokenz, out value); } else if (IsOperator(token)) { if (")".Equals(token)) { //closing parens, we need to evaluate inner

//Must contain at least two values on the stack or the closing paren is invalid if (valStack.Count < 2) { //throw new ArgumentException("Invalid formula, not enough values inside the parentheses."); }

//get the previous value int prevValue = valStack.Pop(); //now get the previous operator String prevOperator = OpeStack.Pop(); while (!"(".Equals(prevOperator)) {

//need to have a value on the stack to perform another operation if (valStack.Count == 0) { throw new ArgumentException("Invalid formula, expected a left value inside the parens, but none was found."); } int leftValue = valStack.Pop(); prevValue = PerformEvaluation(leftValue, prevValue, prevOperator);

//no previous operators and we didn't find the '(' formula is invalid if (OpeStack.Count == 0) { throw new ArgumentException("Invalid formula, expected a '(' with the ')' but wasn't found"); }

//get the next previous operator and do again. prevOperator = OpeStack.Pop(); } //found the opening parens, we are done, let's just push the value to the stack // we discard the parens here since we are done with evaluation. valueStack.Push(prevValue);

//one last check if * or / on stack we need to perform this now if (OpeStack.Count != 0 && ("*".Equals(OpeStack.Peek()) || "/".Equals(OpeStack.Peek()))) { if (valStack.Count < 2) { throw new ArgumentException("Invalid formula, unable to perform operation, as 2 values are not on the stack."); } int right = valStack.Pop(); int left = valStack.Pop(); valStack.Push(PerformEvaluation(left, right, OpeStack.Pop())); } } else if ("+".Equals(token) || "-".Equals(token)) { if (OpeStack.Count != 0 && ("+".Equals(OpeStack.Peek()) || "-".Equals(OpeStack.Peek()))) { //we got a + or - and already have a + or - on the stack. Evaluate now if (valStack.Count < 2) { throw new ArgumentException("Invalid formula, attempted to perform operation and not enough values on stack"); } int right = valStack.Pop(); int left = valStack.Pop(); valStack.Push(PerformEvaluation(left, right, OpeStack.Pop()));

} OpeStack.Push(token); } else { OpeStack.Push(token); } } else { //must be a variable - delegate should throw exception if not found int lookedUpValue = variableLookup(token.Trim()); if (OpeStack.Count != 0 && ("*".Equals(OpeStack.Peek()) || "/".Equals(OpeStack.Peek()))) { //multiplication or division, time to evaluate and push result if (valStack.Count == 0) { throw new ArgumentException("Invalid formula, expected another value for evaluation and none was found"); }

valStack.Push(PerformEvaluation(valStack.Pop(), lookedUpValue, OpeStack.Pop())); } else { //Just a value, no division or mult, just push to stack valStack.Push(lookedUpValue); } }

if (OpeStack.Count == 0) { if (valStack.Count != 1) { throw new ArgumentException("Invalid formula, invalid value count left at end of operation"); } return valStack.Pop(); } else { if (valStack.Count != 2 && OpeStack.Count != 1) { throw new ArgumentException("Invalid formula, too many operators and/or values left at end of Evaluation"); } int right = valStack.Pop(); int left = valStack.Pop(); //perform final evaluation return PerformEvaluation(left, right, OpeStack.Pop()); } } } } ///

/// Evaluates this Formula, using the Lookup delegate to determine the values of variables. (The /// delegate takes a variable name as a parameter and returns its value (if it has one) or throws /// an UndefinedVariableException (otherwise). Uses the standard precedence rules when doing the evaluation. /// /// If no undefined variables or divisions by zero are encountered when evaluating /// this Formula, its value is returned. Otherwise, throws a FormulaEvaluationException /// with an explanatory Message. /// public double Evaluate(Lookup lookup) { return 0; }

///

/// Given a formula, enumerates the tokens that compose it. Tokens are left paren, /// right paren, one of the four operator symbols, a string consisting of a letter followed by /// zero or more digits and/or letters, a double literal, and anything that doesn't /// match one of those patterns. There are no empty tokens, and no token contains white space. /// private static IEnumerable GetTokens(String formula) { // Patterns for individual tokens. // NOTE: These patterns are designed to be used to create a pattern to split a string into tokens. // For example, the opPattern will match any string that contains an operator symbol, such as // "abc+def". If you want to use one of these patterns to match an entire string (e.g., make it so // the opPattern will match "+" but not "abc+def", you need to add ^ to the beginning of the pattern // and $ to the end (e.g., opPattern would need to be @"^[\+\-*/]$".) String lpPattern = @"\("; String rpPattern = @"\)"; String opPattern = @"[\+\-*/]"; String varPattern = @"[a-zA-Z][0-9a-zA-Z]*";

// PLEASE NOTE: I have added white space to this regex to make it more readable. // When the regex is used, it is necessary to include a parameter that says // embedded white space should be ignored. See below for an example of this. String doublePattern = @"(?: \d+\.\d* | \d*\.\d+ | \d+ ) (?: e[\+-]?\d+)?"; String spacePattern = @"\s+";

// Overall pattern. It contains embedded white space that must be ignored when // it is used. See below for an example of this. This pattern is useful for // splitting a string into tokens. String splittingPattern = String.Format("({0}) | ({1}) | ({2}) | ({3}) | ({4}) | ({5})", lpPattern, rpPattern, opPattern, varPattern, doublePattern, spacePattern);

// Enumerate matching tokens that don't consist solely of white space. // PLEASE NOTE: Notice the second parameter to Split, which says to ignore embedded white space /// in the pattern. foreach (String s in Regex.Split(formula, splittingPattern, RegexOptions.IgnorePatternWhitespace)) { if (!Regex.IsMatch(s, @"^\s*$", RegexOptions.Singleline)) { yield return s; } } } }

///

/// A Lookup method is one that maps some strings to double values. Given a string, /// such a function can either return a double (meaning that the string maps to the /// double) or throw an UndefinedVariableException (meaning that the string is unmapped /// to a value. Exactly how a Lookup method decides which strings map to doubles and which /// don't is up to the implementation of the method. /// public delegate double Lookup(string var);

///

/// Used to report that a Lookup delegate is unable to determine the value /// of a variable. /// [Serializable] public class UndefinedVariableException : Exception { /// /// Constructs an UndefinedVariableException containing whose message is the /// undefined variable. /// /// public UndefinedVariableException(String variable) : base(variable) { } }

///

/// Used to report syntactic errors in the parameter to the Formula constructor. /// [Serializable] public class FormulaFormatException : Exception { /// /// Constructs a FormulaFormatException containing the explanatory message. /// public FormulaFormatException(String message) : base(message) { } }

///

/// Used to report errors that occur when evaluating a Formula. /// [Serializable] public class FormulaEvaluationException : Exception { /// /// Constructs a FormulaEvaluationException containing the explanatory message. /// public FormulaEvaluationException(String message) : base(message) { } }

sing System;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Formulas;

namespace FormulaTestCases

{

///

/// These test cases are in no sense comprehensive! They are intended to show you how

/// client code can make use of the Formula class, and to show you how to create your

/// own (which we strongly recommend). To run them, pull down the Test menu and do

/// Run > All Tests.

///

[TestClass]

public class UnitTests

{

///

/// This tests that a syntactically incorrect parameter to Formula results

/// in a FormulaFormatException.

///

[TestMethod]

[ExpectedException(typeof(FormulaFormatException))]

public void Construct1()

{

Formula f = new Formula("_");

}

///

/// This is another syntax error

///

[TestMethod]

[ExpectedException(typeof(FormulaFormatException))]

public void Construct2()

{

Formula f = new Formula("2++3");

}

///

/// Another syntax error.

///

[TestMethod]

[ExpectedException(typeof(FormulaFormatException))]

public void Construct3()

{

Formula f = new Formula("2 3");

}

///

/// Makes sure that "2+3" evaluates to 5. Since the Formula

/// contains no variables, the delegate passed in as the

/// parameter doesn't matter. We are passing in one that

/// maps all variables to zero.

///

[TestMethod]

public void Evaluate1()

{

Formula f = new Formula("2+3");

Assert.AreEqual(f.Evaluate(v => 0), 5.0, 1e-6);

}

///

/// The Formula consists of a single variable (x5). The value of

/// the Formula depends on the value of x5, which is determined by

/// the delegate passed to Evaluate. Since this delegate maps all

/// variables to 22.5, the return value should be 22.5.

///

[TestMethod]

public void Evaluate2()

{

Formula f = new Formula("x5");

Assert.AreEqual(f.Evaluate(v => 22.5), 22.5, 1e-6);

}

///

/// Here, the delegate passed to Evaluate always throws a

/// UndefinedVariableException (meaning that no variables have

/// values). The test case checks that the result of

/// evaluating the Formula is a FormulaEvaluationException.

///

[TestMethod]

[ExpectedException(typeof(FormulaEvaluationException))]

public void Evaluate3()

{

Formula f = new Formula("x + y");

f.Evaluate(v => { throw new UndefinedVariableException(v); });

}

///

/// The delegate passed to Evaluate is defined below. We check

/// that evaluating the formula returns in 10.

///

[TestMethod]

public void Evaluate4()

{

Formula f = new Formula("x + y");

Assert.AreEqual(f.Evaluate(Lookup4), 10.0, 1e-6);

}

///

/// This uses one of each kind of token.

///

[TestMethod]

public void Evaluate5 ()

{

Formula f = new Formula("(x + y) * (z / x) * 1.0");

Assert.AreEqual(f.Evaluate(Lookup4), 20.0, 1e-6);

}

///

/// A Lookup method that maps x to 4.0, y to 6.0, and z to 8.0.

/// All other variables result in an UndefinedVariableException.

///

///

///

public double Lookup4(String v)

{

switch (v)

{

case "x": return 4.0;

case "y": return 6.0;

case "z": return 8.0;

default: throw new UndefinedVariableException(v);

}

}

}

}

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Database 101

Authors: Guy Kawasaki

1st Edition

0938151525, 978-0938151524

More Books

Students also viewed these Databases questions