Click here to Skip to main content
15,878,959 members
Articles / Programming Languages / C#

Math Parther Engine

Rate me:
Please Sign up or sign in to vote.
1.15/5 (9 votes)
30 Jul 2004 33.9K   443   6  
A parser that understand the mathematical equations.Just enter the equation and you will get the result
//Copyright (C) 2004  <Mohammed Azmy> moh286@yahoo.com
/* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 */
using System;

namespace ParserEngine
{
	/// <summary>
	/// this is a standalone class that has a static method allow the programmer to 
	/// send a string represent a mathematical expression and get the answer
	/// This is my first program in my entire life ,so I think it will be foll of mistakes
	/// but at least it work.
	/// this class written by MOHAMMED AZMY - Egypt please do not remove this name
	/// and I allow you to use this class in any way, editing or using in any program
	/// 
	/// You can send to it an equation like this
	/// NOTE: IT SOLVE THE EQUATION IN RADIAN.
	/// 2+3*4/(5*sin3)+(3*4.54)^2-ln(log3)/10E2-e4+3&8
	/// </summary>
	public class Parser
	{
		public static double calculate(string equationtext,ref bool error)
		{
			
			/*
			 * this method will writ the equation in the correct syntax
			 * which is (any thing+0) to avoid some exception...
			 * This method will also fix some syntax errors
			 * like Exponent sign, some logical operation like (2+3)(3+4)
			 * (suppose to be (2+3)*(3+4) & 2(1+2)--> 2*(1+2)
			 * and so on...
			 */
			error=false;
			string correctsyntax=equationtext+"+0";
			parserstring word=new parserstring(correctsyntax);
			/*
			 * this next loop will search foe exponant like 2E2
			 * it will insert + sign to be 2E+2
			 * if 2E-2 it will not do any thing
			 * this is not so important but it is the only way to
			 * solve the expetion coused by entering 2*2E2
			 */
			//this next line related to (-whatever)^2...... go to there.
			//if (word.wordarray[0].ToString()=="(")word=word.insert("0+",0);
			for (int loop=1;loop<word.length-1;loop++)
			{
				string what=word.wordarray[loop].ToString();
				string whatfor=word.wordarray[loop-1].ToString();
				string whataf=word.wordarray[loop+1].ToString();
				if (what=="E")
				{
					if (what!="-")
					{
						word=word.insert("+",loop+1);
					}
				}
				if (what=="("&&whatfor==")")
				{
					word=word.insert("*",loop);
				}
				if (what=="("&&whatfor==".")word=word.insert("*",loop);
				if (what=="(")
				{

					try
					{
						double whatbefore=double.Parse(whatfor);
						word=word.insert("*",loop);
					}
					catch
					{

					}
				}
				if (what==")")
					try
					{
						double whatafter=double.Parse(whataf);
						word=word.insert("*",loop+1);
					}
					catch
					{

					}
				if (what==")"&&whataf==".")word=word.insert("*",loop+1);
				
			}
			try
			{
				return bracket(word);
			}
			catch
			{
				error=true;
				return 0;
			}
		}
		private static double bracket(parserstring word)
		{
			bool dumy=false;
			int start=0;
			string what;
			double result=0;
			string tocalculate;
			string xwhat;
			//int nextpowerindex;
			for (int loop=0;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;
				what=word.wordarray[loop].ToString();
				if (what=="(")start=loop;
				if (what==")")
				{
					tocalculate=word.copy(start+1,loop);
					
					result=calculate(tocalculate,ref dumy);
					if (word.wordarray[loop+1].ToString()=="^")
					{
						for (int xloop=loop+3;loop<word.length;xloop++)
						{
							if (word.wordarray[xloop].ToString()=="E")xloop+=2;
							xwhat=word.wordarray[xloop].ToString();
							if (xwhat=="+"||xwhat=="-"||xwhat=="*"||xwhat=="/"||xwhat=="^")
							{
								string powerpart=word.copy(loop+1,xloop);
								result=compiler(new parserstring(result.ToString()+powerpart));
								word=word.replace("("+result.ToString()+")",start,xloop);
								break;
							}
						}
					}
					else
					{
						word=word.replace(result.ToString(),start,loop+1);
					}
					return bracket(word);
				}
			}
			return advancedfn(word);
			//return calculate(word.ParseToString(word));
		}
		private static double advancedfn(parserstring word)
		{
			/*
			 * this method will solve the advanced fn
			 * sin cos tan Asin Acos Atan sinh cosh tanh log & ln
			 */
			string ch_2;
			string ch_3;
			string ch_4;
			int nextop=0;
			string tocalculate;
			double result=0;
			string what;
			for (int loop=0;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;

				//replacing the constant e
				if (word.wordarray[loop].ToString()=="e")
				{
					if (word.wordarray[loop+1].ToString()=="*"||word.wordarray[loop+1].ToString()=="/"||word.wordarray[loop+1].ToString()=="^"||word.wordarray[loop+1].ToString()=="&")
					{
						word=word.replace(Math.E.ToString(),loop,loop+1);
					}
					else
					{
						word=word.replace(Math.E.ToString()+"^",loop,loop+1);
					}
					return advancedfn(word);
				}
				//solving factorial
				if (word.wordarray[loop].ToString()=="!")
				{
					for (int xloop=loop;xloop>=0;xloop--)
					{
						
						what=word.wordarray[xloop].ToString();
						if (what=="+"||what=="-"||what=="*"||what=="/"||what=="^"||what=="&")
						{
							nextop=xloop;
							
							break;
						}
						if (xloop==0)
						{
							nextop=xloop-1;
						}
						

					}
					tocalculate=word.copy(nextop+1,loop);
					result=Fact(int.Parse(tocalculate));
					word=word.replace(result.ToString(),nextop+1,loop+1);
					
					return advancedfn(word);
				}
				//preparing to solve the fn.
				if(loop>=word.length-3)break;
				ch_2=word.wordarray[loop].ToString()+word.wordarray[loop+1].ToString();
				ch_3=ch_2+word.wordarray[loop+2].ToString();
				ch_4=ch_3+word.wordarray[loop+3].ToString();
				
				//replacing the constant pi
				if (ch_2=="pi")
				{
					word=word.replace(Math.PI.ToString(),loop,loop+2);
					return advancedfn(word);
				}
				//checking for ln
				if (ch_2=="ln")
				{
					for (int xloop=loop+3;xloop<word.length;xloop++)
					{
						what=word.wordarray[xloop].ToString();
						if (what=="+"||what=="-"||what=="*"||what=="/"||what=="^"||what=="&")
						{
							nextop=xloop;
							
							break;
						}
					}
					tocalculate=word.copy(loop+2,nextop);
					result=Math.Log(double.Parse(tocalculate),Math.E);
					word=word.replace(result.ToString(),loop,nextop);
					ch_2="";
					return advancedfn(word);
				}
				//checking for "Asin ,Acos ,Atan ,sinh ,cosh ,tanh "
				if (ch_4=="Asin"||ch_4=="Acos"||ch_4=="Atan"||ch_4=="sinh"||ch_4=="cosh"||ch_4=="tanh")
				{
					for (int xloop=loop+5;xloop<word.length;xloop++)
					{
						what=word.wordarray[xloop].ToString();
						if (what=="+"||what=="-"||what=="*"||what=="/"||what=="^"||what=="&")
						{
							nextop=xloop;
							
							break;
						}
					}
					tocalculate=word.copy(loop+4,nextop);
					//tocalculate=(advancedfn(new parserstring(tocalculate))).ToString();
					switch (ch_4)
					{
						case "Asin":
							result=Math.Asin(double.Parse(tocalculate));
							break;
						case "Acos":
							result=Math.Acos(double.Parse(tocalculate));
							break;
						case "Atan":
							result=Math.Atan(double.Parse(tocalculate));
							break;
						case "sinh":
							result=Math.Sinh(double.Parse(tocalculate));
							break;
						case "cosh":
							result=Math.Cosh(double.Parse(tocalculate));
							break;
						case "tanh":
							result=Math.Tanh(double.Parse(tocalculate));
							break;
					}
					word=word.replace(result.ToString(),loop,nextop);
					ch_4="";
					return advancedfn(word);
				}
				//checking for "log , sin ,cos ,tan"
				if (ch_3=="log"||ch_3=="sin"||ch_3=="cos"||ch_3=="tan")
				{
					for (int xloop=loop+4;xloop<word.length;xloop++)
					{
						what=word.wordarray[xloop].ToString();
						if (what=="+"||what=="-"||what=="*"||what=="/"||what=="^"||what=="&")
						{
							nextop=xloop;
							
							break;
						}
					}
					tocalculate=word.copy(loop+3,nextop);
					//tocalculate=(advancedfn(new parserstring(tocalculate))).ToString();
					switch (ch_3)
					{
						case "log":
							result=Math.Log(double.Parse(tocalculate),10);
							break;
						case "sin":
							result=Math.Sin(double.Parse(tocalculate));
							break;
						case "cos":
							result=Math.Cos(double.Parse(tocalculate));
							break;
						case "tan":
							result=Math.Tan(double.Parse(tocalculate));
							break;		
					}
					word=word.replace(result.ToString(),loop,nextop);
					ch_3="";
					return advancedfn(word);
				}


			}
			return power(word);
		}
		private static double power(parserstring word)
		{
			/*
			 * this method solve the power
			 * like 2^3 or 2√4 i.e sqrt(4) or any other root like
			 * 3√8 (the 3rd root of 8)
			 * 
			 */
			int lastindex=-1;
			//int powerindex;
			bool poweron=false;
			string what;
			
			for (int loop=0;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;
				what=word.wordarray[loop].ToString();
				if (what=="+"||what=="-"||what=="*"||what=="/"||what=="^"||what=="&")
				{
					
					
					if (poweron==true)
					{

						/*if (word.wordarray[lastindex-1].ToString()=="+"||word.wordarray[lastindex-1].ToString()=="-"||
							word.wordarray[lastindex-1].ToString()=="*"||word.wordarray[lastindex-1].ToString()=="/")lastindex--;
						*/	
						string tocompiler=word.copy(lastindex+1,loop);
						double back=(compiler(new parserstring(tocompiler)));

						word=word.replace(back.ToString(),lastindex+1,loop);
						return power(word);
					}
					else
					{
						if(what!="^"&&what!="&")lastindex=loop;
						/*if (lastindex!=0)
						{
							if (what=="-"&&(word.wordarray[loop-1].ToString()=="+"||word.wordarray[loop-1].ToString()=="-"||word.wordarray[loop-1].ToString()=="*"||word.wordarray[loop-1].ToString()=="/"))lastindex--;
						}*/
					}
					
				}
				if (what=="^"||what=="&")
				{
					poweron=true;
					if (word.wordarray[loop+1].ToString()=="+"||word.wordarray[loop+1].ToString()=="-")
					{
						loop+=2;
					}

					//powerindex=loop;
				}

			}
			return calculator(word);
		}

