I'm writing a function parser, which (hopefully) will be able to handle much more complex problems than basic operations. I've just completed the handling of the addition, subtraction, and brackets, but am at a loss of how to implement proper order of operations for multiplication and division. In order to make them work correctly, they must first be put in brackets. ie 2 + 4 * 3 outputs 18 instead of 14, but 2 + (4 * 3) outputs 14.

I've thought of just adding brackets to the function to force order of operations, but that seems more like a band-aid than an actual fix. Heres the code:

Header:

#pragma once
#pragma warning(disable: 4018)
#include <iostream>
#include <string.h>
using namespace std;

class CFunction
{
protected:
	string _sFunc;
	int    _iCursor;
	int GetNextValue(int &);
	char GetNextOp(int &);
	string ToCloseBracket(int &);
public:
	bool SetFunc(string);
	int Solve(char = 0);
	//inline ctor
                CFunction(string s): _iCursor(0)
	{
		int iO(0),iC(0);
		for (int i(0); i < strlen(s.c_str()); ++i)
		{
			if (s[i] == '(')
				iO++;
			else if (s[i] == ')')
				iC++;
		}
		if (iO != iC)
			throw exception ("Bracket Error");
		_sFunc = s;
	}
	~CFunction(void);
};

class cpp file:

#include "Function.h"


CFunction::~CFunction(void)
{
}

int CFunction::GetNextValue(int & i)
{
	string sBuffer;
	char szFormula[255];
	strcpy_s(szFormula, 255, _sFunc.c_str());
	bool numStream(false);
	for (i = i; i < strlen(szFormula); ++i)
    {
       if (isdigit(szFormula[i]))
       {
		   //add the digit to the buffer
            numStream = true;
			sBuffer += szFormula[i];
       }
	   if (numStream && (!isdigit(szFormula[i]) || i == strlen(szFormula) - 1))
	   {
		   return atoi(sBuffer.c_str()); //return the buffer, converted to int
	   }
	   if (szFormula[i] == '(')
	   {//solve what's inside brackets first!
		   string tmp(ToCloseBracket(i));
		   return CFunction(tmp).Solve();
	   }
	}
	//error flag
	return -1;
}

string CFunction::ToCloseBracket(int & iIndex)
{
	string sBuffer = "";
	int iCount(0), iCount2(0);
	int iOIndex(iIndex), iCIndex(iIndex + 1);
	for (iCIndex; iCIndex < strlen(_sFunc.c_str()); ++iCIndex)
	{
		if (_sFunc[iCIndex] == '(')
			iCount++;
		if	(_sFunc[iCIndex] == ')' && iCount == 0)
			break;
		if (_sFunc[iCIndex] == ')')
			iCount--;
	}
	for (iIndex++; iIndex < iCIndex; iIndex++)
			sBuffer += _sFunc[iIndex];
	return sBuffer;
} 

int CFunction::Solve(char var)
{
	if (strlen(_sFunc.c_str()) < 1)
		throw exception ("Invalid Function");
	int i(0),
		iTmpVal(0),
		iReturn(0);
	char op(0);
	iReturn = GetNextValue(i); 
	while (i < strlen(_sFunc.c_str()) - 1)
	{
		op = GetNextOp(i);
		iTmpVal = GetNextValue(i);
		switch (op)
		{
		case '+': iReturn += iTmpVal; break;
		case '-': iReturn -= iTmpVal; break;
		case '*': iReturn *= iTmpVal; break;
		case '/': if (iTmpVal != 0) iReturn /= iTmpVal; else throw exception("Division By Zero"); break;
		default: break;
		}
	}
	return iReturn;
}

char CFunction::GetNextOp(int & i)
{
	for (i; i < strlen(_sFunc.c_str()); ++i)
       if (_sFunc[i] == '+' || _sFunc[i] == '-' || _sFunc[i] == '*' || _sFunc[i] == '/')
		   return _sFunc[i];
	//error flag
	return -1;
}

Sample implementation in main()

#include <string>
#include <iostream>
using namespace std;
#include "Function.h"

