读书笔记之:C++程序设计原理与实践(ch06-ch07)[+++]

 

这儿是本书第6/7章的所有内容,之所以将这两章的内容都添加上来是因为这儿介绍的编写桌面计算器的例子很详细。整个过程非常的好。

1.0 可以完成简单的表达式的计算

View Code
#include <iostream>

#include <string>

#include <stdexcept>

using std::string;

using std::cout;

using std::cin;

using std::endl;

using std::cerr;

using std::runtime_error;

using std::exception;

inline void error(const string& errormessage)

{

        cerr << errormessage << endl;             

            throw runtime_error(errormessage);

}



inline void error(string s1, string s2)

{

    error(s1+s2);

}



class Token {

public:

    char kind;        // what kind of token

    double value;     // for numbers: a value 

    Token(char ch)    // make a Token from a char

        :kind(ch), value(0) { }    

    Token(char ch, double val)     // make a Token from a char and a double

        :kind(ch), value(val) { }

};



class Token_stream {

public

    Token_stream():full(false), buffer(0){}   // make a Token_stream that reads from cin

    Token get();      // get a Token (get() is defined elsewhere)

    void putback(Token t)    {

        if (full) error("putback() into a full buffer");

        buffer = t;       // copy t to buffer

        full = true;      // buffer is now full

    }

private:

    bool full;        // is there a Token in the buffer?

    Token buffer;     // here is where we keep a Token put back using putback()

};



Token Token_stream::get()

{

    if (full) {       // do we already have a Token ready?

        
// remove token from buffer

        full=false;

        return buffer;

    } 



    char ch;

    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)



    switch (ch) {

    case ';':    // for "print"

    case 'q':    // for "quit"

    case '('case ')'case '+'case '-'case '*'case '/'

        return Token(ch);        // let each character represent itself

    case '.':

    case '0'case '1'case '2'case '3'case '4':

    case '5'case '6'case '7'case '8'case '9':

        {    

            cin.putback(ch);         // put digit back into the input stream

            double val;

            cin >> val;              // read a floating-point number

            return Token('8',val);   // let '8' represent "a number"

        }

    default:

        error("Bad token");

    }

}



Token_stream ts;        // provides get() and putback() 

double expression();    // declaration so that primary() can call expression()

double primary()

{

    Token t = ts.get();

    switch (t.kind) {

    case '(':    // handle '(' expression ')'

        {    

            double d = expression();

            t = ts.get();

            if (t.kind != ')') error("')' expected");

            return d;

        }

    case '8':            // we use '8' to represent a number

        return t.value;  // return the number's value

    default:

        error("primary expected");

    }

}



// deal with *, /, and %

double term()

{

    double left = primary();

    Token t = ts.get();        // get the next token from token stream



    while(true) {

        switch (t.kind) {

        case '*':

            left *= primary();

            t = ts.get();

            break;

        case '/':

            {    

                double d = primary();

                if (d == 0) error("divide by zero");

                left /= d; 

                t = ts.get();

                break;

            }

        default

            ts.putback(t);     // put t back into the token stream

            return left;

        }

    }

}



// deal with + and -

double expression()

{

    double left = term();      // read and evaluate a Term

    Token t = ts.get();        // get the next token from token stream



    while(true) {    

        switch(t.kind) {

        case '+':

            left += term();    // evaluate Term and add

            t = ts.get();

            break;

        case '-':

            left -= term();    // evaluate Term and subtract

            t = ts.get();

            break;

        default

            ts.putback(t);     // put t back into the token stream

            return left;       // finally: no more + or -: return the answer

        }

    }

}



int main()

try

