zoukankan      html  css  js  c++  java
  • 读书笔记之:C++程序设计原理与实践(ch06ch07)[+++]

     

    这儿是本书第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;

    }



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

     

  • 相关阅读:
    HTML5中input输入框的种类
    perl mojo 编码
    perl encode_utf8 decode_utf8
    perl mojo use utf8 和no utf8
    perl unload oracle gbk
    perl unload Oracle utf8 数据库
    perl socket 返回发送成功数据的长度
    perl socket 客户端发送消息
    验证码识别(Tess4J初体验)
    Uploadify 3.2 参数属性、事件、方法函数详解
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2641041.html
Copyright © 2011-2022 走看看