Skip to content

Instantly share code, notes, and snippets.

@chengluyu
Last active December 21, 2015 00:19
Show Gist options
  • Save chengluyu/6219251 to your computer and use it in GitHub Desktop.
Save chengluyu/6219251 to your computer and use it in GitHub Desktop.
Calculator
#include <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <cmath>
using namespace std;
class parse_error : exception {
string msg;
public:
parse_error(const char * str) : msg(str) { }
virtual ~parse_error() throw () { }
virtual const char * what() const throw () {
return msg.c_str();
}
};
void error(const char * info) {
throw parse_error(info);
}
double T(istream & in);
double S(istream & in) {
double val = T(in);
while (in.peek() == '-' || in.peek() == '+')
if (in.get() == '+')
val += T(in);
else
val -= T(in);
return val;
}
double V(istream & in) {
double val;
bool negative = false;
while (in.peek() == '-' || in.peek() == '+')
negative ^= in.get() == '-';
if (in.peek() == '(') {
in.get();
val = S(in);
if (in.get() != ')')
error("Bracket doesn't match.");
} else {
if (!isdigit(in.peek()))
error("Missing a operand.");
in >> val;
}
return negative ? -val : val;
}
double U(istream & in) {
double val = V(in), index, result;
if (in.peek() == '^') {
in.get();
index = U(in);
result = pow(val, index);
} else
result = val;
return result;
}
double T(istream & in) {
double val = U(in);
while (in.peek() == '*' || in.peek() == '/')
if (in.get() == '*')
val *= U(in);
else
val /= U(in);
return val;
}
int main(int argc, const char *argv[]) {
// istringstream in("1.2+(9.6^2.5---3+9*9)");
istream & in = cin;
try {
cout << S(in) << endl;
} catch (parse_error e) {
cerr << e.what() << endl;
}
return 0;
}
@chengluyu
Copy link
Author

微软的奇葩定义……一直觉得微软的东西还是封装一下比较好。

@chengluyu
Copy link
Author

加入了错误显示。还有对6-+-(67^5)这样表达式的支持。

@82488059
Copy link

还应该加入除0错误的提示

@82488059
Copy link

rule<phrase_scanner_t> factor, term, exp; 
factor = real_p | ('(' >> exp >> ')');  // real_p | !(ch_p('+')|ch_p('-')) >> ('(' >> exp >> ')') 注释部分是带正负号的规则
term   = factor >> *(('*' >> factor) | ('/' >> factor)); 
exp    = term >> *(('+' >> term) | ('-' >> term)); 

const char *szExp = "(2+3)"; 
parse_info<> rule = parse( szExp , exp, space_p); 
cout << "parse " << (rule.full?"success":"fail") << endl; 
我在网上找到的用boost::spirit对四则运算的验证,后面注释是我改写的可以在括号前面带正负号规则验证。

@chengluyu
Copy link
Author

这倒不错,spirit十分方便,直接写cfg就行了,不过一直嫌boost配置太麻烦。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment