#include <map> #include <string> #include <iostream> #include <sstream> #include <stack> #include <queue> #include <list> template<class T> T string_cast(const std::string& v){ std::stringstream ss; ss << v; T ret; ss >> ret; return ret; } template<class T> std::string to_string( T v){ std::stringstream ss; ss << v; return ss.str(); } std::string op_v(const char c){ std::string ret; ret += c; return ret; } typedef std::list<std::string> exp_list; typedef exp_list::const_iterator exp_item; class simple_script{ typedef std::list<std::string> exp_list; typedef exp_list::const_iterator exp_item; typedef std::map<std::string,std::string> exp_results; typedef std::map<std::string,exp_list> function_list; function_list function_expr; public: simple_script(const std::string& script){ parse_script(script,expr); splite_functions(expr,function_expr); } public: void do_script(){ excute_block(expr.begin(),expr.end()); } protected: exp_item assign_op(exp_item b, exp_item e,const std::string& name = ""){ std::string key = (name.empty()) ? *b++ : name + "." + (*b++);//var std::string asg = *b++;// = exp_item ret; switch(b->c_str()[0]){ case '[':{ //for array ++b; for(int i = 0; *b != "]"; ++b){ if(*b == ",") continue; if(*b == "{") { ret = get_block_range(++b,e); excute_block(b,ret,key+ "@" + to_string(i++)); b = ret; continue; } results[key+ "@" + to_string(i++)] = get_result(*b); } ret = ++b; break; } case '{':{//for mix ret = get_block_range(++b,e); excute_block(b,ret,key); ++ret;//for last } break; } default:{ ret = std::find(b,e,";"); results[key] = calculate_string(b,ret); break; } } return ++ret; } exp_item test_op(exp_item b, exp_item e){ exp_item te = std::find(b,e,"{"); std::string rst = calculate_string(++b,te); exp_item tb = get_block_range(++te,e); if(!rst.empty() && string_cast<int>(rst)){ excute_block(te,tb); } return ++tb; } exp_item for_op(exp_item b , exp_item e){ exp_item test = std::find(++b,e,";");//skip ( exp_item tmp = test; exp_item calc = std::find(++tmp,e,";"); // skip ; tmp = calc; exp_item block = std::find(++tmp,e, ")"); // tmp = block;++tmp; exp_item block_end = get_block_range(++tmp,e); for(assign_op(b,test);;assign_op(++tmp, block)){ tmp = test; std::string rst = calculate_string(++tmp,calc); if(rst.empty() || 0 == string_cast<int>(rst)){ break; } tmp = block;++tmp; excute_block(++tmp,block_end); tmp = calc; } return ++block_end; } protected: exp_item skip_function(exp_item b, exp_item e){ if(b == e || *b !="function"){ return b; } b = std::find(b,e,"{"); return get_block_range(b,e); } public: /* sub function operation */ std::string get_sub_result(const std::string& function_name,exp_item pb,exp_item pe){ function_list::const_iterator it = function_expr.find(function_name); if(it == function_expr.end()){ return ""; } exp_item b = it->second.begin(); exp_item e = it->second.end(); b = std::find(b,e,"("); for(++b,++pb; b != e && pb != pe && *b != ")"; ++b,++pb){ if(*b == ",") continue; results[*b] = *pb; } e = get_block_range(++b,e); excute_block(++b,e); return results[function_name]; } const exp_results& get_results(void)const{ return results; } protected: void excute_block(exp_item b,const exp_item& e,const std::string& name = ""){ for(; b != e;){ std::string key = *b; if(key == "if"){ b = test_op(b,e); }else if (key == "for"){ b = for_op(++b,e); }else{ b = assign_op(b,e,name); } } } exp_item get_block_range(exp_item b ,exp_item e,const std::string& tag1 = "{",const std::string& tag2 = "}")const{ int count = 1; for(++b; b != e; ++b){ if(tag1 == *b) ++count; if(tag2 == *b) --count; if(0 == count) break; } return b; } protected: exp_list expr; protected: /* the script no local var only glob var */ exp_results results; std::string get_result(const std::string& key)const{ exp_results::const_iterator it = results.find(key); return (it == results.end()) ? key : (it->second); } protected: /* base operation */ std::string sub(const std::string& v){ return "-" + get_result(v); } std::string add(const std::string& l,const std::string& r){ const std::string lv = get_result(l); const std::string rv = get_result(r); return to_string(string_cast<double>(lv) + string_cast<double>(rv)); } std::string mut(const std::string& l,const std::string& r){ const std::string lv = get_result(l); const std::string rv = get_result(r); return to_string(string_cast<double>(lv) * string_cast<double>(rv)); } std::string div(const std::string& l,const std::string& r){ const std::string lv = get_result(l); const std::string rv = get_result(r); return to_string(string_cast<double>(lv) / string_cast<double>(rv)); } std::string next_result(exp_item& b , exp_item& e){ ++b; if(*b == "("){ exp_item tb = ++b; exp_item te = get_block_range(tb,e,"(",")"); std::string result = calculate_string(tb,te); b = te; return result; } return get_result(*b); } std::string calculate_string(exp_item& b,exp_item& e){ std::stack<std::string> results; results.push(*b); for(++b; b != e; ++b){ switch(b->c_str()[0]){ case '<':{ std::string l = get_result(results.top()); std::string r = next_result(b,e); results.pop(); results.push(to_string<bool>(string_cast<int>(l) < string_cast<int>(r))); break; } case '>':{ std::string l = get_result(results.top()); std::string r = next_result(b,e); results.pop(); results.push(to_string<bool>(string_cast<int>(l) > string_cast<int>(r))); break; } case '&':{ std::string l = get_result(results.top()); std::string r = next_result(b,e); results.pop(); results.push(to_string(string_cast<int>(l) && string_cast<int>(r))); break; } case '|':{ std::string l = get_result(results.top()); std::string r = next_result(b,e); results.pop(); results.push(to_string(string_cast<int>(l) || string_cast<int>(r))); break; } case '!':{ std::string r = next_result(b,e); results.push(to_string(!string_cast<int>(r))); break; } case '(':{ std::string l = results.top(); if(function_expr.find(l) != function_expr.end()){ results.pop(); exp_item be = std::find(b,e,")"); results.push(get_sub_result(l,b,be)); b = be; }else{ results.push("("); } break; } case ')':{ std::string result = results.top(); for(results.pop(); results.top() != "(";results.pop()){ result = add(result,results.top()); } results.pop(); results.push(result); break; } case '+':{ break; } case '-':{ std::string r = next_result(b,e); results.push(sub(r)); break; } case '*':{ std::string l = results.top(); std::string r = next_result(b,e); results.pop(); results.push(mut(l,r)); break; } case '/':{ std::string l = results.top(); std::string r = next_result(b,e); results.pop(); results.push(div(l,r)); break; } default:{ results.push(*b); break; } } } if(results.size() == 1){ return get_result(results.top()); } std::string result = results.top(); for(results.pop();!results.empty();results.pop()){ result = add(result,results.top()); } return result; } protected: void splite_functions(exp_list& exps,function_list& functions){ exp_item b = exps.begin(); exp_item e = exps.end(); for(exp_item it = std::find(b,e,"function"); it != e; it = std::find(b,e,"function")){ --it;--it;//skip op,get function name exp_item function_name = it; exp_list& function_exp = functions[*function_name]; it = std::find(it,e,"{"); exp_item ite = get_block_range(++it,e); function_exp.insert(function_exp.end(),function_name,++ite); exps.erase(function_name,ite); } } protected: /* parse the script */ void parse_script(const std::string& script,exp_list& results){ std::string::const_iterator b = script.begin(); std::string::const_iterator e = script.end(); std::string value; for(; b != e ;++b){ switch(*b){ case '\t': case '\n': case ' ':{ break; } case '&': case '|': case '!': case '[': case ']': case '<': case '>': case '=': case ';': case '(': case ')': case ',': case '{': case '}': case '+': case '-': case '*': case '/':{ if(!value.empty()) results.push_back(value); results.push_back(op_v(*b)); value.clear(); break; } default:{ value += *b; break; } } } } }; int main(int argc, char* argv[]){ std::string script = "d=(1+2+3+4) * 10 +(5+6+7+8+9+10)*10;\n" "a= 2*(3-4);\n" "c=a+d;\n" "test = function(x,y){\n" " result = 0;\n" " if((c & d) & 0){\n" " result = 1;\n" " }" " test = result + x + y;\n" "}\n" "for(b = 1; b < (100 - 99);b = b+ 1){\n" " a = a + b;\n" "}\n" "e = test(10,8);\n" "f = test(23,32);\n" "h = [1,12,4,a,b,c,{aa=1;bb = 2;}];\n" "i = {ia = 1; ib = a;ic = {ic1= 1; ic2 = 2;};};\n" "h@0 = 2;\n" "i.ia = c;\n" "i.ib = i.ib + i.ia;\n"; std::cout << script << std::endl; simple_script ss(script); ss.do_script(); std::list<std::string> param; param.push_back("("); param.push_back("46"); param.push_back(","); param.push_back("64"); param.push_back(")"); std::cout << ss.get_sub_result("test",param.begin(),param.end()) << std::endl; std::map<std::string,std::string> vals = ss.get_results(); std::map<std::string,std::string>::const_iterator b = vals.begin(); for(; b != vals.end();++b){ std::cout << b->first << "=" << b->second << std::endl; } return 0; }