• 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 << '
    ';
            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) << "
    ";
            }
        }
    }

    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 '
    '
                if (!ip->get(ch))
                    return ct = { Kind::end };
            } while (ch != '
    ' && isspace(ch));
    
            switch (ch)
            {
            case 0:
                return ct = { Kind::end };        // assign and return
            case ';':        // end of expression; print
            case '
    ':
                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;
    }
  • 相关阅读:
    Redis设置生存时间或过期时间的相关命令
    .Net Core使用Redis
    Redis的数据类型
    Java集合 使用Collections
    Java集合 使用Iterator
    Java集合 使用Stack
    响应式常用样式汇总
    图片 文字 背景等响应式设置总结
    微信动态聊天工具
    第2章 栅格系统
  • 原文地址:https://www.cnblogs.com/albizzia/p/8997953.html
Copyright © 2020-2023  润新知