『C++プログラミング言語(特別版)』第6章式と文-デスクトップコンピュータ-Linuxを実現


この実現は単なる構想であり,許容誤差と最適化が必要である.式の構文解析は次のとおりです.
 *****************  * program:  *     END  *     expr_list END  * expr_list:  *     expression PRINT    //PRINT is ;  *     expression PRINT expr_list  * expression:  *     expression + term  *     expression - term  *     term  * term:  *     term/primary  *     term * primary  *     primary  * primary:  *     NUMBER  *     NAME    //this is variable  *     NAME = expression  *     - primary  *     ( expression )  *****************
ファイルリスト:
  • calc.cc
  • calc.h
  • main.cc
  • makefile

  • ソースのダウンロード接続:http://download.csdn.net/detail/wxqee/4397788
    使用方法:
    xiwang@ubuntu:~/Dev/calc$ make
    g++ -Wall -I. -D_DEBUG -c calc.cc -o calc.cc.o
    g++ -Wall -I. -D_DEBUG -c main.cc -o main.cc.o
    g++ -D_DEBUG -L. calc.cc.o main.cc.o -o calc -lpthread
    
    
    xiwang@ubuntu:~/Dev/calc$ ./calc
    r = 2.5;
    2.5      //<  >
    area = pi * r * r;
    19.635   //<  >
    ^C
    

    すべてのコード』』』
    ファイル:calc.cc
    // calc.cc
    #include "calc.h"
    
    #include <ctype.h>
    
    #include <iostream>
    #include <map>
    #include <string>
    
    using namespace std;
    
    // error function
    int no_of_errors;
    
    double error(const string& s)
    {
        no_of_errors++;
        cerr << "error: " << s << '
    '; return 1; } // END error function Token_value curr_tok = PRINT; double expr(bool get) { double left = term(get); for (;;) { switch (curr_tok) { case PLUS: left += term(true); break; case MINUS: left -= term(true); break; default: return left; } } } double term(bool get) { double left = prim(get); for (;;) { switch (curr_tok) { case MUL: left *= prim(true); break; case DIV: if (double d = prim(true)) { left /= d; break; } return error("divide by 0"); default: return left; } } } double number_value; string string_value; map<string, double> table; // var table double prim(bool get) { if (get) get_token(); switch (curr_tok) { case NUMBER: { double v = number_value; get_token(); return v; } case NAME: { double& v = table[string_value]; if (get_token() == ASSIGN) v = expr(true); return v; } case MINUS: return -prim(true); case LP: { double e = expr(true); if (curr_tok != RP) return error(") expected"); get_token(); return e; } default: return error("primary expected"); } } // --BEGIN-- OPTIMIZE get_token function // Token_value get_token() // { // char ch = 0; // cin >> ch; // // switch (ch) { // case 0: // return curr_tok = END; // assign and return // case ';': // case '*': // case '/': // case '+': // case '-': // case '(': // case ')': // case '=': // return curr_tok = Token_value(ch); // case '0': case '1': case '2': case '3': case '4': // case '5': case '6': case '7': case '8': case '9': // case '.': // cin.putback(ch); // cin >> number_value; // return curr_tok = NUMBER; // default: // if (isalpha(ch)) { // cin.putback(ch); // cin >> string_value; // return curr_tok = NAME; // } // error("bad token"); // return curr_tok = PRINT; // } // } Token_value get_token() { char ch = 0; // --BEGIN-- ignore blanks except '
    ' // do { // if (!cin.get(ch)) return curr_tok = END; // } while (ch != '
    ' && isspace(ch)); cin >> ch; // ---END--- ignore blanks except '
    ' switch (ch) { case 0: return curr_tok = END; // assign and return case ';': case '*': case '/': case '+': case '-': case '(': case ')': case '=': return curr_tok = Token_value(ch); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': cin.putback(ch); cin >> number_value; return curr_tok = NUMBER; default: if (isalpha(ch)) { // --BEGIN-- Optimize to avoid meeting blank issue // cin.putback(ch); // cin >> string_value; string_value = ch; while (cin.get(ch) && isalnum(ch)) string_value.push_back(ch); cin.putback(ch); // ---END_-- Optimize to avoid meeting blank issue return curr_tok = NAME; } error("bad token"); return curr_tok = PRINT; } } // ---END--- OPTIMIZE get_token function

    ファイル:calc.h
    /**
     * calc.h
     *****************
     * program:
     *     END
     *     expr_list END
     * expr_list:
     *     expression PRINT     // PRINT is ;
     *     expression PRINT expr_list
     * expression:
     *     expression + term
     *     expression - term
     *     term
     * term:
     *     term / primary
     *     term * primary
     *     primary
     * primary:
     *     NUMBER
     *     NAME    // this is variable
     *     NAME = expression
     *     - primary
     *     ( expression )
     */
    
    #ifndef CALC_H_
    #define CALC_H_
    
    #include <map>
    #include <string>
    
    using namespace std;
    
    enum Token_value {
        NAME,       NUMBER,       END,
        PLUS='+',   MINUS='-',    MUL='*',      DIV='/',
        PRINT=';',  ASSIGN='=',   LP='(',       RP=')'
    };
    
    // for DRIVER PROGRAM
    extern Token_value curr_tok;
    extern map<string, double> table;   // var table
    extern int no_of_errors;
    
    extern double expr(bool get);
    extern Token_value get_token();
    extern double error(const string& s);
    // END for DRIVER PROGRAM
    
    extern double term(bool get);
    extern double prim(bool get);
    
    #endif
    

    ファイル:main.cc(ドライバ)
    /**
     * main.cc
     *
     * EAMPLE
     *     ./calc 'rate=1.1934;150/rate;19.75/rate;217/rate'
     */
    #include <iostream>
    #include <sstream>
    
    #include "calc.h"
    
    using namespace std;
    
    // --BEGIN-- COMMENT SIMPLE DRIVER
    // // DRIVER PROGRAM
    // int main(int argc, char **argv) {
    //   table["pi"] = 3.1415926535897932385;  // PRE-DEFINED NAMES
    //   table["e"]  = 2.7182818284590452354;
    //
    //   while (cin) {
    //       get_token();
    //       if (curr_tok == END) break;
    //       if (curr_tok == PRINT) continue;
    //       cout << expr(false) << endl;
    //   }
    //
    //   return no_of_errors;
    // }
    // ---END--- COMMENT SIMPLE DRIVER
    istream* input;
    
    int main(int argc, char * argv[])
    {
        switch (argc) {
            case 1:
                input = &cin;
                break;
            case 2:
                input = new istringstream(argv[1]);
                break;
            default:
                error("too many arguments");
                return 1;
        }
    
        table["pi"] = 3.1415926535897932385;  // PRE-DEFINED NAMES
        table["e"]  = 2.7182818284590452354;
    
        while (*input) {
            get_token();
            if (curr_tok == END) break;
            if (curr_tok == PRINT) continue;
            cout << expr(false) << '
    '; } if (input != &cin) delete input; return no_of_errors; }

    ファイル:makefile
    # Makefile, 2012-06-23 T1110
    
    # TODO
    # ----------------------------------
    NAME        = calc
    VERSION     = 1.0.0
    RELEASE     = 01
    # ----------------------------------
    
    BIN         = $(NAME)
    OBJS        = $(patsubst %.cpp,%.cpp.o,$(wildcard $(SRC_DIR)/*.cpp))
    OBJS       += $(patsubst %.cc,%.cc.o,$(wildcard $(SRC_DIR)/*.cc))
    OBJS       += $(patsubst %.C,%.C.o,$(wildcard $(SRC_DIR)/*.C))
    
    # TODO
    # BEGIN ----------------------------------
    # Folders
    SRC_DIR     = .
    
    # Flags
    CXXFLAGS    = -Wall
    CXXFLAGS   += -I$(SRC_DIR)
    
    CPPFLAGS    = -D_DEBUG
    
    LDFLAGS     = -L$(SRC_DIR)
    
    LIBS        = -lpthread
    # END ----------------------------------
    
    .PHONY: all clean
    
    all: $(BIN)
    
    $(BIN): $(OBJS)
    	$(CXX) $(CPPFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
    
    # source files
    %.cpp.o: %.cpp
    	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $^ -o $@
    
    %.cc.o: %.cc
    	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $^ -o $@
    
    %.C.o: %.C
    	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $^ -o $@
    
    
    clean:
    	$(RM) $(BIN) $(OBJS)