Calculator parser

I have just started C++ programming and was required to write a program that accepts as input math expressions; parses it to validate the expression and then calculate the value of the math expression. I have the parser figured out which I did by splitting the string into tokens, verifying each token and the checking the syntax of the expression. I am having trouble evaluating the expression. I found a java version which works great but I cannot convert it to C++.Does anyone have suggestions of a easy way to implement this before I post code?

Last edited on
Thank you for your response; before I take a look at it do you know if it evaluates expression that include negative values as well? For example:
(3+2*-4)+1=
Yes, see in function prim:
1
2
case MINUS:		// unary minus
    return -prim(true);
Quick question:

How would I change the input source to that of from a file and the expression assigned to a string. The cin.get and cin.pushback are confusing in the get_token function.
You can create a stringstream
Would this be correct?
function that receives input string -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void calcExpression(string &exp)
{
	 input = new istringstream(exp);		// read argument string
	      
      while (*input)
      {
	  getToken();
	  if (currToken == END) break;
	  if (currToken == PRINT) continue;
	  cout<< expr(false) <<endl;
      }
}
Token_value getToken()
{
      char ch = 0;
      do{ 
		  if(!cin.get(ch)) 
			  return currToken = END; 
	  }		// skip whitespace except '\n'
		while (ch != '\n' && isspace(ch));
      
      switch (ch)
      {
	  case 0 :
	        return currToken=END;
	  case ';' :
	  case '\n' :
	        return currToken = PRINT;
	  case '*' :
	  case '/' :
	  case '+' :
	  case '-' :
	  case '(' :
	  case ')' :
	  case '=' :
	        return currToken = Op(ch);
	  
	  case '0' :	case '1' :	case '2' :	case '3' : 	case '4' :
	  case '5' :	case '6' :	case '7' :	case '8' :	case '9' :
	  case '.' :
	        cin.putback(ch);
	        cin >> num;	        return currToken = NUMBER;
	  default:				// NAME, NAME =, or error
	        if (isalpha(ch))
	        {
		    line = ch;
		    while (cin.get(ch) && isalnum(ch)) cin.putback(ch);
		    cin.putback(ch);
		    return currToken = NAME;
	        }
	        cout<<("Bad Token");
	        return currToken = PRINT;
      }
}




how would i change the cin.get() to work
Replace cin with input.
If you allocate input with new, you should also delete it when you don't need it any more
This is from the link I gave you:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Token_value get_token()
{
	char ch;

	do {	// skip whitespace except '\en'
		if(!input->get(ch)) return curr_tok = END;
	} while (ch!='\n' && isspace(ch));

	switch (ch) {
	case ';':
	case '\n':
		return curr_tok=PRINT;
	case '*':
	case '/':
	case '+':
	case '-':
	case '(':
	case ')':
	case '=':
		return curr_tok=Token_value(ch);
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
	case '.':
		input->putback(ch);
		*input >> number_value;
		return curr_tok=NUMBER;
	default:			// NAME, NAME=, or error
		if (isalpha(ch)) {
			string_value = ch;
			while (input->get(ch) && isalnum(ch))
				string_value += ch;	// string_value.push_back(ch);
							// to work around library bug
			input->putback(ch);
			return curr_tok=NAME;
		}
		error("bad token");
		return curr_tok=PRINT;
	}
}

I have rewritten bjarne stroustrup's calculator program to accept input from a file and parse it and evaluate it. Everything works fine except for the instance where the plus sign acts as a signed value. For example 3*+2.5 equals 7.5 but the program expects a parenthesis. How can I implement the change?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
double expr(bool get)
{
	double left = value(get);
	for(;;)
	switch(currToken)
	{
		case PLUS:
			left += value(true);
			break;
		case MINUS:
			left -= value(true);
			break;
		default:
			return left;
	}
}



Add a case in prim:
1
2
case PLUS:
    return prim(true);
I did try this and it gives an error
error C2196: case value '43' already used

it works in the original code but not in my altered version.
43 is the ascii code for your PLUS.

You can't have two cases which test the same condition.
What do you have in the switch inside prim? Do you have two PLUS cases?
Last edited on
Thanks for the responses, I have managed to resolve the issue. I had the plus case in another method associated with it.
I have another question, can this same program be applied to conditional statements like testing IF statements for example.
Yes, you need to modify it a bit. Here is a theoretical example:
The token is if

   evaluate next expression
   if that is non-zero ( or whatever you want to be true )
      execute next expression
   else
      read next expression and skip that

   if the next token is else
       if the conditional expression was true
           read next expression and skip that
       else
           execute next expression
You may think of implementing a way for reading blocks of code to allow multiple statements to be inside the if.


It would take a bit of work though
Thanks Bazzy, the if statements will be one line inputs from a file. I will take a crack at it and report back if necessary.
I managed to code thus far the tokenizer which breaks the if statement into tokens and validates each one according to a set of grammar rules. I am having trouble validating the syntax of the statement and I realize it is probably easy but what I have implemented does not work.
I used boolean flags to confirm relevant tokens and used those to validate the statement but it does not work all the time.
eg.
1
2
if((isExp && isIdentifier && isRelop) ||(isExp && isStmnt && isElse))
			cout<<"  Statement Syntax Valid. " <<endl;

Another example since the code is long, is the function to test for a token.
1
2
3
4
5
6
7
8
9
10
11
12
bool LexicalTestAddop(string exp)
{
	if((exp == "+") || (exp == "-") || (exp == "OR"))
	{	isAddop = true;
		return true;
	}
	else
	{
		isValid = false;
		return false;
	}
}

Here are the rules of the grammar and all I need now is to validate the final syntax of the statement.

<if-stmt> ::= IF <expr> <stmt> | IF <expr> <stmt> ELSE <stmt>
<stmt> ::= <identifier> := <expr> ?
<expr> ::= <simple expr> | <simple expr> <relop> <simple expr>
<relop> ::= = | <> | < | <= | >= | >
<simple expr> ::= <term> | <simple expr> <addop> <term>
<sign> ::= + | -
<addop> ::= + | - | OR
<term> ::= <factor> | <term> <mulop> <factor>
<mulop> ::= * | / | DIV | MOD | AND
<factor> ::= <identifier> | <sign> <identifier> | <number> |
<sign> <number> | (<expr>) | <sign> (<expr>) | NOT <factor>
<identifier> ::= <letter> | <identifier> <letter> | <identifier> <digit>
<letter> ::= A | B | C | .... | Y | Z
<digit> ::= 0 | 1 | 2 | .... | 8 | 9
<natural> ::= <digit> | <natural> <digit>
<number> ::= <natural> | .<natural> | <natural>.<natural>


Thanks for an suggestions.

Topic archived. No new replies allowed.