{

    double val = 0;

    while (cin) {

        Token t = ts.get();



        if (t.kind == 'q'break// 'q' for quit

        if (t.kind == ';')        // ';' for "print now"

            cout << "=" << val << '\n';

        else

            ts.putback(t);

        val = expression();

    }

}

catch (exception& e) {

    cerr << "error: " << e.what() << '\n'

    return 1;

}

catch (...) {

    cerr << "Oops: unknown exception!\n"

    return 2;

}

 

1.1比较人性化的输入输出,可以处理负数,可以进行模运算,可以错误恢复,

View Code
//

// This is example code from Chapter 7.7 "Recovering from errors" of

// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup

//



#include "std_lib_facilities.h"



/*

    Simple calculator



    Revision history:



        Revised by Bjarne Stroustrup May 2007

        Revised by Bjarne Stroustrup August 2006

        Revised by Bjarne Stroustrup August 2004

        Originally written by Bjarne Stroustrup

            (bs@cs.tamu.edu) Spring 2004.



    This program implements a basic expression calculator.

    Input from cin; output to cout.



    The grammar for input is:



    Statement:

        Expression

        Print

        Quit



    Print:

        ;



    Quit:

        q 



    Expression:

        Term

        Expression + Term

        Expression - Term

    Term:

        Primary

        Term * Primary

        Term / Primary

        Term % Primary

    Primary:

        Number

        ( Expression )

        - Primary

        + Primary

    Number:

        floating-point-literal





        Input comes from cin through the Token_stream called ts.

*/



//------------------------------------------------------------------------------



const char number = '8';    // t.kind==number means that t is a number Token

const char quit   = 'q';    // t.kind==quit means that t is a quit Token

const char print  = ';';    // t.kind==print means that t is a print Token

const string prompt = "";

const string result = ""// used to indicate that what follows is a result



//------------------------------------------------------------------------------



class Token {

public:

    char kind;        // what kind of token

    double value;     // for numbers: a value 

    Token(char ch)    // make a Token from a char

        :kind(ch), value(0) { }    

    Token(char ch, double val)     // make a Token from a char and a double

        :kind(ch), value(val) { }

};



//------------------------------------------------------------------------------



class Token_stream {

public

    Token_stream();   // make a Token_stream that reads from cin

    Token get();      // get a Token (get() is defined elsewhere)

    void putback(Token t);    // put a Token back

private:

    bool full;        // is there a Token in the buffer?

    Token buffer;     // here is where we keep a Token put back using putback()

};



//------------------------------------------------------------------------------



// The constructor just sets full to indicate that the buffer is empty:

Token_stream::Token_stream()

:full(false), buffer(0)    // no Token in buffer

{

}



//------------------------------------------------------------------------------



// The putback() member function puts its argument back into the Token_stream's buffer:

void Token_stream::putback(Token t)

{

    if (full) error("putback() into a full buffer");

    buffer = t;       // copy t to buffer

    full = true;      // buffer is now full

}



//------------------------------------------------------------------------------



Token Token_stream::get() // read characters from cin and compose a Token

{

    if (full) {         // check if we already have a Token ready

        full=false;

        return buffer;

    }  



    char ch;

    cin >> ch;          // note that >> skips whitespace (space, newline, tab, etc.)



    switch (ch) {

    case quit:

    case print:

    case '(':

    case ')':

    case '+':

    case '-':

    case '*':

    case '/'

    case '%':

        return Token(ch); // let each character represent itself

    case '.':             // a floating-point literal can start with a dot

    case '0'case '1'case '2'case '3'case '4':

    case '5'case '6'case '7'case '8'case '9':    // numeric literal

    {

        cin.putback(ch);// put digit back into the input stream

        double val;

        cin >> val;     // read a floating-point number

        return Token(number,val);

    }

    default:

        error("Bad token");

    }

}



//------------------------------------------------------------------------------



Token_stream ts;        // provides get() and putback() 



//------------------------------------------------------------------------------



double expression();    // declaration so that primary() can call expression()



//------------------------------------------------------------------------------



// deal with numbers and parentheses

double primary()

{

    Token t = ts.get();

    switch (t.kind) {

    case '(':           // handle '(' expression ')'

        {

            double d = expression();

            t = ts.get();

            if (t.kind != ')') error("')' expected");

            return d;

        }

    case number:    

        return t.value;    // return the number's value

    case '-':

        return - primary();

    case '+':

        return primary();

    default:

        error("primary expected");

    }

}



//------------------------------------------------------------------------------



// deal with *, /, and %

double term()

{

    double left = primary();

    Token t = ts.get(); // get the next token from token stream



    while(true) {

        switch (t.kind) {

        case '*':

            left *= primary();

            t = ts.get();

            break;

        case '/':

            {    

                double d = primary();

                if (d == 0) error("divide by zero");

                left /= d; 

                t = ts.get();

                break;

            }

        case '%':

            {    

                int i1 = narrow_cast<int>(left);

                int i2 = narrow_cast<int>(term());

                if (i2 == 0) error("%: divide by zero");

                left = i1%i2; 

                t = ts.get();

                break;

            }

        default

            ts.putback(t);        // put t back into the token stream

            return left;

        }

    }

}



//------------------------------------------------------------------------------



// deal with + and -

double expression()

{

    double left = term();      // read and evaluate a Term

    Token t = ts.get();        // get the next token from token stream



    while(true) {    

        switch(t.kind) {

        case '+':

            left += term();    // evaluate Term and add

            t = ts.get();

            break;

        case '-':

            left -= term();    // evaluate Term and subtract

            t = ts.get();

            break;

        default

            ts.putback(t);     // put t back into the token stream

            return left;       // finally: no more + or -: return the answer

        }

    }

}



//------------------------------------------------------------------------------



void clean_up_mess()           // naive



    while (true) {             // skip until we find a print

        Token t = ts.get();

        if (t.kind == print) return;

    }

}



