diff --git a/apps/dsm/DSMChartReader.cpp b/apps/dsm/DSMChartReader.cpp index 7069e18d..94c89540 100644 --- a/apps/dsm/DSMChartReader.cpp +++ b/apps/dsm/DSMChartReader.cpp @@ -26,6 +26,7 @@ */ #include "DSMChartReader.h" #include "log.h" +#include "AmUtils.h" #include // dlopen & friends @@ -149,6 +150,39 @@ DSMFunction* DSMChartReader::functionFromToken(const string& str) { return NULL; } +bool DSMChartReader::forFromToken(DSMArrayFor& af, const string& token) { + string forhdr = token; + if (forhdr.length() < 2 || forhdr[0] != '(' || forhdr[forhdr.length()-1] != ')') { + ERROR("syntax error in 'for %s': expected 'for (x in array)'\n", + forhdr.c_str()); + return false; + } + forhdr = forhdr.substr(1, forhdr.length()-2); + // q&d + vector forh_v = explode(forhdr, " in "); + if (forh_v.size() != 2) { + ERROR("syntax error in 'for %s': expected 'for (x in array)' " + "or 'for (k,v in struct)'\n", + forhdr.c_str()); + return false; + } + + af.array_struct = forh_v[1]; + + vector kv = explode(forh_v[0], ","); + if (kv.size() == 2) { + af.k = kv[0]; + af.v = kv[1]; + DBG("for (%s,%s in %s) {\n", af.k.c_str(), af.v.c_str(), af.array_struct.c_str()); + } else { + af.k = forh_v[0]; + DBG("for (%s in %s) {\n", af.k.c_str(), af.array_struct.c_str()); + } + + + return true; +} + DSMCondition* DSMChartReader::conditionFromToken(const string& str, bool invert) { for (vector::iterator it= mods.begin(); it!= mods.end(); it++) { @@ -245,7 +279,7 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart, stack.push_back(new DSMTransition()); continue; } - + if (stack.empty()) { if (token == ";") continue; @@ -288,27 +322,27 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart, DSMConditionTree* ct = dynamic_cast(stack_top); if (ct) { if (token == "[") { - stack.push_back(new DSMConditionList()); - continue; - } + stack.push_back(new DSMConditionList()); + continue; + } if (token == "{") { stack.push_back(new ActionList(ActionList::AL_if)); continue; } - if (token == ";") { - stack.pop_back(); - ActionList* al = dynamic_cast(&(*stack.back())); - if (al) { - owner->transferElem(ct); - al->actions.push_back(ct); - DBG("Added DSMConditionTree to ActionList\n"); - } else { - ERROR("no ActionList for DSMConditionTree\n"); - delete al; - return false; - } + if (token == ";") { + stack.pop_back(); + ActionList* al = dynamic_cast(&(*stack.back())); + if (al) { + owner->transferElem(ct); + al->actions.push_back(ct); + DBG("Added DSMConditionTree to ActionList\n"); + } else { + ERROR("no ActionList for DSMConditionTree\n"); + delete al; + return false; + } continue; - } + } } State* state = dynamic_cast(stack_top); @@ -405,6 +439,26 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart, return false; } t->actions = al->actions; + } else if (al->al_type == ActionList::AL_for) { + DSMArrayFor* af = dynamic_cast(&(*stack.back())); + if (!af) { + ERROR("no DSMArrayFor for action list\n"); + delete al; + return false; + } + af->actions = al->actions; + + stack.pop_back(); + + ActionList* b_al = dynamic_cast(&(*stack.back())); + if (!b_al) { + ERROR("internal error: no ActionList for 'for'\n"); + return false; + } + b_al->actions.push_back(af); + DBG("} // end for (%s%s in %s) {\n", + af->k.c_str(), af->v.empty() ? "" : (","+af->v).c_str(), + af->array_struct.c_str()); } else { ERROR("internal: unknown transition list type\n"); } @@ -416,12 +470,23 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart, //token is condition tree stack.push_back(new DSMConditionTree()); continue; + } else if (token.substr(0, 3) == "for") { + // token is for loop + DSMArrayFor* af = new DSMArrayFor(); + if (token.length() > 3) { + if (!forFromToken(*af, token.substr(3))) + return false; + } + + stack.push_back(af); + continue; } else { DSMFunction* f = functionFromToken(token); if (f) { DBG("adding actions from function '%s'\n", f->name.c_str()); DBG("al.size is %zd before", al->actions.size()); - for (vector::iterator it=f->actions.begin(); it != f->actions.end(); it++) { + for (vector::iterator it=f->actions.begin(); + it != f->actions.end(); it++) { DSMElement* a = *it; owner->transferElem(a); al->actions.push_back(a); @@ -553,6 +618,31 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart, } continue; } + + DSMArrayFor* af = dynamic_cast(stack_top); + if (af) { + if (af->array_struct.length() || af->k.length()) { + // expecting body + if (token == "}") { + DBG("close for\n"); + ERROR("sounds wrong!!!\n"); + stack.pop_back(); + continue; + } + + if (token == "{") { + // start action list for 'for' + stack.push_back(new ActionList(ActionList::AL_for)); + continue; + } + } else { + if (!forFromToken(*af, token)) + return false; + } + + continue; + } + } for (vector::iterator it= diff --git a/apps/dsm/DSMChartReader.h b/apps/dsm/DSMChartReader.h index 03518775..366fe630 100644 --- a/apps/dsm/DSMChartReader.h +++ b/apps/dsm/DSMChartReader.h @@ -59,8 +59,9 @@ class ActionList : public DSMElement { AL_exit, AL_trans, AL_if, - AL_else, - AL_func + AL_else, + AL_func, + AL_for }; AL_type al_type; @@ -87,6 +88,7 @@ class DSMChartReader { DSMFunction* functionFromToken(const string& str); DSMAction* actionFromToken(const string& str); DSMCondition* conditionFromToken(const string& str, bool invert); + bool forFromToken(DSMArrayFor& af, const string& token); bool importModule(const string& mod_cmd, const string& mod_path); vector mods; diff --git a/apps/dsm/DSMStateEngine.cpp b/apps/dsm/DSMStateEngine.cpp index 47295f1d..2de1cfa0 100644 --- a/apps/dsm/DSMStateEngine.cpp +++ b/apps/dsm/DSMStateEngine.cpp @@ -264,6 +264,7 @@ bool DSMStateEngine::runactions(vector::iterator from, default: break; } } + continue; } DSMConditionTree* cond_tree = dynamic_cast(*it); @@ -285,8 +286,104 @@ bool DSMStateEngine::runactions(vector::iterator from, sess, sc_sess, event, event_params, is_consumed)) return true; } + continue; } + DSMArrayFor* array_for = dynamic_cast(*it); + if (array_for) { + DBG("running for (%s%s in %s) {\n", + array_for->k.c_str(), array_for->v.empty() ? "" : (","+array_for->v).c_str(), + array_for->array_struct.c_str()); + + string array_name = array_for->array_struct; + string k_name = array_for->k; + string v_name = array_for->v; + + if (!array_name.length() || !k_name.length()) { + WARN("empty array or counter name in for\n"); + continue; + } + + if (array_name[0] == '$') array_name.erase(0, 1); + if (k_name[0] == '$') k_name.erase(0, 1); + bool is_kv = !v_name.empty(); + if (is_kv && v_name[0] == '$') v_name.erase(0, 1); + + + vector > cnt_values; + + // get the counter values + if (is_kv) { + VarMapT::iterator lb = sc_sess->var.lower_bound(array_name); + while (lb != sc_sess->var.end()) { + if ((lb->first.length() < array_name.length()) || + strncmp(lb->first.c_str(), array_name.c_str(), array_name.length())) + break; + + string varname = lb->first.substr(array_name.length()+1); + string valname = lb->second; + cnt_values.push_back(make_pair(varname, valname)); + DBG(" '%s,%s'\n", varname.c_str(), valname.c_str()); + lb++; + } + } else { + unsigned int a_index = 0; + while (true) { + VarMapT::iterator v = sc_sess->var.find(array_name+"["+int2str(a_index)+"]"); + if (v == sc_sess->var.end()) + break; + cnt_values.push_back(make_pair(v->second, "")); + DBG(" '%s'\n", v->second.c_str()); + a_index++; + } + } + + // save counter + VarMapT::iterator c_it = sc_sess->var.find(k_name); + bool k_exists = c_it != sc_sess->var.end(); + string k_save = k_exists ? c_it->second : string(""); + + bool v_exists = false; string v_save; + if (is_kv) { + c_it = sc_sess->var.find(v_name); + v_exists = c_it != sc_sess->var.end(); + if (v_exists) + v_save = c_it->second; + } + + // run the loop + DBG("running for loop with %zd items\n", cnt_values.size()); + for (vector >::iterator f_it= + cnt_values.begin(); f_it != cnt_values.end(); f_it++) { + if (is_kv) { + DBG("setting $%s=%s, $%s=%s\n", k_name.c_str(), f_it->first.c_str(), + v_name.c_str(), f_it->second.c_str()); + sc_sess->var[k_name] = f_it->first; + sc_sess->var[v_name] = f_it->second; + } else { + DBG("setting $%s=%s\n", k_name.c_str(), f_it->first.c_str()); + sc_sess->var[k_name] = f_it->first; + } + runactions(array_for->actions.begin(), array_for->actions.end(), + sess, sc_sess, event, event_params, is_consumed); + } + // restore the counter[s] + if (k_exists) + sc_sess->var[k_name] = k_save; + else + sc_sess->var.erase(k_name); + + if (is_kv) { + if (v_exists) + sc_sess->var[v_name] = v_save; + else + sc_sess->var.erase(v_name); + } + + continue; + } + + ERROR("DSMElement typenot understood\n"); } return false; } diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h index c2150d42..97edd2fa 100644 --- a/apps/dsm/DSMStateEngine.h +++ b/apps/dsm/DSMStateEngine.h @@ -177,6 +177,15 @@ class DSMFunction vector actions; }; +class DSMArrayFor +: public DSMElement { + public: + string k; // for(k in array) + string v; // if set, for(k,v in struct) + string array_struct; // array or struct name + vector actions; +}; + class DSMModule; class DSMStateDiagram {