Merge branch 'dsm_lang'

* dsm_lang:
  DSM: support variables in range, e.g. range($myvar)
  DSM: size($arrayname, $dst) action
  added [] to chars not allowed in var names
  DSM: fix for ($bar in array) for structs
  DSM: parsing of "else", if conditions without []
  DSM: implement for ($x in range(2, 5))
  DSM: "for (x in array)" and "for (k,v in struct)"
  dsm: execution reordered (small optimization)
  reindent
  reindent
  implementation of functions in DSM
  initial support for if blocks (no else)
sayer/1.4-spce2.6
Stefan Sayer 15 years ago
commit a533fdcb5e

@ -26,12 +26,16 @@
*/
#include "DSMChartReader.h"
#include "log.h"
#include "AmUtils.h"
#include <dlfcn.h> // dlopen & friends
#include <vector>
using std::vector;
#include <string>
using std::string;
DSMChartReader::DSMChartReader() {
}
@ -43,7 +47,7 @@ bool DSMChartReader::is_wsp(const char c) {
}
bool DSMChartReader::is_snt(const char c) {
return c== ';' || c == '{' || c == '}';
return c== ';' || c == '{' || c == '}' || c == '[' || c == ']';
}
string DSMChartReader::getToken(string str, size_t& pos) {
@ -128,6 +132,74 @@ DSMAction* DSMChartReader::actionFromToken(const string& str) {
return NULL;
}
DSMFunction* DSMChartReader::functionFromToken(const string& str) {
string cmd;
size_t b_pos = str.find('(');
if (b_pos != string::npos) {
cmd = str.substr(0, b_pos);
} else {
return NULL;
}
for (vector<DSMFunction*>::iterator it=funcs.begin(); it!= funcs.end(); it++) {
if((*it)->name == cmd) {
DBG("found function '%s' in fuction list\n", cmd.c_str());
return *it;
}
}
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<string> 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;
}
vector<string> kv = explode(forh_v[0], ",");
if (kv.size() == 2) {
af.for_type = DSMArrayFor::Struct;
af.k = kv[0];
af.v = kv[1];
af.array_struct = forh_v[1];
DBG("for (%s,%s in %s) {\n", af.k.c_str(), af.v.c_str(), af.array_struct.c_str());
} else if (forh_v[1].length() > 7 &&
forh_v[1].substr(0,6)=="range(" &&
forh_v[1][forh_v[1].length()-1] == ')') {
af.for_type = DSMArrayFor::Range;
string range_s = forh_v[1].substr(6, forh_v[1].length()-7);
vector<string> range_v = explode(range_s, ",");
if (range_v.size() == 2) {
af.v = trim(range_v[0], " ");
af.array_struct = trim(range_v[1], " ");
} else {
af.v = "0";
af.array_struct = trim(range_s, " ");
}
af.k = forh_v[0];
DBG("for (%s in range(%s, %s) {\n",
af.k.c_str(), af.v.c_str(), af.array_struct.c_str());
} else {
af.for_type = DSMArrayFor::Array;
af.array_struct = forh_v[1];
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<DSMModule*>::iterator it=
mods.begin(); it!= mods.end(); it++) {
@ -205,6 +277,11 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
continue;
}
if (token == "function") {
stack.push_back(new DSMFunction());
continue;
}
if (token == "initial") {
stack.push_back(new AttribInitial());
continue;
@ -219,16 +296,77 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
stack.push_back(new DSMTransition());
continue;
}
if (stack.empty()) {
if (token == ";")
continue;
continue;
ERROR("Without context I do not understand '%s'\n", token.c_str());
return false;
}
DSMElement* stack_top = &(*stack.back());
DSMFunction* f = dynamic_cast<DSMFunction*>(stack_top);
if (f) {
if (f->name.length()==0) {
size_t b_pos = token.find('(');
if (b_pos != string::npos) {
f->name = token.substr(0, b_pos);
continue;
} else {
ERROR("Parse error -- function declarations must have a name followed "
"by parentheses, e.g., 'function foo()'\n");
return false;
}
}
if (token == "{") {
stack.push_back(new ActionList(ActionList::AL_func));
continue;
}
if (token == ";") {
owner->transferElem(f);
funcs.push_back(f);
DBG("Adding DSMFunction '%s' to funcs\n", f->name.c_str());
continue;
}
DBG("Unknown token: %s\n", token.c_str());
return false;
}
DSMConditionTree* ct = dynamic_cast<DSMConditionTree*>(stack_top);
if (ct) {
if (token == "[") {
DSMConditionList* cl = new DSMConditionList();
cl->is_if = true;
stack.push_back(cl);
continue;
}
if (token == "{") {
stack.push_back(new ActionList(ActionList::AL_if));
continue;
}
if (token == ";" || token == "}") {
stack.pop_back();
ActionList* al = dynamic_cast<ActionList*>(&(*stack.back()));
if (al) {
owner->transferElem(ct);
al->actions.push_back(ct);
} else {
ERROR("no ActionList for DSMConditionTree\n");
delete al;
return false;
}
continue;
}
ERROR("syntax error: got '%s' without context\n", token.c_str());
return false;
}
State* state = dynamic_cast<State*>(stack_top);
if (state) {
if (!state->name.length()) {
@ -237,6 +375,7 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
continue;
}
if (token == "enter") {
DBG("adding 'enter' actions for state '%s'\n", state->name.c_str());
stack.push_back(new ActionList(ActionList::AL_enter));
continue;
}
@ -268,16 +407,64 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
}
if (token == "{") {
continue;
}
}
if ((token == "}") || (token == "->")) {
stack.pop_back();
if (stack.empty()) {
stack.pop_back();
if (stack.empty()) {
ERROR("no item for action list\n");
delete al;
return false;
}
if (al->al_type == ActionList::AL_func) {
DSMFunction* f = dynamic_cast<DSMFunction*>(&(*stack.back()));
if (!f) {
ERROR("no DSMFunction for action list\n");
delete al;
return false;
}
f->actions = al->actions;
delete al;
continue;
}
if (al->al_type == ActionList::AL_enter ||
if (al->al_type == ActionList::AL_if ||
al->al_type == ActionList::AL_else) {
DSMConditionTree* ct = dynamic_cast<DSMConditionTree*>(&(*stack.back()));
if (!ct) {
ERROR("no DSMConditionTree for action list\n");
delete al;
return false;
}
if (al->al_type == ActionList::AL_if)
ct->run_if_true = al->actions;
else
ct->run_if_false = al->actions;
stack.pop_back();
ActionList* al_parent = dynamic_cast<ActionList*>(&(*stack.back()));
if (al_parent) {
owner->transferElem(ct);
al_parent->actions.push_back(ct);
} else {
ERROR("no ActionList for DSMConditionTree\n");
delete al;
return false;
}
if (al->al_type == ActionList::AL_if)
DBG("} // end if\n");
else
DBG("} // end else\n");
delete al;
continue;
}
if (al->al_type == ActionList::AL_enter ||
al->al_type == ActionList::AL_exit) {
State* s = dynamic_cast<State*>(&(*stack.back()));
if (!s) {
@ -285,11 +472,17 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
delete al;
return false;
}
if (al->al_type == ActionList::AL_enter)
if (al->al_type == ActionList::AL_enter) {
s->pre_actions = al->actions;
else if (al->al_type == ActionList::AL_exit)
} else if (al->al_type == ActionList::AL_exit) {
s->post_actions = al->actions;
} else if (al->al_type == ActionList::AL_trans) {
}
delete al;
continue;
}
if (al->al_type == ActionList::AL_trans) {
DSMTransition* t = dynamic_cast<DSMTransition*>(&(*stack.back()));
if (!t) {
ERROR("no DSMTransition for action list\n");
@ -297,80 +490,177 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
return false;
}
t->actions = al->actions;
} else {
ERROR("internal: unknown transition list type\n");
delete al;
continue;
}
if (al->al_type == ActionList::AL_for) {
DSMArrayFor* af = dynamic_cast<DSMArrayFor*>(&(*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<ActionList*>(&(*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());
delete al;
continue;
}
ERROR("internal: unknown transition list type\n");
return false;
}
if (token == "if") {
DBG("if ...\n");
// start condition tree
stack.push_back(new DSMConditionTree());
DSMConditionList* cl = new DSMConditionList();
cl->is_if = true;
stack.push_back(cl);
continue;
}
if (token == "else") {
DBG(" ... else ...\n");
DSMConditionTree* ct = dynamic_cast<DSMConditionTree*>(al->actions.back());
if (NULL == ct) {
ERROR("syntax error: else without if block\n");
return false;
}
stack.push_back(ct);
stack.push_back(new ActionList(ActionList::AL_else));
al->actions.pop_back();
continue;
}
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;
}
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<DSMElement*>::iterator it=f->actions.begin();
it != f->actions.end(); it++) {
DSMElement* a = *it;
owner->transferElem(a);
al->actions.push_back(a);
}
delete al;
DBG("al.size is %zd after", al->actions.size());
continue;
}
// token is action
// DBG("adding action '%s'\n", token.c_str());
DBG("adding action '%s'\n", token.c_str());
DSMAction* a = actionFromToken(token);
if (!a)
return false;
owner->transferElem(a);
al->actions.push_back(a);
continue;
}
} // actionlist
DSMConditionList* cl = dynamic_cast<DSMConditionList*>(stack_top);
if (cl) {
if (token == ";")
continue;
if (token == ";" || token == "[")
continue;
if ((token == "{") || (token == "}")) {
// readability
continue;
}
if ((token == "/") || (token == "->")) {
// end of condition list
if (cl->is_if && token == "{") {
// end of condition list for if
stack.pop_back();
if (stack.empty()) {
ERROR("no transition to apply conditions to\n");
delete cl;
return false;
}
DSMTransition* tr = dynamic_cast<DSMTransition*>(&(*stack.back()));
if (!tr) {
ERROR("no transition to apply conditions to\n");
delete cl;
DSMConditionTree* ct = dynamic_cast<DSMConditionTree*>(&(*stack.back()));
if (!ct) {
ERROR("internal error: condition list without condition tree\n");
return false;
}
DBG("{\n");
ct->conditions = cl->conditions;
ct->is_exception = cl->is_exception;
stack.push_back(new ActionList(ActionList::AL_if));
continue;
}
tr->precond = cl->conditions;
tr->is_exception = cl->is_exception;
delete cl;
if ((token == "{") || (token == "}")) {
// readability
continue;
}
// start AL_trans action list
if (token == "/") {
stack.push_back(new ActionList(ActionList::AL_trans));
}
continue;
if ((token == "/") || (token == "->") || (token == "]")) {
// end of condition list
stack.pop_back();
if (stack.empty()) {
ERROR("nothing to apply conditions to\n");
delete cl;
return false;
}
DSMElement* el = &(*stack.back());
DSMTransition* tr = dynamic_cast<DSMTransition*>(el);
DSMConditionTree* ct = dynamic_cast<DSMConditionTree*>(el);
if (tr) {
tr->precond = cl->conditions;
tr->is_exception = cl->is_exception;
} else if (ct) {
ct->conditions = cl->conditions;
ct->is_exception = cl->is_exception;
} else {
ERROR("no transition or condition list to apply conditions to\n");
delete cl;
return false;
}
delete cl;
// start AL_trans action list
if (token == "/") {
stack.push_back(new ActionList(ActionList::AL_trans));
}
continue;
}
if (token == "not") {
cl->invert_next = !cl->invert_next;
continue;
cl->invert_next = !cl->invert_next;
continue;
}
if (token == "exception") {
cl->is_exception = true;
continue;
cl->is_exception = true;
continue;
}
// DBG("new condition: '%s'\n", token.c_str());
DBG("new condition: '%s'\n", token.c_str());
DSMCondition* c = conditionFromToken(token, cl->invert_next);
cl->invert_next = false;
if (!c)
return false;
return false;
owner->transferElem(c);
cl->conditions.push_back(c);
continue;
}
DSMTransition* tr = dynamic_cast<DSMTransition*>(stack_top);
if (tr) {
if (!tr->name.length()) {
@ -418,6 +708,31 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart,
}
continue;
}
DSMArrayFor* af = dynamic_cast<DSMArrayFor*>(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<DSMModule*>::iterator it=

@ -57,7 +57,11 @@ class ActionList : public DSMElement {
enum AL_type {
AL_enter,
AL_exit,
AL_trans
AL_trans,
AL_if,
AL_else,
AL_func,
AL_for
};
AL_type al_type;
@ -65,14 +69,15 @@ class ActionList : public DSMElement {
ActionList(AL_type al_type)
: al_type(al_type) { }
vector<DSMAction*> actions;
vector<DSMElement*> actions;
};
struct DSMConditionList : public DSMElement {
DSMConditionList() : invert_next(false), is_exception(false) { }
DSMConditionList() : invert_next(false), is_exception(false), is_if(false) { }
vector<DSMCondition*> conditions;
bool invert_next;
bool is_exception;
bool is_if;
};
class DSMChartReader {
@ -81,13 +86,17 @@ class DSMChartReader {
bool is_snt(const char c);
string getToken(string str, size_t& pos);
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<DSMModule*> mods;
DSMCoreModule core_mod;
vector<DSMFunction*> funcs;
public:
DSMChartReader();
~DSMChartReader();

@ -86,6 +86,7 @@ DSMAction* DSMCoreModule::getAction(const string& from_str) {
DEF_CMD("log", SCLogAction);
DEF_CMD("clear", SCClearAction);
DEF_CMD("clearArray", SCClearArrayAction);
DEF_CMD("size", SCSizeAction);
DEF_CMD("logVars", SCLogVarsAction);
DEF_CMD("logParams", SCLogParamsAction);
DEF_CMD("logSelects", SCLogSelectsAction);
@ -545,9 +546,9 @@ string replaceParams(const string& q, AmSession* sess, DSMSession* sc_sess,
res[rstart+1] == '"' ||
res[rstart+1] == '\''
))
rend = res.find_first_of(" ,()$#@\t;:'\"", rstart+2);
rend = res.find_first_of(" ,()[]$#@\t;:'\"", rstart+2);
else
rend = res.find_first_of(" ,()$#@\t;:'\"", rstart+1);
rend = res.find_first_of(" ,()[]$#@\t;:'\"", rstart+1);
if (rend==string::npos)
rend = res.length();
string keyname = res.substr(rstart+1, rend-rstart-1);
@ -691,6 +692,31 @@ EXEC_ACTION_START(SCClearArrayAction) {
} EXEC_ACTION_END;
CONST_ACTION_2P(SCSizeAction, ',', false);
EXEC_ACTION_START(SCSizeAction) {
string array_name = par1;
if (array_name.length() && array_name[0]=='$')
array_name.erase(0,1);
string dst_name = par2;
if (dst_name.length()&&dst_name[0]=='$')
dst_name.erase(0,1);
unsigned int a_size = 0;
while (true) {
string ai_name = array_name+"["+int2str(a_size)+"]";
VarMapT::iterator lb = sc_sess->var.lower_bound(ai_name);
if (lb == sc_sess->var.end() ||
lb->first.substr(0,ai_name.length()) != ai_name)
break;
a_size++;
}
string res = int2str(a_size);
sc_sess->var[dst_name] = res;
DBG("set $%s=%s\n", dst_name.c_str(), res.c_str());
} EXEC_ACTION_END;
CONST_ACTION_2P(SCAppendAction,',', false);
EXEC_ACTION_START(SCAppendAction) {

@ -84,6 +84,7 @@ DEF_ACTION_2P(SCSubStrAction);
DEF_ACTION_1P(SCIncAction);
DEF_ACTION_1P(SCClearAction);
DEF_ACTION_1P(SCClearArrayAction);
DEF_ACTION_2P(SCSizeAction);
DEF_ACTION_2P(SCSetTimerAction);
DEF_ACTION_1P(SCRemoveTimerAction);
DEF_ACTION_1P(SCRemoveTimersAction);

@ -32,11 +32,11 @@ DSMElemContainer::DSMElemContainer() {
}
DSMElemContainer::~DSMElemContainer() {
for (vector<DSMElement*>::iterator it=
for (set<DSMElement*>::iterator it=
owned_elems.begin(); it != owned_elems.end(); it++)
delete *it;
}
void DSMElemContainer::transferElem(DSMElement* elem) {
owned_elems.push_back(elem);
owned_elems.insert(elem);
}

@ -28,11 +28,11 @@
#define _SC_ELEM_CONTAINER_H
class DSMElement;
#include <vector>
using std::vector;
#include <set>
using std::set;
class DSMElemContainer {
vector<DSMElement*> owned_elems;
set<DSMElement*> owned_elems;
public:
DSMElemContainer();
virtual ~DSMElemContainer();

@ -46,11 +46,11 @@ DSMStateDiagram::~DSMStateDiagram() {
void DSMStateDiagram::addState(const State& state, bool is_initial) {
DBG("adding state '%s'\n", state.name.c_str());
for (vector<DSMAction*>::const_iterator it=
for (vector<DSMElement*>::const_iterator it=
state.pre_actions.begin(); it != state.pre_actions.end(); it++) {
DBG(" pre-action '%s'\n", (*it)->name.c_str());
}
for (vector<DSMAction*>::const_iterator it=
for (vector<DSMElement*>::const_iterator it=
state.post_actions.begin(); it != state.post_actions.end(); it++) {
DBG(" post-action '%s'\n", (*it)->name.c_str());
}
@ -75,7 +75,7 @@ bool DSMStateDiagram::addTransition(const DSMTransition& trans) {
DBG(" DSMCondition %s'%s'\n",
(*it)->invert?"not ":"", (*it)->name.c_str());
}
for (vector<DSMAction*>::const_iterator it=
for (vector<DSMElement*>::const_iterator it=
trans.actions.begin(); it != trans.actions.end(); it++) {
DBG(" Action '%s'\n", (*it)->name.c_str());
}
@ -224,42 +224,220 @@ void DSMStateEngine::onBeforeDestroy(DSMSession* sc_sess, AmSession* sess) {
(*it)->onBeforeDestroy(sc_sess, sess);
}
bool DSMStateEngine::runactions(vector<DSMAction*>::iterator from,
vector<DSMAction*>::iterator to,
bool DSMStateEngine::runactions(vector<DSMElement*>::iterator from,
vector<DSMElement*>::iterator to,
AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event,
map<string,string>* event_params, bool& is_consumed) {
// DBG("running %zd actions\n", to - from);
for (vector<DSMAction*>::iterator it=from; it != to; it++) {
DBG("executing '%s'\n", (*it)->name.c_str());
if ((*it)->execute(sess, sc_sess, event, event_params)) {
string se_modifier;
switch ((*it)->getSEAction(se_modifier,
sess, sc_sess, event, event_params)) {
case DSMAction::Repost:
is_consumed = false;
break;
case DSMAction::Jump:
DBG("jumping to %s\n", se_modifier.c_str());
if (jumpDiag(se_modifier, sess, sc_sess, event, event_params)) {
// is_consumed = false;
return true;
} break;
case DSMAction::Call:
DBG("calling %s\n", se_modifier.c_str());
if (callDiag(se_modifier, sess, sc_sess, event, event_params)) {
// is_consumed = false;
return true;
} break;
case DSMAction::Return:
if (returnDiag(sess, sc_sess)) {
//is_consumed = false;
return true;
} break;
default: break;
DBG("running %zd DSM action elements\n", to - from);
for (vector<DSMElement*>::iterator it=from; it != to; it++) {
DSMAction* dsm_act = dynamic_cast<DSMAction*>(*it);
if (dsm_act) {
DBG("executing '%s'\n", (dsm_act)->name.c_str());
if ((dsm_act)->execute(sess, sc_sess, event, event_params)) {
string se_modifier;
switch ((dsm_act)->getSEAction(se_modifier,
sess, sc_sess, event, event_params)) {
case DSMAction::Repost:
is_consumed = false;
break;
case DSMAction::Jump:
DBG("jumping to %s\n", se_modifier.c_str());
if (jumpDiag(se_modifier, sess, sc_sess, event, event_params)) {
// is_consumed = false;
return true;
}
break;
case DSMAction::Call:
DBG("calling %s\n", se_modifier.c_str());
if (callDiag(se_modifier, sess, sc_sess, event, event_params)) {
// is_consumed = false;
return true;
}
break;
case DSMAction::Return:
if (returnDiag(sess, sc_sess)) {
//is_consumed = false;
return true;
}
break;
default: break;
}
}
continue;
}
DSMConditionTree* cond_tree = dynamic_cast<DSMConditionTree*>(*it);
if (cond_tree) {
DBG("checking conditions\n");
vector<DSMCondition*>::iterator con=cond_tree->conditions.begin();
while (con!=cond_tree->conditions.end()) {
if (!(*con)->_match(sess, sc_sess, event, event_params))
break;
con++;
}
if (con == cond_tree->conditions.end()) {
DBG("condition tree matched.\n");
if (runactions(cond_tree->run_if_true.begin(), cond_tree->run_if_true.end(),
sess, sc_sess, event, event_params, is_consumed))
return true;
} else {
if(runactions(cond_tree->run_if_false.begin(), cond_tree->run_if_false.end(),
sess, sc_sess, event, event_params, is_consumed))
return true;
}
continue;
}
DSMArrayFor* array_for = dynamic_cast<DSMArrayFor*>(*it);
if (array_for) {
if (array_for->for_type == DSMArrayFor::Range) {
DBG("running for (%s in range(%s, %s) {\n",
array_for->k.c_str(), array_for->v.c_str(), array_for->array_struct.c_str());
} else {
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 (!k_name.length()) {
ERROR("empty counter name in for\n");
continue;
}
if (array_for->for_type != DSMArrayFor::Range && !array_name.length()) {
ERROR("empty array name in for\n");
continue;
}
if (array_name[0] == '$') array_name.erase(0, 1);
if (k_name[0] == '$') k_name.erase(0, 1);
if (array_for->for_type == DSMArrayFor::Struct && v_name[0] == '$')
v_name.erase(0, 1);
vector<pair<string, string> > cnt_values;
int range[2] = {0,0};
// get the counter values
if (array_for->for_type == DSMArrayFor::Struct) {
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 if (array_for->for_type == DSMArrayFor::Array) {
unsigned int a_index = 0;
VarMapT::iterator v = sc_sess->
var.lower_bound(array_name+"["+int2str(a_index)+"]");
while (v != sc_sess->var.end()) {
string this_index = array_name+"["+int2str(a_index)+"]";
if (v->first.substr(0, this_index.length()) != this_index) {
a_index++;
this_index = array_name+"["+int2str(a_index)+"]";
if (v->first.substr(0, this_index.length()) != this_index) {
break;
}
}
cnt_values.push_back(make_pair(v->second, ""));
DBG(" '%s'\n", v->second.c_str());
v++;
}
} else if (array_for->for_type == DSMArrayFor::Range) {
string s_range = resolveVars(array_for->v, sess, sc_sess, event_params);
if (!str2int(s_range, range[0])) {
WARN("Error converting lower bound range(%s,%s)\n",
array_for->v.c_str(), array_for->array_struct.c_str());
range[0]=0;
} else {
s_range = resolveVars(array_for->array_struct, sess, sc_sess, event_params);
if (!str2int(s_range, range[1])) {
WARN("Error converting upper bound range(%s,%s)\n",
array_for->v.c_str(), array_for->array_struct.c_str());
range[0]=0; range[1]=0;
}
}
}
// save counter k
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("");
// save counter v for Struct
bool v_exists = false; string v_save;
if (array_for->for_type == DSMArrayFor::Struct) {
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
if (array_for->for_type == DSMArrayFor::Range) {
int cnt = range[0];
while (cnt != range[1]) {
sc_sess->var[k_name] = int2str(cnt);
DBG("setting $%s=%s\n", k_name.c_str(), sc_sess->var[k_name].c_str());
runactions(array_for->actions.begin(), array_for->actions.end(),
sess, sc_sess, event, event_params, is_consumed);
if (range[1] > range[0])
cnt++;
else
cnt--;
}
} else {
DBG("running for loop with %zd items\n", cnt_values.size());
for (vector<pair<string, string> > ::iterator f_it=
cnt_values.begin(); f_it != cnt_values.end(); f_it++) {
if (array_for->for_type == DSMArrayFor::Struct) {
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 (array_for->for_type == DSMArrayFor::Struct) {
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;
}

@ -136,31 +136,65 @@ class DSMAction
class DSMTransition;
class State
class State
: public DSMElement {
public:
State();
~State();
vector<DSMAction*> pre_actions;
vector<DSMAction*> post_actions;
vector<DSMElement*> pre_actions;
vector<DSMElement*> post_actions;
vector<DSMTransition> transitions;
};
class DSMTransition
class DSMTransition
: public DSMElement {
public:
DSMTransition();
~DSMTransition();
vector<DSMCondition*> precond;
vector<DSMAction*> actions;
vector<DSMElement*> actions;
string from_state;
string to_state;
bool is_exception;
};
class DSMConditionTree
: public DSMElement {
public:
vector<DSMCondition*> conditions;
vector<DSMElement*> run_if_true;
vector<DSMElement*> run_if_false;
bool is_exception;
};
class DSMFunction
: public DSMElement {
public:
string name;
vector<DSMElement*> actions;
};
class DSMArrayFor
: public DSMElement {
public:
DSMArrayFor() { }
~DSMArrayFor() { }
enum DSMForType {
Range,
Array,
Struct
} for_type;
string k; // for(k in array)
string v; // for(k,v in struct), or range lower bound
string array_struct; // array or struct name, or range upper bound
vector<DSMElement*> actions;
};
class DSMModule;
class DSMStateDiagram {
@ -224,8 +258,8 @@ class DSMStateEngine {
DSMCondition::EventType event,
map<string,string>* event_params);
bool returnDiag(AmSession* sess, DSMSession* sc_sess);
bool runactions(vector<DSMAction*>::iterator from,
vector<DSMAction*>::iterator to,
bool runactions(vector<DSMElement*>::iterator from,
vector<DSMElement*>::iterator to,
AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event,
map<string,string>* event_params, bool& is_consumed);

@ -145,6 +145,10 @@ sendDTMFSequence(sequence [, duration_ms])
append($var, @select); append($var, $var2);
substr($var, pos)
e.g. substr($myvar, 5);
size($arrayname, $dst);
set variable $dst to size of array
(e.g. $arrayname[0], $arrayname[1] set, $dst set to 2)
inc($var)
clear($var)

Loading…
Cancel
Save