//------------------------------------------------------------------------------



void calculate()

{

    while (cin)

      try {

        cout << prompt;

        Token t = ts.get();

        while (t.kind == print) t=ts.get();    // first discard all "prints"

        if (t.kind == quit) return;        // quit

        ts.putback(t);

        cout << result << expression() << endl;

    }

    catch (exception& e) {

        cerr << e.what() << endl;        // write error message

        clean_up_mess();

    }

}



//------------------------------------------------------------------------------



int main()

try {

    calculate();

    keep_window_open();    // cope with Windows console mode

    return 0;

}

catch (runtime_error& e) {

    cerr << e.what() << endl;

    keep_window_open("~~");

    return 1;

}

catch (...) {

    cerr << "exception \n";

    keep_window_open("~~");

    return 2;

}



//------------------------------------------------------------------------------

 

1.2 可以处理变量

View Code
//

// This is example code from Chapter 7.8.3 "Predefined names" of

// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup

//



#include "std_lib_facilities.h"



/*

    Simple calculator



    Revision history:



        Revised by Bjarne Stroustrup May 2007

        Revised by Bjarne Stroustrup August 2006

        Revised by Bjarne Stroustrup August 2004

        Originally written by Bjarne Stroustrup

            (bs@cs.tamu.edu) Spring 2004.



    This program implements a basic expression calculator.

    Input from cin; output to cout.



    The grammar for input is:



    Calculation:

        Statement

        Print

        Quit

        Calculation Statement

    

    Statement:

        Declaration

        Expression

    

    Declaration:

        "let" Name "=" Expression



    Print:

        ;



    Quit:

        q 



    Expression:

        Term

        Expression + Term

        Expression - Term

    Term:

        Primary

        Term * Primary

        Term / Primary

        Term % Primary

    Primary:

        Number

        Name

        ( Expression )

        - Primary

        + Primary

    Number:

        floating-point-literal





        Input comes from cin through the Token_stream called ts.

        Input test:

        let x = 3.4;               

        let y = 2;

        let z = (x+y*2)/pi;

        let z1 = -y*2+z*pi;

        q

*/



//------------------------------------------------------------------------------



const char number = '8';    // t.kind==number means that t is a number Token

const char quit   = 'q';    // t.kind==quit means that t is a quit Token

