Hello

I am new to C++ programming and i am trying to write a c++ class for a calculator. I am having trouble with my get_token function where i'm trying to read one character at a time and if the character represents a number , it should convert it into a double type.

This is possible when you are reading the expression to be evaluated is read through the keyboard by using the commands

char ch;
            int n;                            
            cin>>ch;
            cin.pushback(ch);
            cin>>n;

but now i'm trying to read out the expression from a string...i'm not sure which command to use

here is the code i'm using. Thank you :)


Calc.h

#ifndef CALC_H
#define CALC_H
#include <string>
#include <map>
#include <cctype>



enum Token_value
{
	NAME,      NUMBER,     END,
	PLUS='+',  MINUS='-',  MUL='*',   DIV='/',
	PRINT=';', ASSIGN='=', LP='(',    RP=')'
};



class Calculator
{
public:
	Calculator() {defined=false;cur_tok=PRINT;}
	void Get(string str,istream &is);
	void Show(ostream &os);
	Token_value get_token(int &index);
	double Prim(bool get,int &index);
	double Term(bool get,int &index);
	double Expr(bool get,int &index);
	double Eval();
	double error(const string& s);

private:
	bool defined;
	string expr;
	Token_value cur_tok;

};
#endif

Calc.cpp

#include <iostream>
#include <string>
#include <map>
#include <cctype>

using namespace std;
#include "Calc.h"



double number_value;
string string_value;
int no_of_errors;
map<string,double> table;







double Calculator::Expr(bool get,int &index)
{
	double left=Term(get,index);

	for(;;)
		switch(cur_tok)
	{
		case PLUS:
			left+=Term(true,index);
			break;
		case MINUS:
			left-=Term(true,index);
			break;
		default:
			return left;
	}
}

double Calculator::Term(bool get,int &index)
{
	double left=Prim(get,index);
	for(;;)
		switch(cur_tok)
	{
		case MUL:
			left*=Prim(true,index);
			break;
		case DIV:
			if(double d=Prim(true,index))
			{
				left/=d;
				break;
			}
			return error("divide by 0");
		default:
			return left;
	}
}

double Calculator::Prim(bool get,int &index)
{
	if(get)get_token(index);

	switch (cur_tok)
	{
	case NUMBER:
		{
		double v=number_value;
		get_token(index);
		return v;
		}
	case NAME:
		{
			//Name *n3=t1.lookup(string_value);
			double &v=table[string_value];
			if(get_token(index)==ASSIGN) v=Expr(true,index);
			return v;
		}
	case MINUS:
		return -Prim(true,index);
	case LP:
		{
		double e=Expr(true,index);
		if(cur_tok!=RP) return error(") expected");
		get_token(index);
		return e;
		}
	default:
		return error("primary expected");
	}
}

Token_value Calculator::get_token(int &index)
{
	char ch=expr[index];
	cout<<"data="<<expr[index]<<'\n';
	int n;
	n=atoi(&ch);
	cout<<"n="<<n<<'\n';
	index++;
	switch(ch)
	{
	case 0:
		return cur_tok=END;
	case ';':
	case '*':
	case '/':
	case '+':
	case '-':
	case '(':
	case ')':
	case '=':
		return cur_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 '.':
		cin.putback(ch);
		cin>>number_value;
		return cur_tok=NUMBER;
	default:
		if(isalpha(ch))
		{
			cin.putback(ch);
			cin>>string_value;
			return cur_tok=NAME;
		}
		error("bad token");
		return cur_tok=PRINT;
	}
}


double Calculator::error(const string& s)
{
	no_of_errors++;
	cerr<<"error:"<<s<<'\n';
	return 1;
}

/*int main()
{
	
	table["pi"]=3.1415926535897932385;
	table["e"]=2.7182818284590452354;

	while(cin)
	{
		get_token();
		if(cur_tok==END)
			break;
		if(cur_tok==PRINT) 
			continue;
		cout<<expr(false)<<'\n';
	}
	return no_of_errors;
}*/

double Calculator::Eval()
{
	bool result;
    int i=0;
	while(i<expr.size())
	{
		get_token(i);
		if(cur_tok==END)
			break;
		if(cur_tok==PRINT) 
			continue;
		result=Expr(false,i);
	}
	return result;
}



void Calculator::Get(string str,istream &is)
{
	cout<<str;
	string exp;
	if(is.peek()!='\n')
	{
		getline(is,exp);
		expr=exp;
		defined=true;
	}
	//is.ignore(INT_MAX,'\n');
}

void Calculator::Show(ostream &os)
{
	os<<expr;
}

Main

#include <iostream>
#include <string>
#include <map>

using namespace std;

#include "Calc.h"

int main()
{
	double x;
	//table["pi"]=3.1415926535897932385;
	//table["e"]=2.7182818284590452354;
	Calculator c;
	c.Get("Enter an expression\n",cin);
	c.Show(cout);
	
	x=c.Eval();
	cout<<"result="<<x<<'\n';
	return 0;
}

The Eval function loops through tokens without remembering what it did last and returns a bool value rather than double.
For parsing, there is no replacement for strtok, or something that does the same.
So, you get the string, tokenize it into an array of small tokens.
Then, you use standard parsing functions for the numerics.
You might want to look into the standard parsing functions atof, atod, or atoi.

> how to read input from strings using cin

1. Create a std::stringbuf which gets its input from a std::string.
2.Set this as the std::streambuf used by std::cin

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string input_string = "string containing input 123 45 a 72.45 etc." ;
    std::stringbuf streambuf( input_string, std::ios_base::in ) ;
    std::cin.rdbuf( &streambuf ) ;

    // now use std::cin to read the contents of input_string
}
commented: excellent concise iostream example +1
commented: Nice, I learned something new. +5

Thank you very much :)

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.