From 638398785d624541bb8bd0c0f70b9eb3f8820e9b Mon Sep 17 00:00:00 2001 From: sbrandt Date: Mon, 4 Mar 2013 23:50:30 +0000 Subject: Significant upgrade of Piraha: It no longer uses strings to store intermediate values in expressions. It now supports everything that was supported by the old expression parser. Comments added. Numerous pieces of error checking added. git-svn-id: http://svn.cactuscode.org/flesh/trunk@4974 17b73243-c579-4c4c-a9d2-2d5706c11dac --- src/piraha/Call.cc | 838 ++++++++++++++++++++++++++++++++++++++--------- src/piraha/Makefile | 2 +- src/piraha/Matcher.cc | 5 +- src/piraha/Piraha.hpp | 8 +- src/piraha/smart_ptr.cc | 2 +- src/piraha/smart_ptr.hpp | 38 +-- 6 files changed, 715 insertions(+), 178 deletions(-) (limited to 'src') diff --git a/src/piraha/Call.cc b/src/piraha/Call.cc index 9df8fd10..ef981fd6 100644 --- a/src/piraha/Call.cc +++ b/src/piraha/Call.cc @@ -1,11 +1,14 @@ #include +#include #include #include "Piraha.hpp" #include #include +#include "cctk_core.h" #include "cctk_Parameter.h" #include #include +#include namespace piraha { @@ -13,168 +16,665 @@ namespace piraha { extern "C" int CCTK_ParameterFilename(int len, char *filename); -std::map > values; -typedef std::map >::iterator th_iter; -typedef std::map::iterator nm_iter; +/** + * This holds the structure required for parsing + * a Cactus par file. + */ +static smart_ptr par_file_grammar = new Grammar(); + +static std::string mklower(std::string& in) { + std::string s = in; + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + return s; +} + +enum ValueType { PIR_STRING,PIR_INT,PIR_REAL,PIR_BOOL,PIR_VOID }; + +std::string get_parfile() { + char path[500]; + CCTK_ParameterFilename(500, path); + char *value = strrchr (path, '/'); + if (value == NULL) { + value = path; + } else { + value++; + } + int n = strlen(value); + if(n > 4 && strcmp(value+n-4,".par")==0) { + value[n-4] = '\0'; + } + std::string s = value; + return s; +} + +std::ostream& operator<<(std::ostream& o,const ValueType& vt) { + if(vt == PIR_STRING) + o << "STRING"; + else if(vt == PIR_INT) + o << "INT"; + else if(vt == PIR_REAL) + o << "REAL"; + else if(vt == PIR_BOOL) + o << "BOOL"; + else if(vt == PIR_VOID) + o << "VOID"; + else + o << "UNDEF"; + return o; +} + +std::string current_thorn; + +/** + * The Value class is something like a union. It holds + * integer, real, and string data and has a type field + * that identifies which field is currently valid. + */ +struct Value { + /** This field holds the parse tree element associated with this Value. */ + smart_ptr hold; + double ddata; + int idata; + std::string sdata; + ValueType type; + Value(smart_ptr g) : hold(g), ddata(0), idata(0), sdata(), type(PIR_VOID) {} + ~Value() {} + /** + * Create a string representation of the Value. + */ + std::string copy() { + assert(type != PIR_VOID); + if(type == PIR_STRING) { + return sdata; + } else if(type == PIR_BOOL) { + std::string s = idata ? "yes" : "no"; + return s; + } else { + std::ostringstream o; + if(type == PIR_REAL) { + o << std::setprecision(15) << ddata; + } else { + o << idata; + } + return o.str(); + } + } + /** + * Check to see if something is a bool and throw an error + * if it's not. + */ + void checkBool() { + if(type != PIR_BOOL) { + std::ostringstream msg; + msg << "Does not evaluate to a boolean: " << hold->substring(); + std::string par = get_parfile(); + CCTK_Error(hold->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } + /** + * Compares with another Value, and throws a CCTK_Error + * if the comparison doesn't make sense. + */ + bool equals(smart_ptr v) { + if(type == PIR_BOOL && v->type == PIR_BOOL) { + return idata == v->idata; + } else if(type == PIR_INT && v->type == PIR_INT) { + return idata == v->idata; + } else if(type == PIR_INT && v->type == PIR_REAL) { + return idata == v->ddata; + } else if(type == PIR_REAL && v->type == PIR_INT) { + return ddata == v->idata; + } else if(type == PIR_REAL && v->type == PIR_REAL) { + return ddata == v->ddata; + } else if(type == PIR_STRING && v->type == PIR_STRING) { + return sdata == v->sdata; + } + std::ostringstream msg; + msg << "Cannot compare " << type << " and " << v->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(hold->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + /** + * Return a double value, whether the underlying + * quantity is integer or real. + */ + double doubleValue() { + if(type == PIR_REAL) + return ddata; + else if(type == PIR_INT) + return idata; + std::ostringstream msg; + msg << "Cannot convert " << type << " to double." << std::endl; + std::string par = get_parfile(); + CCTK_Error(hold->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + return 0; + } + bool intOrDouble() { + return type == PIR_INT || type == PIR_REAL; + } + /** + * This function converts a double to a real, but + * only if this can be done without loss of precision. + */ + void integerize() { + if(type == PIR_REAL) { + idata = ddata; + if(idata == ddata) { + type = PIR_INT; + } + } + } + void booleanize(smart_ptr gr) { + if(type == PIR_STRING) { + std::string s = mklower(sdata); + if(s == "yes" || s == "true") { + idata = 1; + type = PIR_BOOL; + } else if(s == "no" || s == "false") { + idata = 0; + type = PIR_BOOL; + } + } else if(type == PIR_INT) { + /// Steven R. Brandt would like to remove this + /// particular auto-conversion + if(idata == 1 || idata == 0) { + type = PIR_BOOL; + std::ostringstream msg; + msg << "Boolean variable is set with integer: " << gr->substring() << std::endl; + std::string par = get_parfile(); + CCTK_Warn(1,gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } + } +}; + +std::ostream& operator<<(std::ostream& o,const smart_ptr& val) { + if(!val.valid()) { + return o << "NULL"; + } + o << "(" << val->type << ")"; + if(val->type == PIR_REAL) { + o << val->ddata; + } else if(val->type == PIR_INT) { + o << val->idata; + } else if(val->type == PIR_BOOL) { + o << (val->idata ? "true" : "false"); + } else if(val->type == PIR_STRING) { + o << "\"" << val->sdata << "\""; + } else { + o << val->hold->substring(); + } + return o; +} + +std::map > > values; +typedef std::map > >::iterator th_iter; +typedef std::map >::iterator nm_iter; + +smart_ptr eval_expr(std::string inp); // If the value was already defined in this parameter file, look // it up in the map. Otherwise, get it from Cactus. -bool find_val(std::string thorn,std::string name,std::string& ret) { +smart_ptr find_val(std::string thorn,std::string name) { + smart_ptr ret; th_iter th = values.find(thorn); if(th != values.end()) { nm_iter nm = th->second.find(name); if(nm != th->second.end()) { ret = nm->second; - return true; + return ret; } } const cParamData *data = CCTK_ParameterData(name.c_str(),thorn.c_str()); - if(data == NULL) - return false; - ret = data->defval; - return true; + if(data != NULL) { + std::string expr = data->defval; + ret = eval_expr(expr); + } + return ret; } -bool lookup_var(smart_ptr gr,std::string& res) { +smart_ptr lookup_var(smart_ptr gr) { + smart_ptr ret; if(gr->group(0)->getPatternName() == "env") { const char *env = getenv(gr->group(0)->group(0)->substring().c_str()); if(env != NULL) { - res = env; - return true; + ret = new Value(gr); + ret->type = PIR_STRING; + ret->sdata = env; } } else if(gr->group(0)->substring() == "parfile") { - char path[500]; - CCTK_ParameterFilename(500, path); - char *value = strrchr (path, '/'); - if (value == NULL) { - value = path; - } else { - value++; - } - /* skip the parameter file extension */ - if (strcmp (value + strlen (value) - 4, ".par") == 0) - { - value[strlen (value) - 4] = '\0'; - } - res = value; - return true; + ret = new Value(gr); + ret->type = PIR_STRING; + ret->sdata = get_parfile(); } else if(gr->group(0)->substring() == "pi") { - std::ostringstream ostr; - ostr << (4.0*atan2(1.,1.)) << std::flush; - res = ostr.str(); - return true; + ret = new Value(gr); + ret->type = PIR_REAL; + ret->ddata = 4.0*atan2(1.0,1.0); + } + if(!ret.valid()) { + std::ostringstream msg; + msg << "Unknown variable: " << gr->substring() << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); } - return false; + return ret; } -// Converts a value to a string -void meval(smart_ptr gr,std::string& val) { - val.clear(); - if(gr->getPatternName() == "value" || gr->getPatternName() == "paren") { - meval(gr->group(0),val); - } else if(gr->getPatternName() == "quot") { - smart_ptr inquot = gr->group(0); - val = inquot->substring(); - int last = 0; - std::string nw; - for(int i=0;i < inquot->groupCount();i++) { - smart_ptr vr = inquot->group(i); - std::string sub; - if(lookup_var(vr,sub)) { - int start = vr->start() - inquot->start(); - nw += val.substr(last,start-last); - nw += sub; - last = vr->end() - inquot->start(); +/** + * The meval() function takes any node within + * the parse tree and creates a Value object + * from it. It is, therefore, designed to be + * used recursively. + **/ +smart_ptr meval(smart_ptr gr) { + assert(gr.valid()); + std::string pn = gr->getPatternName(); + smart_ptr ret = new Value(gr); + if(pn == "num") { + std::string s = gr->substring(); + ret->ddata = atof(s.c_str()); + ret->idata = ret->ddata; + if(ret->idata == ret->ddata && (s.find('.') == std::string::npos)) + ret->type = PIR_INT; + else + ret->type = PIR_REAL; + } else if(pn == "paren" || pn == "parindex") { + return meval(gr->group(0)); + } else if(pn == "func") { + std::string fn = gr->group(0)->substring(); + fn = mklower(fn); + smart_ptr val = meval(gr->group(1)); + if(val->type == PIR_REAL || val->type == PIR_INT) { + if(fn == "trunc") { + val->ddata = trunc(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "floor") { + val->ddata = floor(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "ceil") { + val->ddata = ceil(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "sqrt") { + val->ddata = sqrt(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "atan") { + val->ddata = atan(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "sin") { + val->ddata = sin(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "cos") { + val->ddata = cos(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "tan") { + val->ddata = tan(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "exp") { + val->ddata = exp(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "log") { + val->ddata = log(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "abs") { + val->ddata = fabs(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "acos") { + val->ddata = acos(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "asin") { + val->ddata = asin(val->doubleValue()); + val->type = PIR_REAL; + return val; + } else if(fn == "bool") { + if(val->type == PIR_REAL) { + val->idata = val->ddata; + } + val->type = PIR_BOOL; + return val; + } else if(fn == "int") { + if(val->type == PIR_REAL) { + val->idata = val->ddata; + val->type = PIR_INT; + } + return val; + } else if(fn == "real") { + if(val->type == PIR_INT) { + val->ddata = val->idata; + val->type = PIR_REAL; + } + return val; } + } else if(val->type == PIR_BOOL) { + if(fn == "int") { + val->type = PIR_INT; + return val; + } else if(fn == "real") { + val->type = PIR_REAL; + val->ddata = val->idata; + return val; + } + } + std::ostringstream msg; + msg << "Unknown func: " << fn << "(" << val->type << ")" << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } else if(pn == "name") { + std::string s = gr->substring(); + s = mklower(s); + if(s == "no" || s == "false") { + ret->type = PIR_BOOL; + ret->idata = 0; + } else if(s == "yes" || s == "true") { + ret->type = PIR_BOOL; + ret->idata = 1; + } else { + ret->type = PIR_STRING; + ret->sdata = gr->substring(); } - if(last < val.size()) - nw += val.substr(last,val.size()-last); - val = nw; - } else if(gr->getPatternName() == "par") { + return ret; + } else if(pn == "par") { std::string thorn = gr->group(0)->substring(); std::string name = gr->group(1)->substring(); - - bool found = find_val(thorn,name,val); - if(found) { - ; + if(gr->groupCount() == 3) { + std::ostringstream vn; + smart_ptr index = meval(gr->group(2)); + if(index->type == PIR_INT) { + std::stringstream o; + o << name << "[" << index->idata << "]"; + o << std::flush; + std::string keyi = o.str(); + ret = find_val(thorn,keyi); + return ret; + } } else { - val += thorn; - val += "::"; - val += name; - } - } else if(gr->getPatternName() == "name") { - val += gr->substring(); - } else if(gr->getPatternName() == "num") { - val += gr->substring(); - } else if(gr->getPatternName() == "var") { - lookup_var(gr,val); - } else if(gr->getPatternName() == "mexpr") { - if(gr->groupCount()==1) { - meval(gr->group(0),val); - return; + ret = find_val(thorn,name); + return ret; } - std::string val2; - meval(gr->group(0),val2); - double v2 = atof(val2.c_str()); - for(int i=1;i < gr->groupCount();i += 2) { - std::string val3; - meval(gr->group(i+1),val3); - double v3 = atof(val3.c_str()); - if(gr->group(i)->substring() == "*") { - v2 *= v3; + std::ostringstream msg; + msg << "Unknown par: " << thorn << "::" << name << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } else if(pn == "var") { + ret = lookup_var(gr); + } else if(pn == "value") { + if(gr->groupCount()==2) { + std::string unop = gr->group(0)->substring(); + ret = meval(gr->group(1)); + if(unop == "-") { + if(ret->type == PIR_INT) { + ret->idata = -ret->idata; + } else if(ret->type == PIR_REAL) { + ret->ddata = -ret->ddata; + } else { + std::ostringstream msg; + msg << "Unknown operation: " << unop << ret->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else if(unop == "!") { + if(ret->type == PIR_BOOL) { + ret->idata = !ret->idata; + } else { + std::ostringstream msg; + msg << "Unknown operation: " << unop << ret->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } } else { - v2 /= v3; + std::ostringstream msg; + msg << "Unknown operation: " << unop << ret->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); } -// std::cout << "MEXPR: " << v2 << gr->group(i)->substring() << v3 << std::endl; + } else { + return meval(gr->group(0)); } - std::ostringstream ostr; - ostr << v2 << std::flush; - val = ostr.str(); - } else if(gr->getPatternName() == "aexpr") { - if(gr->groupCount()==1) { - meval(gr->group(0),val); - return; + } else if(pn == "quot") { + ret->type = PIR_STRING; + ret->sdata = gr->group(0)->substring(); + } else if(pn == "inquot") { + ret->type = PIR_STRING; + ret->sdata = gr->substring(); + } else if(pn == "expr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + smart_ptr v2 = meval(gr->group(1)); + v1->checkBool(); + v2->checkBool(); + ret->type = PIR_BOOL; + ret->idata = v1->idata || v2->idata; + } else if(pn == "powexpr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + smart_ptr v2 = meval(gr->group(1)); + ret->type = PIR_REAL; + ret->ddata = pow(v1->doubleValue(),v2->doubleValue()); + } else if(pn == "andexpr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + smart_ptr v2 = meval(gr->group(1)); + v1->checkBool(); + v2->checkBool(); + ret->type = PIR_BOOL; + ret->idata = v1->idata && v2->idata; + } else if(pn == "eqexpr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + std::string eqop = gr->group(1)->substring(); + smart_ptr v2 = meval(gr->group(2)); + ret->type = PIR_BOOL; + if(eqop == "==") { + ret->idata = v1->equals(v2); + } else if(eqop == "!=") { + ret->idata = !v1->equals(v2); + } else { + std::ostringstream msg; + msg << "Unknown equality operator: " << eqop << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); } - std::string val2; - meval(gr->group(0),val2); - double v2 = atof(val2.c_str()); - for(int i=1;i < gr->groupCount();i += 2) { - std::string val3; - meval(gr->group(i+1),val3); - double v3 = atof(val3.c_str()); - if(gr->group(i)->substring() == "+") { - v2 += v3; + } else if(pn == "compexpr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + if(gr->groupCount()>0) { + std::string compop = gr->group(1)->substring(); + smart_ptr v2 = meval(gr->group(2)); + double d1 = v1->doubleValue(); + double d2 = v2->doubleValue(); + ret->type = PIR_BOOL; + if(compop == "<") { + ret->idata = (d1 < d2); + return ret; + } else if(compop == ">") { + ret->idata = (d1 > d2); + return ret; + } else if(compop == "<=") { + ret->idata = (d1 <= d2); + return ret; + } else if(compop == ">=") { + ret->idata = (d1 >= d2); + return ret; + } + std::ostringstream msg; + msg << "Unknown comparison operator: " << compop << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else if(pn == "aexpr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + for(int i=1;i+1groupCount();i+=2) { + std::string addop = gr->group(i)->substring(); + smart_ptr v2 = meval(gr->group(i+1)); + assert(v2.valid()); + if(v1->type == PIR_INT && v2->type == PIR_INT) { + ret->type = PIR_INT; + if(addop == "+") { + ret->idata = v1->idata + v2->idata; + } else if(addop == "-") { + ret->idata = v1->idata - v2->idata; + } else { + std::ostringstream msg; + msg << "Unknown add operator: " << addop << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else if(v1->type == PIR_STRING && v2->type == PIR_STRING) { + ret->type = PIR_STRING; + if(addop == "+") { + ret->sdata = v1->sdata + v2->sdata; + } else { + std::ostringstream msg; + msg << "Unknown add operator: " << addop << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else if(v1->intOrDouble() && v2->intOrDouble()) { + ret->type = PIR_REAL; + if(addop == "+") { + ret->ddata = v1->doubleValue()+v2->doubleValue(); + } else if(addop == "-") { + ret->ddata = v1->doubleValue()-v2->doubleValue(); + } else { + std::ostringstream msg; + msg << "Unknown add operator: " << addop << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } } else { - v2 -= v3; + std::ostringstream msg; + msg << "Unknown operation: " << v1->type; + msg << " " << addop << v2->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); } -// std::cout << "AEXPR: " << v2 << gr->group(i)->substring() << v3 << std::endl; + v1 = ret; } - std::ostringstream ostr; - ostr << v2 << std::flush; - val = ostr.str(); - } else if(gr->getPatternName() == "func") { - std::string func_name = gr->group(0)->substring(); - std::string arg; - meval(gr->group(1),arg); - std::stringstream ostr; - if(func_name == "sin") { - ostr << sin(atof(arg.c_str())); - } else if(func_name == "cos") { - ostr << cos(atof(arg.c_str())); - } else if(func_name == "sqrt") { - ostr << sqrt(atof(arg.c_str())); - } else if(func_name == "tan") { - ostr << tan(atof(arg.c_str())); - } else if(func_name == "log") { - ostr << log(atof(arg.c_str())); - } else if(func_name == "exp") { - ostr << exp(atof(arg.c_str())); + } else if(pn == "mexpr") { + if(gr->groupCount()==1) + return meval(gr->group(0)); + smart_ptr v1 = meval(gr->group(0)); + for(int i=1;i+1groupCount();i+=2) { + std::string mulop = gr->group(i)->substring(); + smart_ptr v2 = meval(gr->group(i+1)); + if(v1->type == PIR_INT && v2->type == PIR_INT) { + ret->type = PIR_INT; + if(mulop == "*") { + ret->idata = v1->idata * v2->idata; + } else if(mulop == "/") { + ret->idata = v1->idata / v2->idata; + } else if(mulop == "%") { + ret->idata = v1->idata % v2->idata; + } else { + std::ostringstream msg; + msg << "Unknown mul operator: " << v1->type << mulop << v2->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else if(v1->type == PIR_STRING && v2->type == PIR_INT) { + ret->type = PIR_STRING; + if(mulop == "*") { + ret->sdata = v1->sdata + v2->sdata; + } else { + std::ostringstream msg; + msg << "Unknown mul operator: " << v1->type << mulop << v2->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else if(v1->intOrDouble() && v2->intOrDouble()) { + ret->type = PIR_REAL; + if(mulop == "*") { + ret->ddata = v1->doubleValue()*v2->doubleValue(); + } else if(mulop == "/") { + ret->ddata = v1->doubleValue()/v2->doubleValue(); + } else { + std::ostringstream msg; + msg << "Unknown mul operator: " << v1->type << mulop << v2->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + } else { + std::ostringstream msg; + msg << "Unknown operation: " << v1->type << " " << mulop << v2->type << std::endl; + std::string par = get_parfile(); + CCTK_Error(gr->line(),par.c_str(),current_thorn.c_str(),msg.str().c_str()); + } + v1 = ret; } - ostr << std::flush; - val = ostr.str(); } else { - std::cout << "Not handled[" << gr->getPatternName() << "]" << std::endl; - abort(); + std::ostringstream msg; + std::string par = get_parfile(); + msg << "Pattern not handled[" << gr->getPatternName() << "]=" << gr->substring() << + " at " << gr->line() << " in " << par << std::endl; + CCTK_Error(__LINE__,__FILE__,"piraha",msg.str().c_str()); + } + return ret; +} + + +smart_ptr eval_expr(std::string input) { + smart_ptr m = new Matcher(par_file_grammar,"eval",input.c_str()); + smart_ptr ret; + if(m->matches()) { + ret = meval(m->group(0)); + } + return ret; +} + +void check_types(const char *thorn,int line,ValueType v,int t) { + bool ok = false; + if(v == PIR_STRING && (t == PARAMETER_STRING || t == PARAMETER_KEYWORD)) + ok = true; + else if(v == PIR_INT && t == PARAMETER_INT) + ok = true; + else if(v == PIR_BOOL && t == PARAMETER_BOOLEAN) + ok = true; + else if((v == PIR_INT || v == PIR_REAL) && t == PARAMETER_REAL) + ok = true; + if(!ok) { + std::string par = get_parfile(); + std::ostringstream msg; + msg << "Parameter type mismatch "; + switch(t) { + case PARAMETER_BOOLEAN: + msg << "BOOL"; + break; + case PARAMETER_INT: + msg << "INT"; + break; + case PARAMETER_KEYWORD: + msg << "KEYWORD"; + break; + case PARAMETER_STRING: + msg << "STRING"; + break; + case PARAMETER_REAL: + msg << "REAL"; + break; + default: + msg << "type(" << t << ")"; + break; + } + msg << " != " << v << std::endl; + CCTK_Error(line,par.c_str(),thorn,msg.str().c_str()); } } @@ -190,39 +690,49 @@ extern "C" int cctk_PirahaParser(const char *buffer,unsigned long buffersize,int "inquot = ({var}|\\\\.|[^\\\\\"])*\n" "fname = \\.?/[-\\./0-9a-zA-Z_]+\n" "quot = \"{inquot}\"|{fname}\n" - "num = [-+]?([0-9]+(\\.[0-9]*|)|\\.[0-9]+)(e[+-]?[0-9]+|)\n" + "num = (inf|([0-9]+(\\.[0-9]*|)|\\.[0-9]+)(e[+-]?[0-9]+|))\n" "env = ENV\\{{name}\\}\n" "var = \\$({env}|{name}|\\{{name}\\})\n" - "mulop = [*/]\n" - "mexpr = {value}( {mulop} {value})*\n" + "powexpr = {value}( \\*\\* {value})?\n" + "mulop = [*/%]\n" + "mexpr = {powexpr}( {mulop} {powexpr})*\n" "addop = [+-]\n" "aexpr = {mexpr}( {addop} {mexpr})*\n" - "paren = \\( {aexpr} \\)\n" - "par = {name} :: {name}\n" - "func = {name} \\( {aexpr} \\)\n" - "array = \\[ {aexpr}( , {aexpr})* \\]\n" + "compop = [<>]=?\n" + "compexpr = {aexpr}( {compop} {aexpr})?\n" + "eqop = [!=]=\n" + "eqexpr = {compexpr}( {eqop} {eqexpr})?\n" + "andexpr = {eqexpr}( && {eqexpr})?\n" + "expr = {andexpr}( \\|\\| {andexpr})?\n" + "eval = {expr}\n" - "value = {func}|{paren}|{num}|{quot}|{par}|{name}|{var}\n" + "paren = \\( {expr} \\)\n" + "par = {name} :: {name}( {parindex})?\n" + "func = {name} \\( {expr} \\)\n" + "array = \\[ {expr}( , {expr})* \\]\n" + + "value = {unop}?({par}|{func}|{paren}|{num}|{quot}|{name}|{var})\n" + "unop = [-!]\n" "int = [0-9]+\n" "index = \\[ {int} \\]\n" + "parindex = \\[ {expr} \\]\n" "active = (?i:ActiveThorns)\n" - "set = ({active}|{par}( {index}|)) = ({array}|{aexpr}){-skipeol}\n" - "file = ( !DESC {quot}|)( ({set} )*)$\n"; + "set = ({active} = ({quot}|{name})|{par}( {index}|) = ({array}|\\+?{expr})){-skipeol}\n" + "file = ^( !DESC {quot}|)( ({set}|{active}) )*$\n"; - smart_ptr g = new Grammar(); - compileFile(g,par_file_src,strlen(par_file_src)); + compileFile(par_file_grammar,par_file_src,strlen(par_file_src)); std::string active; - smart_ptr m2 = new Matcher(g,"file",buffer,buffersize); + smart_ptr m2 = new Matcher(par_file_grammar,"file",buffer,buffersize); if(m2->matches()) { int line = -1; for(int i=0;igroupCount();i++) { smart_ptr gr = m2->group(i); if(gr->group(0)->getPatternName() == "active") { - std::string val; - meval(gr->group(1),val); + smart_ptr smv = meval(gr->group(1)); + std::string val = smv->copy(); active += val; active += ' '; line = gr->line(); @@ -242,19 +752,40 @@ extern "C" int cctk_PirahaParser(const char *buffer,unsigned long buffersize,int key += thorn; key += "::"; key += name; + const cParamData *data = CCTK_ParameterData(name.c_str(),thorn.c_str()); - smart_ptr index = gr->group("index"); + smart_ptr index = par->group("parindex"); if(index.valid()) { key += '['; - key += index->group(0)->substring(); + smart_ptr vv = meval(index); + if(vv->type != PIR_INT) { + std::ostringstream msg; + std::string par = get_parfile(); + msg << "bad index " << vv << std::endl; + CCTK_Error(index->line(),par.c_str(),thorn.c_str(),msg.str().c_str()); + } + std::string vvstr = vv->copy(); + key += vvstr; key += ']'; } std::string val; - smart_ptr aexpr = gr->group("aexpr"); + smart_ptr aexpr = gr->group("expr"); if(aexpr.valid()) { - meval(aexpr,val); - values[thorn][key] = val; + current_thorn = thorn; + smart_ptr smv = meval(aexpr); + val = smv->copy(); + assert(smv.valid()); + values[thorn][key] = smv; + std::cout << "set_function(" << key << "," << val << ")" << std::endl; + smv->integerize(); + if(data != NULL) { + if(data->type == PARAMETER_REAL) + smv->integerize(); + if(data->type == PARAMETER_BOOLEAN) + smv->booleanize(gr); + check_types(thorn.c_str(),aexpr->line(),smv->type,data->type); + } set_function( strdup(key.c_str()), strdup(val.c_str()), @@ -264,9 +795,18 @@ extern "C" int cctk_PirahaParser(const char *buffer,unsigned long buffersize,int for(int i=0;igroupCount();i++) { aexpr = arr->group(i); std::ostringstream keyi; - keyi << key << '[' << (i+1) << ']'; - meval(aexpr,val); - values[thorn][keyi.str()] = val; + keyi << key << '[' << i << ']'; + smart_ptr smv = meval(aexpr); + val = smv->copy(); + values[thorn][keyi.str()] = smv; + std::cout << "set_function_array(" << keyi.str() << "," << val << ")" << std::endl; + if(data != NULL) { + if(data->type == PARAMETER_REAL) + smv->integerize(); + if(data->type == PARAMETER_BOOLEAN) + smv->booleanize(gr); + check_types(thorn.c_str(),aexpr->line(),smv->type,data->type); + } set_function( strdup(keyi.str().c_str()), strdup(val.c_str()), @@ -276,7 +816,7 @@ extern "C" int cctk_PirahaParser(const char *buffer,unsigned long buffersize,int } } } else { - std::cout << "ERROR IN PARAMETER FILE: "; + std::cout << "ERROR IN PARAMETER FILE:" << std::endl; m2->showError(); return 1; } diff --git a/src/piraha/Makefile b/src/piraha/Makefile index 7528fc54..45e4f4dc 100644 --- a/src/piraha/Makefile +++ b/src/piraha/Makefile @@ -1,7 +1,7 @@ # Build the standalone tool # CXX = g++ -CXXFLAGS = -Wall +CXXFLAGS = -Wall -Wreturn-type SRCS = AutoGrammar.cc Bracket.cc Dot.cc End.cc \ Generic.cc Grammar.cc Group.cc ILiteral.cc \ Literal.cc Lookup.cc Matcher.cc Multi.cc \ diff --git a/src/piraha/Matcher.cc b/src/piraha/Matcher.cc index dad67a67..55f042be 100644 --- a/src/piraha/Matcher.cc +++ b/src/piraha/Matcher.cc @@ -16,6 +16,7 @@ bool Matcher::matches() { smart_ptr p = g->patterns.get(pat); if(!p.valid()) { std::cout << "Grammar does not contain \"" << pat << "\"" << std::endl; + std::cout << g->patterns << std::endl; } assert(p.valid()); pos = 0; @@ -53,9 +54,9 @@ void Matcher::showError() { start_of_previous_line[i] = 0; for(int i=0;ifirst << "]"; } + o << "}"; return o; } diff --git a/src/piraha/smart_ptr.cc b/src/piraha/smart_ptr.cc index e1d26b71..b2e5a826 100644 --- a/src/piraha/smart_ptr.cc +++ b/src/piraha/smart_ptr.cc @@ -1,3 +1,3 @@ #include "smart_ptr.hpp" -std::vector ptrs; +std::set *ptrs = new std::set(); diff --git a/src/piraha/smart_ptr.hpp b/src/piraha/smart_ptr.hpp index 0ac761b3..2c6f7d28 100644 --- a/src/piraha/smart_ptr.hpp +++ b/src/piraha/smart_ptr.hpp @@ -7,40 +7,32 @@ #ifndef SMART_PTR_HPP #define SMART_PTR_HPP #include -#include +#include #include #ifndef NULL #define NULL ((void*)0) #endif -extern std::vector ptrs; +extern std::set *ptrs; -#ifndef NDEBUG -inline void add(std::vector& v,void *t) { +#ifdef NDEBUG +inline void add(std::set& v,void *t) { if(t == NULL) return; - for(std::vector::iterator i=v.begin();i != v.end();++i) { - assert(*i != t); - } - v.push_back(t); + assert(v.find(t) == v.end()); + v.insert(t); } -inline void remove(std::vector& v,void* t) { - if(t == NULL) - return; - for(std::vector::iterator i=v.begin();i != v.end();++i) { - if(*i == t) { - v.erase(i); - return; - } - } - assert(false); +inline void remove(std::set& v,void* t) { + std::set::iterator it = v.find(t); + assert(it != v.end()); + v.erase(it); } #else -inline void add(std::vector& v,void* t) { +inline void add(std::set& v,void* t) { } -inline void remove(std::vector& v,void* t) { +inline void remove(std::set& v,void* t) { } #endif @@ -55,12 +47,12 @@ class smart_ptr_guts { bool array; smart_ptr_guts(int rc,T *p,bool array_) : ref_count(rc), ptr(p), array(array_) { if(ptr != NULL) { - add(ptrs,(void*)ptr); + add(*ptrs,(void*)ptr); } } ~smart_ptr_guts() { if(ptr != NULL) { - remove(ptrs,(void*)ptr); + remove(*ptrs,(void*)ptr); if(array) delete[] ptr; else @@ -155,7 +147,7 @@ class smart_ptr { assert(guts != NULL); return guts->ptr; } - bool valid() { + bool valid() const { return guts != NULL && guts->ptr != NULL; } int ref_count() { -- cgit v1.2.3