const char print  = ';';    // t.kind==print means that t is a print Token

const char name   = 'a';    // name token

const char let    = 'L';    // declaration token

const string declkey = "let";// declaration keyword 

const string prompt  = "";

const string result  = ""// used to indicate that what follows is a result



//------------------------------------------------------------------------------



class Token {

public:

    char kind;        // what kind of token

    double value;     // for numbers: a value 

    string name;      // for names: name itself

    Token(char ch)             : kind(ch), value(0)   {}

    Token(char ch, double val) : kind(ch), value(val) {}

    Token(char ch, string n)   : kind(ch), name(n)    {}

};



//------------------------------------------------------------------------------



class Token_stream {

public

    Token_stream();   // make a Token_stream that reads from cin

    Token get();      // get a Token (get() is defined elsewhere)

    void putback(Token t);    // put a Token back

    void ignore(char c);      // discard tokens up to an including a c

private:

    bool full;        // is there a Token in the buffer?

    Token buffer;     // here is where we keep a Token put back using putback()

};



//------------------------------------------------------------------------------



// The constructor just sets full to indicate that the buffer is empty:

Token_stream::Token_stream()

:full(false), buffer(0)    // no Token in buffer

{

}



//------------------------------------------------------------------------------



// The putback() member function puts its argument back into the Token_stream's buffer:

void Token_stream::putback(Token t)

{

    if (full) error("putback() into a full buffer");

    buffer = t;       // copy t to buffer

    full = true;      // buffer is now full

}



//------------------------------------------------------------------------------



Token Token_stream::get() // read characters from cin and compose a Token

{

    if (full) {         // check if we already have a Token ready

        full=false;

        return buffer;

    }  



    char ch;

    cin >> ch;          // note that >> skips whitespace (space, newline, tab, etc.)



    switch (ch) {

    case quit:

    case print:

    case '(':

    case ')':

    case '+':

    case '-':

    case '*':

    case '/'

    case '%':

    case '=':

        return Token(ch); // let each character represent itself

    case '.':             // a floating-point literal can start with a dot

    case '0'case '1'case '2'case '3'case '4':

    case '5'case '6'case '7'case '8'case '9':    // numeric literal

    {

        cin.putback(ch);// put digit back into the input stream

        double val;

        cin >> val;     // read a floating-point number

        return Token(number,val);

    }

    default:

        if (isalpha(ch)) {

            string s;

            s += ch;

            while (cin.get(ch) && (isalpha(ch) || isdigit(ch))) s+=ch;

            cin.putback(ch);

            if (s == declkey) return Token(let); // keyword "let"

            return Token(name,s);

        }

        error("Bad token");

    }

}



//------------------------------------------------------------------------------



void Token_stream::ignore(char c)

    // c represents the kind of a Token

{

    // first look in buffer:

    if (full && c==buffer.kind) {

        full = false;

        return;

    }

    full = false;



    // now search input:

    char ch = 0;

    while (cin>>ch)

        if (ch==c) return;

}



//------------------------------------------------------------------------------



Token_stream ts;        // provides get() and putback() 



//------------------------------------------------------------------------------



class Variable {

public:

    string name;

    double value;

    Variable (string n, double v) :name(n), value(v) { }

};



//------------------------------------------------------------------------------



vector<Variable> var_table;



//------------------------------------------------------------------------------



double get_value(string s)

    // return the value of the Variable names s

{

    for (int i = 0; i<var_table.size(); ++i)

        if (var_table[i].name == s) return var_table[i].value;

    error("get: undefined variable ", s);

}



//------------------------------------------------------------------------------



void set_value(string s, double d)

    // set the Variable named s to d

{

    for (int i = 0; i<var_table.size(); ++i)

        if (var_table[i].name == s) {

            var_table[i].value = d;

            return;

        }

    error("set: undefined variable ", s);

}



//------------------------------------------------------------------------------



bool is_declared(string var)

    // is var already in var_table?