		private static double calculator(parserstring word)
		{
			

			/*
			 * Finally it works.
			 * I donn't know how to describe how this method work.
			 * 
			 */
			bool multon=false;
			int firstsumpoint=-1;
			for (int loop=1;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;
				if (word.wordarray[loop].ToString()=="*" || word.wordarray[loop].ToString()=="/")
				{
					// I think this can be improved...........HERE
					
					multon=true;
					//loop++;
					if (word.wordarray[loop+1].ToString()=="+" || word.wordarray[loop+1].ToString()=="-")
					{
						loop+=2;
					}
					else
					{
						loop++;
					}
					
				}
				
				if ((word.wordarray[loop].ToString()=="+" || word.wordarray[loop].ToString()=="-")&& multon==true)
				{
					string tomultiplier=word.copy(firstsumpoint+1,loop);
					string multres=(multiplier(new parserstring(tomultiplier))).ToString();
					word=word.replace(multres,firstsumpoint+1,loop);
					return calculator(word);
					
					
				}
				if ((word.wordarray[loop].ToString()=="+" || word.wordarray[loop].ToString()=="-")&& multon==false)
				{
					firstsumpoint=loop;

				}
				
			}
			return adder(word);

		}
		private static double multiplier(parserstring word)
		{
			/*
			 * this method receive an word contain alot af mult. or division
			 * values like 5*6/3*2 and return the result as a double
			 */
			bool multon=false;
			for (int loop=1;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;
				if (word.wordarray[loop].ToString()=="*" ||word.wordarray[loop].ToString()=="/")
				{
					if (multon==true)
					{
						string tocompile=word.copy(0,loop);
						string compilerRes=(compiler(new parserstring(tocompile))).ToString();
						word=word.replace(compilerRes,0,loop);
						multon=false;
						return multiplier(word);						
					}
					else
					{
						multon=true;
						loop++;
						/*
						 * I make loop+=1 to solve the exception coused by typing
						 * *- or /+ like 1*-3 this will equal -2;
						 */
					}
				}


			}
			return compiler(word);

		}
		private static double adder(parserstring word)
		{
			/*
			 * this method receive an word contain alot af added or subtracted
			 * values like 5+2+-3-6 and return the res as a double
			 */
			bool sumon=false;
			for (int loop=1;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;
				if (word.wordarray[loop].ToString()=="+" ||word.wordarray[loop].ToString()=="-")
				{
					if (sumon==true)
					{
						string tocompile=word.copy(0,loop);
						string compilerRes=(compiler(new parserstring(tocompile))).ToString();
						word=word.replace(compilerRes,0,loop);
						sumon=false;
						return adder(word);						
					}
					else
					{
						sumon=true;
						loop++;
						/*
						 * I make loop+=1 to solve the exception coused by typing
						 * +- or -+ like 1+-3 this will equal -2;
						 */
					}
				}


			}
			return compiler(word);
			/*if (sumon==true)
			{
				return compiler(word);
			}
			else
			{
				return double.Parse(word.copy(0,word.length));			
			}*/
		}
		private static double compiler(parserstring word)
		{
			/*
			 * this methode execute a simple operation like No1+No2 or N01/No2
			 * and so on. by basing an parserstring array contain this eq.
			 * The loop begains from the second element in the array to avoid
			 * considering the -ve or +ve sign as an operation.
			 */
			string result=word.ParseToString();
			double res=0;
			for (int loop=1;loop<word.length;loop++)
			{
				if (word.wordarray[loop].ToString()=="E")loop+=2;
				
				if (word.wordarray[loop].ToString()=="+" ||word.wordarray[loop].ToString()=="-" ||word.wordarray[loop].ToString()=="*" ||word.wordarray[loop].ToString()=="/"||word.wordarray[loop].ToString()=="^"||word.wordarray[loop].ToString()=="&")
				{
					int index=loop;
					//double result;
					string value1=word.copy(0,loop);
					string value2=word.copy(loop+1,word.length);
					double no1=double.Parse(value1);
					double no2=double.Parse(value2);
					switch (word.wordarray[loop].ToString())
					{
						case "+":
							res=(no1+no2);
							break;
						case "-":
							res=(no1-no2);
							break;
						case "*":
							res=(no1*no2);
							break;
						case "/":
							res=(no1/no2);
							break;
						case "^":
							res=Math.Pow(no1,no2);
							break;
						case "&":
							res=Math.Pow(no2,1/no1);
							break;
					}
					break;					
				}
			}
			
			return res;
			/*if (res!=0)
			{
				return res;
			}
			else
			{
				return double.Parse(result);
			}*/
		}
		private static int Fact(int x)
		{
			if (x==0) return 1;
			else return x*Fact(x-1);
		}
	}
	class parserstring
	{
		/*
		 * this class contain an array of characters treated as a string
		 * and some methods that do some functions over it like removing
		 * and replacing and inserting
		 * the constuctor puts an string into the array
		 * 
		 */
		public char[] wordarray;
		public int length=0;
		public parserstring(string word)
		{
						
			this.length=word.Length;
			wordarray=new char[length];
			wordarray=word.ToCharArray(0,length);


		}
		public string copy(/*from starting with zero*/int start,/*to*/int end)
		{
			/*
			 * this static method copy a piece of the parserstring array to an string
			 */
			string copyed="";
			for (int loop=start;loop<end;loop++)
			{
				copyed=copyed+wordarray[loop];
			}
			return copyed;
		}
		public parserstring insert(string whattoinsert,int at)
		{
			/*
			 * this method insert a string at an specific index(before it)
			 */
			string resultstring=copy(0,at);
			resultstring+=whattoinsert+copy(at,this.length);
			return new parserstring(resultstring);
		}
		public parserstring replace(string whattoinsert,int from,int to)
		{
			/*
			 * this method replace a No. of characters in the array with a string
			 * from an specified index to another
			 * 
			 */
			string resultstring=copy(0,from);
			resultstring+=whattoinsert+copy(to,this.length);
			return new parserstring(resultstring);
		}
		public string ParseToString()
		{
			string back="";
			foreach (char i in wordarray)
			{
				back+=i.ToString();
			}
			return back;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Egypt Egypt
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions