//#include //#include #include "plan_parser.hpp" #include "parser_state.hpp" #include #include CSFHRPASM* CPlanParser::Parse(const char* fn, IEngineDescriptor* engine) { xmlSAXHandler* ptrSaxHandler = new xmlSAXHandler; CParserState* ptrState = new CParserState; ptrState->ctx = ptrSaxHandler; ptrState->state = CParserState::ENTRY_STATE; ptrState->engine = engine; ptrState->error = false; ptrState->flags = 0; //std::cout << fn << std::endl; //for the visual studio is is broken by design, we need to initialize callbacks manualy :-~ ptrSaxHandler->internalSubset = NULL; ptrSaxHandler->isStandalone = NULL; ptrSaxHandler->hasInternalSubset = NULL; ptrSaxHandler->hasExternalSubset = NULL; ptrSaxHandler->resolveEntity = NULL; ptrSaxHandler->getEntity = NULL; ptrSaxHandler->entityDecl = NULL; ptrSaxHandler->notationDecl = NULL; ptrSaxHandler->attributeDecl = NULL; ptrSaxHandler->elementDecl = NULL; ptrSaxHandler->unparsedEntityDecl = NULL; ptrSaxHandler->setDocumentLocator = NULL; ptrSaxHandler->startDocument = NULL; ptrSaxHandler->endDocument = NULL; ptrSaxHandler->startElement = NULL; ptrSaxHandler->endElement = NULL; ptrSaxHandler->reference = NULL; ptrSaxHandler->characters = NULL; ptrSaxHandler->ignorableWhitespace = NULL; ptrSaxHandler->processingInstruction = NULL; ptrSaxHandler->comment = NULL; ptrSaxHandler->warning = NULL; ptrSaxHandler->error = NULL; ptrSaxHandler->fatalError = NULL; ptrSaxHandler->getParameterEntity = NULL; ptrSaxHandler->cdataBlock = NULL; ptrSaxHandler->externalSubset = NULL; //ptrSaxHandler->initialized //before we initialize those we are interested in ptrSaxHandler->startElement = &CPlanParser::startElement; ptrSaxHandler->endElement = &CPlanParser::endElement; ptrSaxHandler->characters = &CPlanParser::characters; int res = xmlSAXUserParseFile(ptrSaxHandler, ptrState, fn); CSFHRPASM* agent = ptrState->agent; bool failed = (ptrState->state == CParserState::FATAL_ERROR); delete ptrSaxHandler; delete ptrState; if( (res != 0) || failed) { //delete agent; return null; } else/**/ return agent; } //start element callback header /*static*/ void CPlanParser::startElement( void * user_data, const xmlChar * name, const xmlChar ** attrs) { CParserState* state = (static_cast( user_data)); //get proper object if(state->state == CParserState::FATAL_ERROR) return; //exit in case of error std::string tag = (char *) name; /**/ std::map< std::string, std::string> attributes; normalize(attrs, attributes); std::map< std::string, std::string>::iterator it; if( (it = attributes.find( ID_PARAM)) != attributes.end()) { state->ids.push(it->second); } else { state->ids.push(NO_ID_PARAM); //reset element name } //std::cout << "Starting: " << tag << std::endl; switch(state->state) { //parsing started case CParserState::ENTRY_STATE: if(tag == AGENT_TAG) { state->state = CParserState::AGENT; state->agent = new CSFHRPASM(state->engine); //create new agent with context of engine } else { errorUnexpectedTag(tag, state); } break; //entering agent specification - root element case CParserState::AGENT: if(tag == SFHRPLAN_TAG) { state->state = CParserState::SFHRPLAN; } else { errorUnexpectedTag(tag, state); } break; //one specific plan of the agent case CParserState::SFHRPLAN: if(tag == PRIO_TAG) { state->state = CParserState::PRIO; state->parent.push(CParserState::SFHRPLAN); state->priority = -1; //clear posible priority from previous condition } else if(tag == COND_TAG) { state->state = CParserState::COND; state->parent.push(CParserState::SFHRPLAN); state->params.clear(); //clear posible params from previous condition } else if(tag == INIT_TAG) { state->state = CParserState::INIT; } else if(tag == HRPLAN_TAG) { state->state = CParserState::HRPLAN; state->rplanner = new ReactivePlanner(); //new HRP Planner for current SF-HRP Plan //TODO check entry exists - or by DTD? ptrSimplePlan foo = state->EnsurePlan(attributes["entry"]); state->rplanner->EntryPlan(foo); } else if(tag == CLEANUP_TAG) { state->state = CParserState::CLEANUP; } else if(tag == TERM_TAG) { state->state = CParserState::TERM; } else { errorUnexpectedTag(tag, state); } break; case CParserState::COND: if(tag == ELEM_TAG) { state->state = CParserState::C_ELEM; } else if(tag == AND_TAG) { state->state = CParserState::C_AND; } else if(tag == OR_TAG) { state->state = CParserState::C_OR; } else if(tag == NOT_TAG) { state->state = CParserState::C_NOT; } else { errorUnexpectedTag(tag, state); } break; case CParserState::C_ELEM: if(tag == TYPE_TAG) { state->state = CParserState::TYPE; state->parent.push(CParserState::C_ELEM); } else if(tag == PARAM_TAG) { state->state = CParserState::PARAM; state->parent.push(CParserState::C_ELEM); } else { errorUnexpectedTag(tag, state); } break; case CParserState::HRPLAN: if(tag == PLAN_TAG) { state->state = CParserState::PLAN; state->actualPlan = state->EnsurePlan(attributes[ID_PARAM]); } else { errorUnexpectedTag(tag, state); } break; case CParserState::PLAN: if(tag == RULE_TAG) { state->state = CParserState::RULE; //rule is processed later, in order to determin which type of rule to choose } else { errorUnexpectedTag(tag, state); } break; case CParserState::RULE: if(tag == PRIO_TAG) { state->state = CParserState::PRIO; state->parent.push(CParserState::RULE); state->priority = -1; //clear posible priority from previous condition } else if (tag == WEIGHT_TAG){ state->state = CParserState::WEIGHT; } else if (tag == SUCCESSES_TAG){ state->state = CParserState::SUCCS; } else if (tag == FAILS_TAG){ state->state = CParserState::FAILS; } else if (tag == STTOUT_TAG){ state->state = CParserState::STTOUT; } else if (tag == FLAGS_TAG){ state->state = CParserState::FLAGS; state->flags = 0; } else if(tag == COND_TAG) { state->state = CParserState::COND; state->parent.push(CParserState::RULE); state->params.clear(); //clear posible params from previous condition } else if(tag == EXEC_TAG) { if(attributes[TYPE_PARAM] == TYPE_SUCCESS) { state->state = CParserState::EXEC_S; } else if(attributes[TYPE_PARAM] == TYPE_FAIL) { state->state = CParserState::EXEC_F; } else if(attributes[TYPE_PARAM] == TYPE_PLAN) { state->state = CParserState::EXEC_P; } else if(attributes[TYPE_PARAM] == TYPE_ACTION) { state->state = CParserState::EXEC_A; state->actions.clear(); //clear previous actions; } else { //TODO not opening tag but param value errorUnexpectedTag(attributes[TYPE_PARAM], state); } state->execType = state->state; } else { errorUnexpectedTag(tag, state); } break; case CParserState::FLAGS: if (tag == INTERSAFE_TAG){ state->state = CParserState::INTERSAFE; } else if (tag == RELSAFE_TAG){ state->state = CParserState::RELSAFE; } else if (tag == STICKY_TAG){ state->state = CParserState::STICKY; } else { errorUnexpectedTag(tag, state); } break; case CParserState::EXEC_A: if (tag == ACTION_TAG){ state->state = CParserState::ACTION; } else { errorUnexpectedTag(tag, state); } break; case CParserState::ACTION: if (tag == TYPE_TAG){ state->state = CParserState::TYPE; state->parent.push(CParserState::ACTION); } else if (tag == PARAM_TAG){ state->state = CParserState::PARAM; state->parent.push(CParserState::EXEC_A); } else { errorUnexpectedTag(tag, state); } break; break; case CParserState::INIT: if (tag == LIST_TAG){ state->state = CParserState::LIST; } else { errorUnexpectedTag(tag, state); } break; case CParserState::TERM: if (tag == SUCC_TAG){ state->state = CParserState::SUCC; } else if (tag == FAIL_TAG){ state->state = CParserState::FAIL; } else { errorUnexpectedTag(tag, state); } break; case CParserState::LIST: if (tag == OBJECT_TAG){ state->state = CParserState::OBJECT; } else { errorUnexpectedTag(tag, state); } break; default: //TODO throw unknown tag errorUnexpectedTag(tag, state); break; } /**/ } //end element callback header /*static*/ void CPlanParser::endElement( void * user_data, const xmlChar * name) { CParserState* state = (static_cast( user_data)); //get proper object std::string tag = (char *) name; if(state->state == CParserState::FATAL_ERROR) { //assert( false); return; //exit in case of error } /**/ //std::cout << "Ending: " << tag << std::endl; switch(state->state) { //leaving agent tag case CParserState::AGENT: if(tag == AGENT_TAG) { state->state = CParserState::ENTRY_STATE; } else { errorUnexpectedTag(tag, state); } break; //leaving sf-hrplan specification case CParserState::SFHRPLAN: if(tag == SFHRPLAN_TAG) { state->state = CParserState::AGENT; //TODO - element has priority element child assert(state->priority != -1); CSFHRPPlan* plan = new CSFHRPPlan(state->agent, state->engine, state->priority, state->conditions.top(), state->iphase, state->rplanner, state->tphase); state->agent->AddPlan( plan); state->conditions.top()->SetReleaseable(plan); //assign plan to the condition state->conditions.pop(); assert(state->conditions.empty()); //no conditions on stack after leaving sfhrplan } else { errorUnexpectedTag(tag, state); } break; //leaving init phase case CParserState::INIT: if(tag == INIT_TAG) { state->state = CParserState::SFHRPLAN; state->iphase = new InitPhase(state->engine, state->objects); } else { errorUnexpectedTag(tag, state); } break; case CParserState::HRPLAN: if(tag == HRPLAN_TAG) { state->state = CParserState::SFHRPLAN; } else { errorUnexpectedTag(tag, state); } break; case CParserState::CLEANUP: if(tag == CLEANUP_TAG) { state->state = CParserState::SFHRPLAN; } else { errorUnexpectedTag(tag, state); } break; case CParserState::TERM: if(tag == TERM_TAG) { state->state = CParserState::SFHRPLAN; state->tphase = new TermPhase(state->engine, state->term_succ, state->term_fail); } else { errorUnexpectedTag(tag, state); } break; //leaving condition definition case CParserState::COND: if(tag == COND_TAG) { state->state = state->parent.top(); state->parent.pop(); //close condition and store it CNodeBase* root = state->nodes.top(); state->nodes.pop(); //TODO throw error assert(state->nodes.empty()); //there are no unused nodes left CCondition* condition = new CCondition( root, state->ids.top()); root->SetParent(condition); state->conditions.push(condition); //remember for further use state->agent->AddCondition(condition); } else { errorUnexpectedTag(tag, state); } break; //leaving priority element case CParserState::PRIO: if(tag == PRIO_TAG) { state->state = state->parent.top(); state->parent.pop(); } else { errorUnexpectedTag(tag, state); } break; case CParserState::C_ELEM: if(tag == ELEM_TAG) { state->state = CParserState::COND; //create elem node CElement* node = new CElement(); int code = state->engine->RegisterCondition(state->type, state->params); state->agent->RegisterElement( code, node); //TODO here register elems and store them //push node for later use state->nodes.push(node); } else { errorUnexpectedTag(tag, state); } break; case CParserState::C_AND: if(tag == AND_TAG) { state->state = CParserState::COND; //TODO throw reasonable error assert(state->nodes.size() > 1); CNodeBase *lchld, *rchld; lchld = state->nodes.top(); state->nodes.pop(); rchld = state->nodes.top(); state->nodes.pop(); //create and node and assign parent to its childrens CNodeBase* node = new CNodeAnd(lchld, rchld); lchld->SetParent(node); rchld->SetParent(node); //push it to stack state->nodes.push(node); } else { errorUnexpectedTag(tag, state); } break; case CParserState::C_OR: if(tag == OR_TAG) { state->state = CParserState::COND; //TODO throw reasonable error assert(state->nodes.size() > 1); CNodeBase *lchld, *rchld; lchld = state->nodes.top(); state->nodes.pop(); rchld = state->nodes.top(); state->nodes.pop(); //create and node and assign parent to its childrens CNodeBase* node = new CNodeOr(lchld, rchld); lchld->SetParent(node); rchld->SetParent(node); //push it to stack state->nodes.push(node); } else { errorUnexpectedTag(tag, state); } break; case CParserState::C_NOT: if(tag == NOT_TAG) { state->state = CParserState::COND; //TODO throw reasonable error assert(state->nodes.size() > 0); CNodeBase *chld; chld = state->nodes.top(); state->nodes.pop(); //create and node and assign parent to its childrens CNodeBase* node = new CNodeNot(chld); chld->SetParent(node); //push it to stack state->nodes.push(node); } else { errorUnexpectedTag(tag, state); } break; case CParserState::TYPE: if(tag == TYPE_TAG) { state->state = state->parent.top(); state->parent.pop(); } else { errorUnexpectedTag(tag, state); } break; case CParserState::PARAM: if(tag == PARAM_TAG) { state->state = state->parent.top(); state->parent.pop(); } else { errorUnexpectedTag(tag, state); } break; case CParserState::PLAN: if(tag == PLAN_TAG) { state->state = CParserState::HRPLAN; } else { errorUnexpectedTag(tag, state); } break; case CParserState::RULE: if(tag == RULE_TAG) { state->state = CParserState::PLAN; //TODO IReleaseable* foo; switch(state->execType) { case CParserState::EXEC_P: //if target plan does not exist, create it state->EnsurePlan(state->ruleplan); foo = state->actualPlan->AddPlanRule( state->priority, state->weight, state->plans[state->ruleplan], state->flags, state->sticky_timeout, state->successes, state->fails); break; case CParserState::EXEC_A: foo = state->actualPlan->AddActionRule(state->ids.top(), state->priority, state->weight, state->actions, state->flags, state->sticky_timeout, state->successes, state->fails); break; case CParserState::EXEC_S: foo = state->actualPlan->AddSuccessRule(state->ids.top(), state->priority, state->weight, state->flags, state->sticky_timeout, state->successes, state->fails); break; case CParserState::EXEC_F: foo = state->actualPlan->AddFailRule(state->ids.top(), state->priority, state->weight, state->flags, state->sticky_timeout, state->successes, state->fails); break; } state->conditions.top()->SetReleaseable(foo); state->conditions.pop(); } else { errorUnexpectedTag(tag, state); } break; case CParserState::WEIGHT: if (tag == WEIGHT_TAG){ state->state = CParserState::RULE; } else { errorUnexpectedTag(tag, state); } break; case CParserState::SUCCS: if (tag == SUCCESSES_TAG){ state->state = CParserState::RULE; } else { errorUnexpectedTag(tag, state); } break; case CParserState::FAILS: if (tag == FAILS_TAG){ state->state = CParserState::RULE; } else { errorUnexpectedTag(tag, state); } break; case CParserState::FLAGS: if (tag == FLAGS_TAG){ state->state = CParserState::RULE; } else { errorUnexpectedTag(tag, state); } break; case CParserState::INTERSAFE: state->state = CParserState::FLAGS; state->flags |= BaseRule::INTERRUPT_SAFE; break; case CParserState::RELSAFE: state->state = CParserState::FLAGS; state->flags |= BaseRule::RELEASER_SAFE; break; case CParserState::STICKY: state->state = CParserState::FLAGS; state->flags |= BaseRule::STICKY; break; case CParserState::STTOUT: if (tag == STTOUT_TAG){ state->state = CParserState::RULE; } else { errorUnexpectedTag(tag, state); } break; case CParserState::EXEC_S: case CParserState::EXEC_F: case CParserState::EXEC_P: case CParserState::EXEC_A: if (tag == EXEC_TAG){ state->state = CParserState::RULE; } else { errorUnexpectedTag(tag, state); } break; case CParserState::ACTION: if (tag == ACTION_TAG){ state->state = CParserState::EXEC_A; state->actions.push_back( state->engine->RegisterAction(state->type, state->params)); } else { errorUnexpectedTag(tag, state); } break; //leaving object list case CParserState::LIST: if(tag == LIST_TAG) { state->state = CParserState::INIT; } else { errorUnexpectedTag(tag, state); } break; //leaving object case CParserState::OBJECT: if(tag == OBJECT_TAG) { state->state = CParserState::LIST; } else { errorUnexpectedTag(tag, state); } break; case CParserState::SUCC: if(tag == SUCC_TAG) { state->state = CParserState::TERM; } else { errorUnexpectedTag(tag, state); } break; case CParserState::FAIL: if(tag == FAIL_TAG) { state->state = CParserState::TERM; } else { errorUnexpectedTag(tag, state); } break; default: errorUnexpectedTag(tag, state); break; } /**/ state->ids.pop(); } //function is declared as static in hpp /*static*/ void CPlanParser::characters( void * user_data, const xmlChar * chars, int len) { CParserState* state = (static_cast( user_data)); //get proper object if(state->state == CParserState::FATAL_ERROR) return; //exit in case of error std::string foo(""); /**/ //p.Characters( foo); switch(state->state) { case CParserState::TYPE: state->type.clear(); xmlCharToString(chars, len, state->type); break; case CParserState::PARAM: xmlCharToString(chars, len, foo); state->params.push_back(foo); break; case CParserState::PRIO: xmlCharToString(chars, len, foo); state->priority = atoi(foo.c_str()); //TODo - or via DTD? assert(state->priority >= 0); break; case CParserState::WEIGHT: xmlCharToString(chars, len, foo); state->weight = atoi(foo.c_str()); break; case CParserState::STTOUT: xmlCharToString(chars, len, foo); state->sticky_timeout = atoi(foo.c_str()); break; case CParserState::SUCCS: xmlCharToString(chars, len, foo); state->successes = atoi(foo.c_str()); break; case CParserState::FAILS: xmlCharToString(chars, len, foo); state->fails = atoi(foo.c_str()); break; case CParserState::EXEC_P: xmlCharToString(chars, len, state->ruleplan); break; case CParserState::OBJECT: xmlCharToString(chars, len, foo); state->objects.push_back(foo); break; case CParserState::SUCC: state->term_succ.clear(); xmlCharToString(chars, len, state->term_succ); break; case CParserState::FAIL: state->term_fail.clear(); xmlCharToString(chars, len, state->term_fail); break; default: //TODO ignore only whitespace //errorUnexpectedChars(foo, state); break; } /**/ } //normalize tag atributes into map /*static*/ void CPlanParser::normalize( const xmlChar** attrs, std::map< std::string, std::string> & normd) { if(attrs == NULL) return; //no attribures //convert NULL terminated array of pairs of char* into map of strings for(size_t i = 0; attrs[i] != NULL; i += 2) { normd.insert( std::pair< std::string, std::string>( (char *) attrs[i], (char *) attrs[i + 1])); } } //function is declared as static in hpp /*static*/ void CPlanParser::xmlCharToString( const xmlChar* chars, size_t len, std::string & str) { for(const xmlChar* cur = chars ; cur != (chars + len); ++cur) { str.push_back((char) *cur); } return; } /*static */ void CPlanParser::errorUnexpectedTag(std::string & tag, CParserState* state) { //std::cout << "Unexpected tag " << tag //<< " at line " << xmlSAX2GetLineNumber(NULL) //<< " at column " << xmlSAX2GetColumnNumber(state->ctx) //<< std::endl; //TODO throw exception or whatever //const std::string s("unexpected tag: " + tag); //throw new std::logic_error(s); state->state = CParserState::FATAL_ERROR; } /*static */ void CPlanParser::errorUnexpectedChars(std::string & chars, CParserState* state) { //std::cout << "Unexpected chars " << chars //<< " at line " << xmlSAX2GetLineNumber(NULL) //<< " at column " << xmlSAX2GetColumnNumber(state->ctx) //<< std::endl; //TODO throw exception or whatever } /**/