This implementation is just an idea and requires fault tolerance and optimization. Expression syntax analysis is as follows:
*****************
* 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)
*****************
File List:
- Calc. CC
- Calc. h
- Main. CC
- Makefile
Source download connection: http://download.csdn.net/detail/wxqee/4397788
Usage:
Xiwang @ Ubuntu :~ /Dev/calc $ makeg ++-wall-I. -d_debug-C Calc. CC-O Calc. cc. OG ++-wall-I. -d_debug-C main. CC-O main. cc. OG ++-d_debug-L. calc. cc. O main. cc. o-O calc-lpthreadxiwang @ Ubuntu :~ /Dev/calc $./calcr = 2.5; 2.5 // <output> area = pI * r; 19.635 // <output> ^ C
All codes
File: Calc. CC
// calc.cc#include "calc.h"#include <ctype.h>#include <iostream>#include <map>#include <string>using namespace std;// error functionint no_of_errors;double error(const string& s){ no_of_errors++; cerr << "error: " << s << '\n'; return 1;}// END error functionToken_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 tabledouble 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 '\n' // do { // if (!cin.get(ch)) return curr_tok = END; // } while (ch != '\n' && isspace(ch)); cin >> ch; // ---END--- ignore blanks except '\n' 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
File: 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 PROGRAMextern Token_value curr_tok;extern map<string, double> table; // var tableextern int no_of_errors;extern double expr(bool get);extern Token_value get_token();extern double error(const string& s);// END for DRIVER PROGRAMextern double term(bool get);extern double prim(bool get);#endif
File: Main. CC (driver)
/** * 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 DRIVERistream* 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) << '\n'; } if (input != &cin) delete input; return no_of_errors;}
File: makefile
# Makefile, 2012-06-23 T1110# TODO# ----------------------------------NAME = calcVERSION = 1.0.0RELEASE = 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 ----------------------------------# FoldersSRC_DIR = .# FlagsCXXFLAGS = -WallCXXFLAGS += -I$(SRC_DIR)CPPFLAGS = -D_DEBUGLDFLAGS = -L$(SRC_DIR)LIBS = -lpthread# END ----------------------------------.PHONY: all cleanall: $(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)