int main()
{
	char szBuffer[255];
	string sBuffer = "";
	for (int i(0); i < 5; ++i)
	{
		cin.ignore(cin.rdbuf()->in_avail());
		cout << "Enter formula: ";
		cin.getline(szBuffer, 254);
		sBuffer = szBuffer;
		CFunction myFunc(sBuffer);
		int ii(0);
		try
		{
			if ((ii = myFunc.Solve()) == -1)
				throw exception("Unknown Error");
			cout << sBuffer << " = " << ii;
		}
		catch (exception exc)
		{
			cout << "Error Encountered while solving for " << sBuffer;
			cout << "\nType: " << exc.what();
		}
		cin.get();
	}
	return 0;
}

Any pointers in the right direction would be greatly appreciated!

Recommended Answers

All 9 Replies

Have you ever search INET for arithmetic expressions parsing&evaluation?
Try that, there are lots of info and codes on this old good topic...

Have you ever search INET for arithmetic expressions parsing&evaluation?
Try that, there are lots of info and codes on this old good topic...

Hmm well from what a google search turned up, I got a bunch of libraries and dlls that will do parsing for me, but I want to write the actual parser! Not many of them seem to be open source, but I'll keep looking. thanks. Perhaps post a more direct link, since a lot of companies/websites seem to have the word INET in it :P .

Also try to read and understand a recursive descent parser : http://en.wikipedia.org/wiki/Recursive_descent_parser

Yikes. I'm not afraid of C but that program is a bit beyond me. Although I think I'm on the right track, in that I'm recursively solving the brackets until the most simplified possible expression can be solved by basic operations. Correct me if I'm wrong, but I think this could be considered a recursive descending parser. Thanks for the link btw.

Hey Skatamatic, Right now I'm into C# for that matter and I have been in BASIC, Pascal,Modula-2,C,C++. So the language is not that much of an issue.
Look at this compilercode from a master :
http://www.246.dk/pl0.html
For the moment I am trying to translate in C# the code for the calculator in Bjarne Stroustrup's book: "The C++ PROGRAMMING LANGUAGE"
Maybe we can exchange codes?

commented: Helpful guy! +3

Hey Skatamatic, Right now I'm into C# for that matter and I have been in BASIC, Pascal,Modula-2,C,C++. So the language is not that much of an issue.
Look at this compilercode from a master :
http://www.246.dk/pl0.html

That, again, is quite the code! I'm not too sure of the language, I'm only really fluent with C++, SQL, basic assembly, and QBasic, but it's still somewhat readable. I'm not too sure of it's functionality though; this looks like a complete compiler, yet I can't seem to find where it converts its data into opcodes/assembly language. I'll keep trying to make some sense of it! Thanks.

Hey Skatamatic, Right now I'm into C# for that matter and I have been in BASIC, Pascal,Modula-2,C,C++. So the language is not that much of an issue.
Look at this compilercode from a master :
http://www.246.dk/pl0.html
For the moment I am trying to translate in C# the code for the calculator in Bjarne Stroustrup's book: "The C++ PROGRAMMING LANGUAGE"
Maybe we can exchange codes?

Sounds good. Is there a link to this calculator's specifications?

Hmm well from what a google search turned up, I got a bunch of libraries and dlls that will do parsing for me, but I want to write the actual parser! Not many of them seem to be open source, but I'll keep looking. thanks. Perhaps post a more direct link, since a lot of companies/websites seem to have the word INET in it :P .

That's not the point to get "a buch of libraries and dlls that will do parsing for me" (all dlls are libraries too ;) ) though open source parsing codes are excellent text-books and primers per se. There lots of text-books and articles on this topic too.

Don't search word INET: INET means Internet, that's all. If you want direct links - for example, download compact and well-written book "Parsing Techniques - A Practical Guide" from http://www.cs.vu.nl/~dick/PTAPG.html.

Don't invent square wheels...

That's not the point to get "a buch of libraries and dlls that will do parsing for me" (all dlls are libraries too ;) ) though open source parsing codes are excellent text-books and primers per se. There lots of text-books and articles on this topic too.

Don't search word INET: INET means Internet, that's all. If you want direct links - for example, download compact and well-written book "Parsing Techniques - A Practical Guide" from http://www.cs.vu.nl/~dick/PTAPG.html.

Don't invent square wheels...

Lol. I feel like an idiot (inet :P). And there's nothing wrong with reinventing square wheels if it further helps me understand parsing techniques!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.