C++ Programming Language中的Calculator源代码

C++ Programming Language 4th中的Calculator源代码整理,因为在C++ Programming Language中,涉及了很多文件位置之类的变化,所以,这里只是其中的一个版本:

error.h

#include <string>
#include <iostream>

namespace Error
{
    extern int no_of_errors;
    
    inline double error(const std::string& s)
    {
        no_of_errors++;
        std::cerr << "error:" << s << '\n';
        return 1;
    }
}

Table.h

#include <map>
#include <string>

namespace Table
{
    extern std::map<std::string, double> table;
}

Lexer.h

#include <string>
#include <istream>

namespace Lexer
{
    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;
    };

    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();            // read and return next token
        Token& current()    // most recent read token
        {
            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;            // pointer to an input stream
        bool owns;                    // does the Token_stream own the istream?
        Token ct{ Kind::end };        // current token
    };

    extern Token_stream ts;
}

Parser.h

namespace Parser
{
    double prim(bool get);
    double term(bool get);
    double expr(bool get);
}

Driver.h

#include <iostream>
#include "Lexer.h"
#include "Parser.h"

namespace Driver
{
    using namespace Lexer;
    using namespace Parser;

    inline void calculate()
    {
        for (;;)
        {
            ts.get();
            if (ts.current().kind == Kind::end) break;
            if (ts.current().kind == Kind::print) continue;
            std::cout << expr(false) << "\n";
        }
    }
}

Error.cpp

#include "Error.h"

namespace Error
{
    int no_of_errors = 0;
}

Table.cpp

#include "Table.h"

namespace Table
{
    std::map<std::string, double> table;
}

Lexer.cpp

#include "Lexer.h"
#include <iostream>

namespace Lexer
{
    Token Token_stream::get()
    {
        char ch = 0;

        do { // skip whitespace except '\n'
            if (!ip->get(ch))
                return ct = { Kind::end };
        } while (ch != '\n' && isspace(ch));

        switch (ch)
        {
        case 0:
            return ct = { Kind::end };        // assign and return
        case ';':        // end of expression; print
        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);            // put the first digit (or .) back into the input stream
            *ip >> ct.number_value;        // read number into ct
            ct.kind = Kind::number;
            return ct;
        default:            // name, name = , or error
            if (isalpha(ch))
            {
                ct.string_value = ch;
                while (ip->get(ch) && isalnum(ch))
                    ct.string_value += ch;        // append ch to end of string_value
                ip->putback(ch);
                return ct = { Kind::name };
            }

        }
    }

    Token_stream ts{ std::cin };
}

Parser.cpp

#include "Parser.h"
#include "Lexer.h"
#include "Error.h"
#include "Table.h"

namespace Parser
{
    using namespace Lexer;
    using namespace Error;
    using namespace Table;

    double expr(bool get)        // add and subtract
    {
        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)        // multiply and divide
    {
        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)        // handle primaries
    {
        if (get) ts.get();        // read next token

        switch (ts.current().kind)
        {
        case Kind::number:            // floating-point constant
        {
            double v = ts.current().number_value;
            ts.get();
            return v;
        }
        case Kind::name:
        {
            double& v = table[Lexer::ts.current().string_value];        // find the corresponding
            if (ts.get().kind == Kind::assign)
                v = expr(true);                                        // '=' seen: assignment
            return v;
        }
        case Kind::minus:        // unary minus
            return -prim(true);
        case Kind::lp:
        {
            auto e = expr(true);
            if (ts.current().kind != Kind::rp)
                return error("')' expected");
            ts.get();        // eat ')'
            return e;
        }
        default:
            return error("primary expected");
        }
    }
}

实际使用代码(测试代码):

#include "Error.h"
#include "Driver.h"
#include "Table.h"

int main()
{
    Table::table["pi"] = 3.1415926535897932385; // inser t predefined names
    Table::table["e"] = 2.7182818284590452354;

    Driver::calculate();
    return Error::no_of_errors;
}

 

posted on 2018-05-06 13:02  月落无影  阅读(426)  评论(0编辑  收藏  举报