{

    for (int i = 0; i<var_table.size(); ++i)

        if (var_table[i].name == varreturn true;

    return false;

}



//------------------------------------------------------------------------------



double define_name(string vardouble val)

    // add (var,val) to var_table

{

    if (is_declared(var)) error(var," declared twice");

    var_table.push_back(Variable(var,val));

    return val;

}



//------------------------------------------------------------------------------



double expression();    // declaration so that primary() can call expression()



//------------------------------------------------------------------------------



// deal with numbers and parentheses

double primary()

{

    Token t = ts.get();

    switch (t.kind) {

    case '(':           // handle '(' expression ')'

        {

            double d = expression();

            t = ts.get();

            if (t.kind != ')') error("')' expected");

            return d;

        }

    case number:    

        return t.value;    // return the number's value

    case name:

        return get_value(t.name); // return the variable's value

    case '-':

        return - primary();

    case '+':

        return primary();

    default:

        error("primary expected");

    }

}



//------------------------------------------------------------------------------



// deal with *, /, and %

double term()

{

    double left = primary();

    Token t = ts.get(); // get the next token from token stream



    while(true) {

        switch (t.kind) {

        case '*':

            left *= primary();

            t = ts.get();

            break;

        case '/':

            {    

                double d = primary();

                if (d == 0) error("divide by zero");

                left /= d; 

                t = ts.get();

                break;

            }

        case '%':

            {    

                int i1 = narrow_cast<int>(left);

                int i2 = narrow_cast<int>(term());

                if (i2 == 0) error("%: divide by zero");

                left = i1%i2; 

                t = ts.get();

                break;

            }

        default

            ts.putback(t);        // put t back into the token stream

            return left;

        }

    }

}



//------------------------------------------------------------------------------



// deal with + and -

double expression()

{

    double left = term();      // read and evaluate a Term

    Token t = ts.get();        // get the next token from token stream



    while(true) {    

        switch(t.kind) {

        case '+':

            left += term();    // evaluate Term and add

            t = ts.get();

            break;

        case '-':

            left -= term();    // evaluate Term and subtract

            t = ts.get();

            break;

        default

            ts.putback(t);     // put t back into the token stream

            return left;       // finally: no more + or -: return the answer

        }

    }

}



//------------------------------------------------------------------------------



double declaration()

    // handle: name = expression

    
// declare a variable called "name" with the initial value "expression"

{

    Token t = ts.get();

    if (t.kind != name) error ("name expected in declaration");

    string var_name = t.name;



    Token t2 = ts.get();

    if (t2.kind != '=') error("= missing in declaration of ", var_name);



    double d = expression();

    define_name(var_name,d);

    return d;

}



//------------------------------------------------------------------------------



double statement()

{

    Token t = ts.get();

    switch (t.kind) {

    case let:

        return declaration();

    default:

        ts.putback(t);

        return expression();

    }

}



//------------------------------------------------------------------------------



void clean_up_mess()



    ts.ignore(print);

}



//------------------------------------------------------------------------------



void calculate()

{

    while (cin)

      try {

        cout << prompt;

        Token t = ts.get();

        while (t.kind == print) t=ts.get();    // first discard all "prints"

        if (t.kind == quit) return;        // quit

        ts.putback(t);

        cout << result << statement() << endl;

    }

    catch (exception& e) {

        cerr << e.what() << endl;        // write error message

        clean_up_mess();

    }

}



//------------------------------------------------------------------------------



int main()

try {

    // predefine names:

    define_name("pi",3.1415926535);

    define_name("e",2.7182818284);



    calculate();



    keep_window_open();    // cope with Windows console mode

    return 0;

}

catch (exception& e) {

    cerr << e.what() << endl;

    keep_window_open("~~");

    return 1;

}

catch (...) {

    cerr << "exception \n";

    keep_window_open("~~");

    return 2;

}



//------------------------------------------------------------------------------

 

posted @ 2012-04-10 14:46  Mr.Rico  阅读(736)  评论(0编辑  收藏  举报