when i copy the code from the book The C++ Programming Language Fourth Edition ,Bjarne Stroustrup I found out that when i input a pi(which has been defined in the code) the output is wrong so i spent 1 day to find out the problem. i just share it
#include<iostream>
#include<map>
#include<string>
#include<sstream>
#include<cctype>
enum class Kind:char{
name,number,end,
plus='+',minus='-',mul='*',div='/',print=';',assign='=',lp='(',rp=')'
};
struct Token{
Kind kind;
std::string string_value;
double number_value;
};
int no_of_errors;
double error(const std::string& s)
{
no_of_errors++;
std::cerr<<"error: "<<s<<'\n';
return 1;
}
std::map<std::string,double> table;
double expr(bool get);
double term(bool get);
double prim(bool get);
class Token_stream{
public:
Token_stream(std::istream& s):ip{&s},owns{false}{}
Token_stream(std::istream* p):ip{p},owns{true}{}
~Token_stream(){close();}
Token get();
Token& current(){return ct;}
void set_input(std::istream& s){close();ip=&s;owns=false;}
void set_input(std::istream* p){close();ip=p;owns=true;}
private:
void close(){if(owns) delete ip;}
std::istream* ip;
bool owns;
Token ct{Kind::end};
};
Token_stream ts{std::cin};
//Token& Token_stream::current()
//{
// return ct;
//}
Token Token_stream::get()
{
char ch;
do{
if(!ip->get(ch)){
return ct={Kind::end};
}
}while(ch!='\n' && std::isspace(ch));
switch(ch){
case ';':
case '\n':
return ct={Kind::print};
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return ct={static_cast<Kind>(ch)};
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':{
ip->putback(ch);
*ip>>ct.number_value;
ct.kind=Kind::number;
return ct;
}
default:
if(std::isalpha(ch)){
ct.string_value = ch;
while(ip->get(ch) && std::isalnum(ch)){
ct.string_value +=ch;
}
//test
//std::cout<<ts.current().string_value<<'\n';
//std::cout<<table[ct.string_value]<<'\n';
ip->putback(ch);
return ct={Kind::name,ct.string_value};
}
error("bad token");
return ct={Kind::print};
}
}
double expr(bool get)
{
//test
// std::cout<<ts.current().string_value<<'\n';
// std::cout<<table[ts.current().string_value]<<'\n';
double left=term(get);
for(;;){
switch(ts.current().kind){
case Kind::plus:
left += term(true);
break;
case Kind::minus:
left-= term(true);
break;
default:
return left;
}
}
}
double term(bool get)
{
double left = prim(get);
for(;;){
switch(ts.current().kind){
case Kind::mul:
left *= prim(true);
break;
case Kind::div:
if(auto d = prim(true)){
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
}
double prim(bool get)
{
if(get){
ts.get();
}
switch(ts.current().kind){
case Kind::number:
{
double v=ts.current().number_value;
ts.get();
return v;
}
case Kind::name:
{
//test
//std::cout<<ts.current().string_value<<'\n';
double& v=table[ts.current().string_value];
//std::cout<<table[ts.current().string_value]<<'\n';
if(ts.get().kind == Kind::assign){
v=expr(true);
}
//std::cout<<ts.current().string_value<<'\n';
//std::cout<<v<<'\n';
//std::cout<<table[ts.current().string_value]<<'\n';
return v;
}
case Kind::lp:
{
auto e = expr(true);
if(ts.current().kind!=Kind::rp){
return error("')' expected");
}
void(ts.get());
return e;
}
default:
return error("primary expected");
}
}
void calculate()
{
for(;;){
ts.get();
//test
//if(ts.current().kind != Kind::number){
// std::cout<<"number"<<'\n';
//}
if(ts.current().kind == Kind::end)break;
if(ts.current().kind == Kind::print)continue;
std::cout<<expr(false)<<'\n';
}
}
int main(int arg,char* argv[])
{
switch(arg){
case 1:
break;
case 2:
ts.set_input(new std::istringstream{argv[1]});
break;
default:
error("too many arguments");
return 1;
}
table["pi"] = 3.1415926535897932385;
table["e"] = 2.7182818284590452354;
calculate();
return no_of_errors;
}
233,1 Bot
the most important for correct the error is as follows:
//in member function Token Token_stream::get()
//old code:
return ct={Kind::name;}
we should change the code like this:
//in member function Token Token_stream::get()
//new code:
return ct={Kind::name,ct.string_value}
Aucun commentaire:
Enregistrer un commentaire