- Main Page
- Namespaces
- Classes
- Files
- Related Pages

# /Users/fpy/titan-1-5-MBARI/Mers/Models/CCA/Io/Xmpl/XmplParser.cpp

    00001 //------------------------------------------------------------------------------
    00002 // Copyright 2001 The Johns Hopkins University Applied Physics Laboratory
    00003 // All Rights Reserved
    00004 //
    00005 // This software is provided "as is".  Neither the authors nor JHU/APL assume
    00006 // any responsibility for damages resulting from the use of this software.
    00007 //------------------------------------------------------------------------------
    00008 // Last updated: $Date: 2005-12-06 15:13:10 -0500 (Tue, 06 Dec 2005) $
    00009 // Revision:     $Revision: 5729 $
    00010 //------------------------------------------------------------------------------
    00011
    00012 //------------------------------------------------------------------------------
    00013 // Includes
    00014 //------------------------------------------------------------------------------
    00015 #include "XmplParser.h"
    00016
    00017 #include <sstream>
    00018 #include <list>
    00019 #include <cassert>
    00020
    00021 using Mers::Models::CCA::CCAModel;
    00022 using Mers::Models::CCA::CCAClause;
    00023 using Mers::Models::CCA::CCASentence;
    00024 using Mers::Models::CCA::CCAVariable;
    00025 using Mers::Models::CCA::CCAValue;
    00026 using Mers::Models::CCA::CCAValues;
    00027 using Mers::Models::CCA::CCADomain;
    00028 using Mers::Models::CCA::CCAAssignment;
    00029 using Mers::Models::CCA::CCAState;
    00030 using Mers::Utils::Lang::BaseModelObject;
    00031 using Mers::Utils::Lang::String;
    00032
    00033 //------------------------------------------------------------------------------
    00034 // Static initializations
    00035 //------------------------------------------------------------------------------
    00036 /* static */ int XmplParser::_numInstances = 0;
    00037
    00038 // Tags specific to the xmpl model file
    00039 const string XmplParser::VARIABLE_TYPE_TAG("ci:attributetype");
    00040 const string XmplParser::MODE_TAG("ci:statevector");
    00041 const string XmplParser::VARIABLE_TAG("ci:attribute");
    00042 const string XmplParser::TRANSITION_TAG("ci:transition");
    00043 const string XmplParser::CLAUSE_TAG("ci:clause");
    00044 const string XmplParser::COMPONENT_INSTANCE_TAG("componentinstance");
    00045 const string XmplParser::COMPONENT_TAG("ci:component");
    00046 const string XmplParser::TERM_TAG("ci:term");
    00047
    00048
    00049
    00050 XmplParser::XmplParser()
    00051 {
    00052         if (_numInstances == 0)
    00053                 initXMLUtils();
    00054         _numInstances++;
    00055
    00056         // Instantiate the DOM parser
    00057         XMLCh tempStr[100];
    00058         XMLString::transcode("LS", tempStr, 99);
    00059         DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    00060         _parser = ((DOMImplementationLS*)impl)->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    00061
    00062         _parser->setFeature(XMLUni::fgDOMValidateIfSchema, true);
    00063         _parser->setFeature(XMLUni::fgDOMNamespaces, true);
    00064         _parser->setFeature(XMLUni::fgXercesSchema, false);
    00065         _parser->setFeature(XMLUni::fgDOMWhitespaceInElementContent, false);
    00066         _parser->setErrorHandler(&_xmlErrorHandler);
    00067 }
    00068
    00069
    00070 XmplParser::~XmplParser()
    00071 {
    00072         _numInstances--;
    00073 //      if (_numInstances == 0)
    00074 //              terminateXMLUtils();
    00075
    00076         delete _parser;
    00077 }
    00078
    00079
    00080 VariableInfoMap
    00081 XmplParser::generateTitanModel(CCAModel &titanModel,
    00082                 const string & xmplFile,
    00083                 const string & hrnFile,
    00084                 const string & iniFile)
    00085         throw (ParsingException)
    00086 {
    00087         // use this object to cache variable information
    00088         VariableInfoMap variableMap;
    00089         // use this object to cache information about initialized mode variables
    00090         VariableInfoMap initialModesMap;
    00091         //AncestorList test;
    00092         //test.unit_test();
    00093
    00094         // @TODO: see if we can throw some decent exceptions for file not found
    00095         // style errors
    00096         try
    00097         {
    00098           DOMDocument *doc = 0;
    00099
    00100           // Use the harness file to identify observables and commands
    00101           #ifdef __DEBUG
    00102           cout << "[DEBUG]: Parsing harness file" << endl;
    00103           #endif
    00104           doc =_parser->parseURI(hrnFile.c_str());
    00105                                         if( doc == NULL ) {
    00106                                                 throw ParsingException("Unable to load hrn file.");
    00107                                         }
    00108           parseHarnessTree((DOMNode*)doc->getDocumentElement(),
    00109                            variableMap);
    00110           _parser->resetDocumentPool();
    00111           #ifdef __DEBUG
    00112           cout << "[DEBUG]: Done with harness file" << endl;
    00113           #endif
    00114
    00115           // Use the initialization file to get initial values of modes
    00116           // We cannot set these in the CCAModel, so we just return them
    00117           #ifdef __DEBUG
    00118           cout << "[DEBUG]: Parsing initialization file" << endl;
    00119           #endif
    00120           doc = _parser->parseURI(iniFile.c_str());
    00121                 parseInitializationTree((DOMNode*)doc->getDocumentElement(),
    00122                                         initialModesMap);
    00123                 _parser->resetDocumentPool();
    00124           #ifdef __DEBUG
    00125           cout << "[DEBUG]: Done with initialization file" << endl;
    00126           #endif
    00127
    00128           // Parse the xmpl file to generate data structures
    00129           #ifdef __DEBUG
    00130           cout << "[DEBUG]: Parsing xmpl file" << endl;
    00131           #endif
    00132           doc = _parser->parseURI(xmplFile.c_str());
    00133           AncestorList ancestors(true);
    00134           //printXMLTree(xmplFile.c_str());
    00135           parseModelTree((DOMNode*)doc->getDocumentElement(), titanModel,
    00136                          variableMap, ancestors);
    00137           _parser->resetDocumentPool();
    00138           #ifdef __DEBUG
    00139           cout << "[DEBUG]: Done with xmpl file" << endl;
    00140           #endif
    00141         }
    00142         catch (const XMLException &ex)
    00143         {
    00144                 throw ParsingException("XMLException: " + getString(ex.getMessage()));
    00145         }
    00146         catch (const DOMException &ex)
    00147         {
    00148                 throw ParsingException("DOMException: " + ex.code);
    00149         }
    00150         catch (ParsingException ex)
    00151         {
    00152                 throw;
    00153         }
    00154         catch (...)
    00155         {
    00156                 throw ParsingException("unrecognized parse exception");
    00157         }
    00158         return initialModesMap;
    00159 }
    00160
    00161
    00162 /* static */ string
    00163 XmplParser::getString(const XMLCh* const xmlString)
    00164 {
    00165         char *local;
    00166
    00167         local = XMLString::transcode(xmlString);
    00168         string s(local);
    00169         delete [] local;
    00170         return s;
    00171 }
    00172
    00173
    00174 /* static */ string
    00175 XmplParser::getString(const DOMString* const domString)
    00176 {
    00177         char *local = domString->transcode();
    00178         string s(local);
    00179         delete [] local;
    00180         return s;
    00181 }
    00182
    00183
    00184 /* static */ string
    00185 XmplParser::getString(const DOMString & domString)
    00186 {
    00187         return getString(&domString);
    00188 }
    00189
    00190
    00191 void
    00192 XmplParser::initXMLUtils()
    00193 {
    00194         try
    00195         {
    00196                 #ifdef __DEBUG
    00197                 cout << "[DEBUG]: initializing XML toolkit" << endl;
    00198                 #endif
    00199
    00200                 XMLPlatformUtils::Initialize();
    00201         }
    00202         catch (const XMLException &ex)
    00203         {
    00204                 cerr << "[ERROR]: " << getString(ex.getMessage()) << endl;
    00205         }
    00206 }
    00207
    00208
    00209 void
    00210 XmplParser::terminateXMLUtils()
    00211 {
    00212         try
    00213         {
    00214                 #ifdef __DEBUG
    00215                 cout << "[DEBUG]: terminating XML toolkit" << endl;
    00216                 #endif
    00217
    00218                 XMLPlatformUtils::Terminate();
    00219         }
    00220         catch (const XMLException &ex)
    00221         {
    00222                 cerr << "[ERROR]: " << getString(ex.getMessage()) << endl;
    00223         }
    00224 }
    00225
    00226
    00227 /* static */ void
    00228 XmplParser::printChildren(const DOMNode* parent, int depth)
    00229 {
    00230         DOMNodeList* children = parent->getChildNodes();
    00231         int numChildren = children->getLength();
    00232
    00233         // Print node information
    00234         for (int i = 0; i < numChildren; i++)
    00235         {
    00236                 printNode(children->item(i), depth);
    00237
    00238                 // print any attributes this node has
    00239                 const DOMNamedNodeMap* attributes = children->item(i)->getAttributes();
    00240                 if (attributes != NULL)
    00241                 {
    00242                         for (unsigned int j = 0; j < attributes->getLength(); j++)
    00243                         {
    00244                                 printNode(attributes->item(j), depth);
    00245                         }
    00246                 }
    00247
    00248                 // do this for DFS
    00249                 printChildren(children->item(i), depth + 1);
    00250         }
    00251 }
    00252
    00253
    00254 /* static */ void
    00255 XmplParser::printNode(const DOMNode* node, int depth)
    00256 {
    00257         static string attributeName = "";
    00258         static string compName = "";
    00259         char * cNodeName = XMLString::transcode(node->getNodeName());
    00260         char * cNodeValue = XMLString::transcode(node->getNodeValue());
    00261
    00262         for (int i = 0; i < depth; i++)
    00263                 cout << "     ";
    00264
    00265         switch (node->getNodeType())
    00266         {
    00267                 case DOMNode::ELEMENT_NODE:
    00268                         cout << "[ELEMENT] ";
    00269                         cout << cNodeName;
    00270                         break;
    00271
    00272                 case DOMNode::ATTRIBUTE_NODE:
    00273                         cout << " ";
    00274                         cout << "{ATTRIBUTE} ";
    00275                         cout << cNodeName << " = " << cNodeValue;
    00276                         break;
    00277
    00278                 case DOMNode::TEXT_NODE:
    00279                         cout << "[TEXT] ";
    00280                         cout << cNodeName << " = " << cNodeValue;
    00281                         break;
    00282
    00283                 case DOMNode::COMMENT_NODE:
    00284                         cout << "[COMMENT] ";
    00285                         break;
    00286
    00287                 case DOMNode::DOCUMENT_TYPE_NODE:
    00288                         cout << "[DOC TYPE] ";
    00289                         break;
    00290
    00291                 default:
    00292                         cout << "[OTHER] ";
    00293                         break;
    00294         }
    00295
    00296         delete [] cNodeName;
    00297         delete [] cNodeValue;
    00298
    00299         cout << endl;
    00300 }
    00301
    00302
    00303 void
    00304 XmplParser::printXMLTree(const string &filename)
    00305 {
    00306         try
    00307         {
    00308                 DOMDocument* doc = _parser->parseURI(filename.c_str());
    00309                 printChildren(doc, 0);
    00310         }
    00311         catch (const XMLException &ex)
    00312         {
    00313                 cerr << "[ERROR]: " << getString(ex.getMessage()) << endl;
    00314         }
    00315         catch (const DOMException &ex)
    00316         {
    00317                 cerr << "[ERROR]: DOM_DOM parse exception: " << ex.code << endl;
    00318         }
    00319         catch (...)
    00320         {
    00321                 cerr << "[ERROR]: unrecoginzed parse exception" << endl;
    00322         }
    00323 }
    00324
    00325
    00326 void
    00327 XmplParser::parseHarnessTree(
    00328                 const DOMNode* node,
    00329                 VariableInfoMap &variableMap)
    00330         throw (ParsingException)
    00331 {
    00332         // Tags specific to the harness file
    00333         static const string OBSERVABLE_TAG("obs");
    00334         static const string COMMAND_TAG("cmd");
    00335
    00336         DOMNodeList* children = node->getChildNodes();
    00337         int numChildren = children->getLength();
    00338
    00339         // Visit all nodes at this depth
    00340         for (int i = 0; i < numChildren; i++)
    00341         {
    00342                 DOMNode* childNode = children->item(i);
    00343
    00344                 // only concerned with element nodes for now...
    00345                 if (childNode->getNodeType() == DOMNode::ELEMENT_NODE)
    00346                 {
    00347                         try
    00348                         {
    00349                                 // The action to perform depends upon the element type
    00350                                 string nodeName = getString(childNode->getNodeName());
    00351                                 if (nodeName.compare(OBSERVABLE_TAG) == 0)
    00352                                 {
    00353                                         parseHarnessObservable(childNode, variableMap);
    00354                                 }
    00355                                 else if (nodeName.compare(COMMAND_TAG) == 0)
    00356                                 {
    00357                                         parseHarnessCommand(childNode, variableMap);
    00358                                 }
    00359                         }
    00360                         catch (ParsingException ex)
    00361                         {
    00362                                 throw;
    00363                         }
    00364                 }
    00365
    00366                 // parse the child nodes (even though we don't expect any)
    00367                 parseHarnessTree(childNode, variableMap);
    00368         }
    00369 }
    00370
    00371
    00372 string
    00373 XmplParser::parseHarnessObservable(
    00374                 const DOMNode* _node,
    00375                 VariableInfoMap &_variableMap)
    00376         throw (ParsingException)
    00377 {
    00378         if (!_node->hasAttributes())
    00379                 throw ParsingException("harness observable has no attributes");
    00380
    00381         string name = getAttribute(_node, "name");
    00382
    00383         // TODO: tag the variable as an observable
    00384         _variableMap.put(name, VariableInfo(CCAVariable::OBSERVABLE));
    00385
    00386         return name;
    00387 }
    00388
    00389
    00390 string
    00391 XmplParser::parseHarnessCommand(
    00392                 const DOMNode* _node,
    00393                 VariableInfoMap &_variableMap)
    00394         throw (ParsingException)
    00395 {
    00396         if (!_node->hasAttributes())
    00397                 throw ParsingException("harness command has no attributes");
    00398
    00399         string name = getAttribute(_node, "name");
    00400
    00401         // TODO: tag the variable as an command
    00402         _variableMap.put(name, VariableInfo(CCAVariable::CONTROL));
    00403
    00404         return getAttribute(_node, "name");
    00405 }
    00406
    00407
    00408 void
    00409 XmplParser::parseInitializationTree(
    00410                 const DOMNode* _node,
    00411                 VariableInfoMap &_initialModesMap)
    00412         throw (ParsingException)
    00413 {
    00414         // Tags specific to the initialization file
    00415         static const string ASSIGN_TAG("assign");
    00416
    00417         DOMNodeList* children = _node->getChildNodes();
    00418         int numChildren = children->getLength();
    00419
    00420         // Visit all nodes at this depth
    00421         for (int i = 0; i < numChildren; i++)
    00422         {
    00423                 DOMNode* childNode = children->item(i);
    00424
    00425                 // only concerned with element nodes for now...
    00426                 if (childNode->getNodeType() == DOMNode::ELEMENT_NODE)
    00427                 {
    00428                         try
    00429                         {
    00430                                 // The action to perform depends upon the element type
    00431                                 string nodeName = getString(childNode->getNodeName());
    00432
    00433                                 if (nodeName.compare(ASSIGN_TAG) == 0)
    00434                                 {
    00435                                   parseInitializationAssignment(childNode, _initialModesMap);
    00436                                 }
    00437                         }
    00438                         catch (ParsingException ex)
    00439                         {
    00440                                 throw;
    00441                         }
    00442                 }
    00443
    00444                 // parse the child nodes (even though we don't expect any)
    00445                 parseInitializationTree(childNode, _initialModesMap);
    00446         }
    00447 }
    00448
    00449
    00450 string
    00451 XmplParser::parseInitializationAssignment(
    00452                 const DOMNode* _node,
    00453                 VariableInfoMap &_initialModesMap)
    00454         throw (ParsingException)
    00455 {
    00456         if (!_node->hasAttributes())
    00457                 throw ParsingException("init assignment has no attributes");
    00458
    00459         string value = getAttribute(_node, "eq");
    00460
    00461         unsigned int sepIndex = value.rfind("=");
    00462         if (sepIndex == string::npos)
    00463                 throw ParsingException("init assignment is missing '='");
    00464         string name = value.substr(0, sepIndex);
    00465         value = value.substr(sepIndex+1, value.length() - sepIndex);
    00466
    00467         if (value.length() <= 0)
    00468                 throw ParsingException("init assignment has no value");
    00469
    00470         // TODO: tag the inital state of the variable
    00471         _initialModesMap.put(name, VariableInfo(CCAVariable::STATE, value));
    00472         return name;
    00473 }
    00474
    00475
    00476 void
    00477 XmplParser::parseModelTree(
    00478                 const DOMNode* _node,
    00479                 CCAModel &_model,
    00480                 VariableInfoMap &_variableMap,
    00481                 AncestorList &_ancestors)
    00482         throw (ParsingException)
    00483 {
    00484         DOMNodeList* children = _node->getChildNodes();
    00485         int numChildren = children->getLength();
    00486
    00487         // Visit all nodes at this depth
    00488         for (int i = 0; i < numChildren; i++)
    00489         {
    00490                 DOMNode* childNode = children->item(i);
    00491
    00492                 // only concerned with element nodes for now...
    00493                 if (childNode->getNodeType() == DOMNode::ELEMENT_NODE)
    00494                 {
    00495                         try
    00496                         {
    00497                                 // The action to perform depends upon the element type
    00498                                 string nodeName = getString(childNode->getNodeName());
    00499
    00500                                 if (nodeName.compare(COMPONENT_INSTANCE_TAG) == 0)
    00501                                 {
    00502                                         // this needs to be the first thing that happens in the file.
    00503                                         assert(_ancestors.isEmpty());
    00504                                         _ancestors.push(parseComponentInstance(childNode));
    00505                                         #ifdef __DEBUG
    00506                                                 cout << "Component Instance: " << _ancestors.root() << endl;
    00507                                         #endif
    00508                                         parseModelTree(childNode, _model, _variableMap, _ancestors);
    00509                                 }
    00510                                 else if (nodeName.compare(COMPONENT_TAG) == 0)
    00511                                 {
    00512                                         parseComponentTree(childNode, _model, _ancestors, _variableMap);
    00513                                 }
    00514                                 else if (nodeName.compare(VARIABLE_TYPE_TAG) == 0)
    00515                                 {
    00516                                         parseEnumeration(childNode, _model, _ancestors);
    00517                                 }
    00518                                 else
    00519                                 {
    00520                                         parseModelTree(childNode, _model, _variableMap, _ancestors);
    00521                                 }
    00522
    00523                         }
    00524                         catch (ParsingException ex)
    00525                         {
    00526                                 throw;
    00527                         }
    00528                 }
    00529         }
    00530 }
    00531
    00532
    00533 string
    00534 XmplParser::parseComponentInstance(
    00535                 const DOMNode* _node)
    00536         throw (ParsingException)
    00537 {
    00538         if (!_node->hasAttributes())
    00539                 throw ParsingException("component instance has no attributes");
    00540 //      const DOMNamedNodeMap attributes = _node.getAttributes();
    00541
    00542 //      if (attributes.getLength() <= 0)
    00543 //              throw ParsingException("component instance has no attributes");
    00544
    00545         return getAttribute(_node, "name");
    00546 }
    00547
    00548
    00549 string
    00550 XmplParser::parseComponentTree(
    00551                 const DOMNode* _node,
    00552                 CCAModel &_model,
    00553                 AncestorList &_ancestors,
    00554                 VariableInfoMap &_variableMap)
    00555         throw (ParsingException)
    00556 {
    00557         string componentName = getAttribute(_node, "name");
    00558         //string componentType = getAttribute(_node, "type");
    00559
    00560         cout << "Component Name: " << componentName << endl;
    00561
    00562         _ancestors.popToRoot();
    00563
    00564         // ignore the module name
    00565         if (componentName != _ancestors.root())
    00566                 _ancestors.push(componentName);
    00567
    00568         #ifdef __DEBUG
    00569                 cout << "Ancestors : " << _ancestors.qualify("") << endl;
    00570         #endif
    00571
    00572         map<string, vector<CCAClause> *> clauseMap;
    00573         CCASentence globalConstraint(CCASentence::CNF);
    00574
    00575         DOMNodeList* children = _node->getChildNodes();
    00576         int numChildren = children->getLength();
    00577
    00578         string modeVariableName;
    00579
    00580         #ifdef __DEBUG
    00581                 cout << "Parsing Component" << endl;
    00582         #endif
    00583
    00584         // Visit all nodes at this depth
    00585         for (int i = 0; i < numChildren; i++)
    00586         {
    00587                 DOMNode* childNode = children->item(i);
    00588
    00589                 // only concerned with element nodes for now...
    00590                 if (childNode->getNodeType() == DOMNode::ELEMENT_NODE)
    00591                 {
    00592                         try
    00593                         {
    00594                                 // The action to perform depends upon the element type
    00595                                 string nodeName = getString(childNode->getNodeName());
    00596
    00597                                 if (nodeName.compare(MODE_TAG) == 0)
    00598                                 {
    00599                                         modeVariableName = parseMode(childNode, _model, _ancestors);
    00600                                 }
    00601                                 else if (nodeName.compare(VARIABLE_TAG) == 0)
    00602                                 {
    00603                                         string var = parseVariable(childNode, _model, _variableMap,
    00604                                                 _ancestors, modeVariableName);
    00605                                         // We no longer need domain constraints.
    00606                                         //createDomainConstraint(var, _model);
    00607                                 }
    00608                                 else if (nodeName.compare(TRANSITION_TAG) == 0)
    00609                                 {
    00610                                         parseTransition(childNode, _model,
    00611                                                 _ancestors, modeVariableName);
    00612                                 }
    00613                                 else if (nodeName.compare(CLAUSE_TAG) == 0)
    00614                                 {
    00615                                         vector<CCAClause> clauses;
    00616                                         string modeValueAssociation("");
    00617
    00618                                         parseClause(childNode, _model, _ancestors, modeVariableName,
    00619                                                 clauses, modeValueAssociation);
    00620
    00621                                         if (modeValueAssociation.size() != 0) {
    00622                                                 vector<CCAClause> * clausesForModeValue =
    00623                                                         clauseMap[modeValueAssociation];
    00624
    00625                                                 if (clausesForModeValue == NULL) {
    00626                                                         clausesForModeValue = new vector<CCAClause>;
    00627                                                         clauseMap[modeValueAssociation] = clausesForModeValue;
    00628                                                 }
    00629
    00630                                                 clausesForModeValue->insert(
    00631                                                         clausesForModeValue->end(),
    00632                                                         clauses.begin(),
    00633                                                         clauses.end());
    00634                                         } else {
    00635                                                 #ifdef __DEBUG
    00636                                                 cout << "Added Clause to global constraint" << endl;
    00637                                                 #endif
    00638                                                 for (vector<CCAClause>::const_iterator it = clauses.begin();
    00639                                                                 it != clauses.end(); ++it)
    00640                                                 {
    00641                                                         globalConstraint.insert_clause(*it);
    00642                                                 }
    00643                                         }
    00644                                 }
    00645                         }
    00646                         catch (ParsingException ex)
    00647                         {
    00648                                 throw;
    00649                         }
    00650                 }
    00651         }
    00652
    00653         _model.insert_global_constraint(globalConstraint);
    00654
    00655         const CCAVariable *modeVar = _model.get_variable_p(String(modeVariableName.c_str()));
    00656
    00657         if (modeVar != NULL) {
    00658                 const CCAValues *vals = modeVar->getDomain();
    00659                 CCAValues::const_iterator valItr = vals->begin();
    00660
    00661
    00662                 for (; valItr != vals->end(); ++valItr) {
    00663                         CCASentence constraint(CCASentence::CNF);
    00664
    00665                         vector<CCAClause> * clauses =   clauseMap[(*valItr).getName()];
    00666
    00667                         // make sure we get an empty constraint
    00668                         if (clauses == NULL) {
    00669                                 constraint.insert_clause(CCAClause(CCAClause::CONJUNCTIVE));
    00670                                 _model.set_state_constraint(String(modeVariableName.c_str()),
    00671                                         String((*valItr).getName()), constraint);
    00672                                 continue;
    00673                         }
    00674
    00675                         vector<CCAClause>::const_iterator clauseItr= clauses->begin();
    00676
    00677                         for (; clauseItr != clauses->end(); ++clauseItr) {
    00678                                 constraint.insert_clause(*clauseItr);
    00679                         }
    00680
    00681                         #ifdef __DEBUG
    00682                                 cout << "Setting State Constraint (" << modeVariableName << ", "
    00683                                           << (*valItr).getName() << "): " << constraint << endl;
    00684                         #endif
    00685
    00686                         _model.set_state_constraint(String(modeVariableName.c_str()),
    00687                                 String((*valItr).getName()), constraint);
    00688
    00689                         //delete clauses;
    00690                 }
    00691         }
    00692
    00693         return componentName;
    00694 }
    00695
    00696
    00697 void
    00698 XmplParser::createDomainConstraint(
    00699                 const string &_var,
    00700                 CCAModel &_model)
    00701         throw (ParsingException)
    00702 {
    00703         const CCAVariable *var = _model.get_variable_p(String(_var.c_str()));
    00704
    00705         assert(var != NULL);
    00706
    00707         const CCAValues *vals = var->getDomain();
    00708         CCAValues::const_iterator valItr = vals->begin();
    00709         CCASentence constraint(CCASentence::CNF);
    00710
    00711         for (; valItr != --(vals->end()); ++valItr) {
    00712                 CCAValues::const_iterator valItr2 = valItr;
    00713                 ++valItr2;
    00714
    00715                 for (; valItr2 != vals->end(); ++valItr2) {
    00716                         CCAAssignment lit1 = createSimpleLiteral(
    00717                                 false, var->getName(), (*valItr).getName(), _model);
    00718                         CCAAssignment lit2 = createSimpleLiteral(
    00719                                 false, var->getName(), (*valItr2).getName(), _model);
    00720
    00721                         CCAClause cl(true);
    00722
    00723                         cl.insert_assignment(lit1);
    00724                         cl.insert_assignment(lit2);
    00725
    00726                         constraint.insert_clause(cl);
    00727                 }
    00728         }
    00729
    00730         valItr = vals->begin();
    00731         CCAClause cl(true);
    00732
    00733         for (; valItr != vals->end(); ++valItr) {
    00734                 CCAAssignment lit = createSimpleLiteral(
    00735                         true, var->getName(), (*valItr).getName(), _model);
    00736                 cl.insert_assignment(lit);
    00737         }
    00738
    00739         constraint.insert_clause(cl);
    00740
    00741         _model.insert_global_constraint(constraint);
    00742 }
    00743
    00744
    00745 string
    00746 XmplParser::parseEnumeration(
    00747                 const DOMNode* _node,
    00748                 CCAModel &_model,
    00749                 const AncestorList &_ancestors)
    00750         throw (ParsingException)
    00751 {
    00752         if (!_node->hasAttributes())
    00753                 throw ParsingException("enumeration has no attributes");
    00754
    00755         string name = getAttribute(_node, "name");
    00756         string membersStr = getAttribute(_node, "members");
    00757         CCAValues members = new CCAValues(true, BaseModelObject::BMDomain);
    00758
    00759         char *allMembers = new char[membersStr.length()+1];
    00760         char *tok;
    00761         strcpy(allMembers, membersStr.c_str());
    00762
    00763         tok = strtok(allMembers, " ");
    00764         // TODO set ids???
    00765         while (tok != NULL)
    00766         {
    00767                 members.insert_value(CCAValue(tok));
    00768                 tok = strtok(NULL, " ");
    00769         }
    00770
    00771         delete allMembers;
    00772
    00773         name = _ancestors.qualify(name, AncestorList::ROOT);
    00774
    00775         if (members.isEmpty())
    00776                 throw ParsingException("enumeration has no members");
    00777
    00778         // add domain to model
    00779         _model.insert_domain(String(name.c_str()), members);
    00780
    00781         #ifdef __DEBUG
    00782                 cout << "Inserting domain '" << name << "' : " << members << endl;
    00783         #endif
    00784
    00785         return name;
    00786 }
    00787
    00788
    00789 string
    00790 XmplParser::parseMode(
    00791                 const DOMNode* _node,
    00792                 CCAModel &_model,
    00793                 const AncestorList &_ancestors)
    00794         throw (ParsingException)
    00795 {
    00796         if (!_node->hasAttributes())
    00797                 throw ParsingException("mode has no attributes");
    00798
    00799         string modeVariableName = getAttribute(_node, "vars");
    00800
    00801         modeVariableName = _ancestors.qualify(modeVariableName);
    00802
    00803         #ifdef __DEBUG
    00804                 cout << "Mode Variable: " << modeVariableName << endl;
    00805         #endif
    00806
    00807         return modeVariableName;
    00808 }
    00809
    00810
    00811 string
    00812 XmplParser::parseVariable(
    00813                 const DOMNode* _node,
    00814                 CCAModel &_model,
    00815                 VariableInfoMap &_variableMap,
    00816                 const AncestorList &_ancestors,
    00817                 const string &_modeVariableName)
    00818         throw (ParsingException)
    00819 {
    00820         if (!_node->hasAttributes())
    00821                 throw ParsingException("model attribute has no attributes");
    00822
    00823         string name = _ancestors.qualify(getAttribute(_node, "name"));
    00824         string domain = _ancestors.qualify(
    00825                 getAttribute(_node, "type"), AncestorList::ROOT);
    00826
    00827
    00828         #ifdef __DEBUG
    00829                 cout << "Parsing Variable: " << name << endl;
    00830         #endif
    00831
    00832         CCAVariable::VariableType variableType = CCAVariable::DEPENDENT;
    00833
    00834         if (_modeVariableName.compare(name) == 0){
    00835                 variableType = CCAVariable::STATE;
    00836         } else if (_variableMap.has(name))
    00837         {
    00838                 // use the hrn file to resolve the type.
    00839                 variableType = _variableMap.get(name)._type;
    00840         }
    00841
    00842         // add the new variable to the model
    00843         _model.insert_variable(
    00844                 String(name.c_str()), variableType, String(domain.c_str()));
    00845
    00846         return name;
    00847 }
    00848
    00849
    00850 string
    00851 XmplParser::parseTransition(
    00852                 const DOMNode* _node,
    00853                 CCAModel &_model,
    00854                 const AncestorList &_ancestors,
    00855                 const string &_modeVariableName)
    00856         throw (ParsingException)
    00857 {
    00858         if (!_node->hasAttributes())
    00859                 throw ParsingException("transition has no attributes");
    00860
    00861         string name = getAttribute(_node, "name", true);
    00862         string from = getAttribute(_node, "from");
    00863         string to = getAttribute(_node, "to");
    00864
    00865         bool hasProbability = true;
    00866         double prob = 1.0;
    00867         string probString = getAttribute(_node, "probability", true);
    00868         if (probString == "") {
    00869                 hasProbability = false;
    00870         }
    00871         if (hasProbability)
    00872                 sscanf((char*)(probString.c_str()), "%lf", &prob);
    00873
    00874         #ifdef __DEBUG
    00875                 cout << "Parsing Transition: " << name << " from " << from << " to "
    00876                      << to << endl;
    00877         #endif
    00878
    00879         // Parse the transition guard, which is a full sentence
    00880         DOMNodeList* children = _node->getChildNodes();
    00881         int numChildren = children->getLength();
    00882         vector<CCAClause> guardClauseVec;
    00883         for (int i = 0; i < numChildren; i++) {
    00884                 DOMNode* childNode = children->item(i);
    00885
    00886                 if (childNode->getNodeType() != DOMNode::ELEMENT_NODE)
    00887                         continue;
    00888
    00889                 // xmpl transition gaurd clauses are disjunctive.
    00890                 // the guardClauseVec is passed by reference, and thus is built up over
    00891                 // the series of calls.
    00892                 if (!parseClause(childNode, _model, _ancestors, _modeVariableName,
    00893                          guardClauseVec, CCAClause::DISJUNCTIVE))
    00894                 {
    00895                         // NOTE: This is probably no longer valid.
    00896                         throw ParsingException(
    00897                                 string("A literal of type variable=variable was ")
    00898                                 + "found in a guard clause.");
    00899                 }
    00900         }
    00901
    00902         // Take the list of clauses, and place them into a sentence
    00903         // do this in a separate loop in case we can allow var=var literals
    00904         CCASentence full_guard = CCASentence(CCASentence::CNF);
    00905         for (vector<CCAClause>::const_iterator it = guardClauseVec.begin();
    00906                 it != guardClauseVec.end(); ++it)
    00907         {
    00908                 // we created the clauses as disjuncts
    00909                 full_guard.insert_clause((*it));
    00910         }
    00911
    00912         // Titan expects the transition guard clause to be conjunctive
    00913         CCAClause guard = CCAClause(CCAClause::CONJUNCTIVE);
    00914
    00915         // To for the transition guard clause, simply use the first clause of
    00916         // the sentence.
    00917         // Unfortunately, this means that sentences w/ > 1 clause are incompatible
    00918         // with the original Titan implementation.
    00919         if (!guardClauseVec.empty())
    00920         {
    00921                 guard = invertClause(guardClauseVec[0]);
    00922                 if (guardClauseVec.size() > 1)
    00923                         cout << "[warning]: transition guard contains > 1 clause, and is incompatible with original Titan transition function\n";
    00924         }
    00925
    00926         #ifdef __DEBUG
    00927                 cout << "Guard Clause: " << guard << endl;
    00928         #endif
    00929
    00930         if (from == "*") {
    00931                 const CCAVariable *modeVar = _model.get_variable_p(String(_modeVariableName.c_str()));
    00932                 const CCAValues *toValues = modeVar->getDomain();
    00933                 CCAValues::const_iterator it = toValues->begin();
    00934
    00935                 for (; it != toValues->end(); ++it) {
    00936                         string from = (*it).getName();
    00937                         if (from != to)
    00938                                 _model.insert_transition(String(_modeVariableName.c_str()),
    00939                                         String(from.c_str()),
    00940                                         String(to.c_str()), guard, /*full_guard,*/ prob);
    00941                 }
    00942         } else {
    00943                 _model.insert_transition(String(_modeVariableName.c_str()),
    00944                         String(from.c_str()),
    00945                         String(to.c_str()), guard, /*full_guard,*/ prob);
    00946         }
    00947
    00948         // Because state variables do not have fault/nominal semantics encoded
    00949         // in XMPL, we will use the transition to make an educated guess as to
    00950         // the disposition of the "to" state.  i.e. the "to" state of a fault
    00951         // transition is a fault mode, while the "to" state of a nominal
    00952         // transition is a nominal mode.
    00953         //
    00954         // The problem here is that while we know a tranisition is a failure if it
    00955         // is given a probability, if its not it could be either. So we don;t want
    00956         // to overwrite failure stateTypes with nominal ones. to do this, we'll
    00957         // always set failure if it should be, and only set nominal if the state
    00958         // isn't failure. If it defaults to failure, we're hurtin' (but there's
    00959         // probably a reason for UNKNOWN...)
    00960         //
    00961         // Some more comments:
    00962         // - Technically, it probably doesn't matter whether the state is marked
    00963         //   as nominal or failure.  The core algorithm doesn't care.
    00964         // - In the near future, we may try to erase the distinction between
    00965         //   nominal and fault states/transitions.  All transitions may then have
    00966         //   a rank value and all may support a from state of "*".  That change
    00967         //   will clearly break this logic, but it also will not matter.
    00968         if (hasProbability)
    00969                 _model.set_state_type(String(_modeVariableName.c_str()),
    00970                         String(to.c_str()), CCAState::FAILURE);
    00971         else {
    00972                 CCAAssignment a = _model.get_assignment(String(_modeVariableName.c_str()),
    00973                                                         String(to.c_str()));
    00974                 const CCAState *s = _model.get_state_p(a);
    00975
    00976                 if (s->type() != CCAState::FAILURE)
    00977                         _model.set_state_type(String(_modeVariableName.c_str()),
    00978                                 String(to.c_str()), CCAState::NOMINAL);
    00979         }
    00980
    00981         return name;
    00982 }
    00983
    00984
    00991 CCAClause
    00992 XmplParser::invertClause(CCAClause guard) {
    00993         CCAClause ret = CCAClause(CCAClause::CONJUNCTIVE);
    00994
    00995         for (CCAClause::const_iterator it = guard.begin(); it != guard.end(); ++it) {
    00996                 const CCAAssignment & lit = (*it);
    00997                 CCAAssignment::OperatorType invertedType = (
    00998                         (lit.getOperator() == CCAAssignment::POSITIVE) ?
    00999                         CCAAssignment::NEGATIVE : CCAAssignment::POSITIVE
    01000                 );
    01001
    01002                 ret.insert_assignment(CCAAssignment(lit.getVariable(),
    01003                                                     lit.getValue(),
    01004                                                     invertedType));
    01005         }
    01006
    01007         return ret;
    01008 }
    01009
    01010
    01011 bool
    01012 XmplParser::parseClause(
    01013                 const DOMNode* _node,
    01014                 const CCAModel &_model,
    01015                 const AncestorList &_ancestors,
    01016                 const string &_modeVariableName,
    01017                 vector<CCAClause> &_clauses,
    01018                 CCAClause::ClauseType  _clauseType)
    01019         throw (ParsingException)
    01020 {
    01021         string toss;
    01022
    01023         return parseClause(_node, _model, _ancestors, _modeVariableName,
    01024                 _clauses, toss, false, _clauseType);
    01025 }
    01026
    01027
    01028 bool
    01029 XmplParser::parseClause(
    01030                 const DOMNode* _node,
    01031                 const CCAModel &_model,
    01032                 const AncestorList &_ancestors,
    01033                 const string &_modeVariableName,
    01034                 vector<CCAClause> &_clauses,
    01035                 string &_modeValueAssociation,
    01036                 bool _inspectForModeAssociation,
    01037                 CCAClause::ClauseType _clauseType)
    01038         throw (ParsingException)
    01039 {
    01040 //      _clauses.clear();
    01041         CCAClause simpleClause(_clauseType);
    01042
    01043         _modeValueAssociation = "";
    01044         bool hasCompoundLiteral = false;
    01045         list<ParsedLiteral> parsedLiterals;
    01046
    01047
    01048         #ifdef __DEBUG
    01049                 cout << "Parsing Clause" << endl;
    01050         #endif
    01051
    01052         // clauses may be empty, in which case they are ignored
    01053         if (! _node->hasChildNodes())
    01054         {
    01055                 #ifdef __DEBUG
    01056                 cout << "[DEBUG]: empty clause detected" << endl;
    01057                 //printNode(_node, 10);
    01058                 #endif
    01059                 return true;
    01060         }
    01061
    01062         DOMNodeList* children = _node->getChildNodes();
    01063
    01064         // for each term element
    01065         for (unsigned int i = 0; i < children->getLength(); i++)
    01066         {
    01067                 DOMNode* childNode = children->item(i);
    01068                 string nodeName = getString(childNode->getNodeName());
    01069
    01070                 if (childNode->getNodeType() != DOMNode::ELEMENT_NODE)
    01071                         continue;
    01072
    01073                 if (nodeName != TERM_TAG)
    01074                         throw ParsingException(
    01075                                 "Element " + nodeName + " unexpected in clause element");
    01076
    01077                 // sometimes the xml parser refuses to remove whitespace,
    01078                 // so checks like this are invalid, as we will get empty
    01079                 // '#text' elements
    01080                 //if (children->getLength() > 1)
    01081                 //      throw ParsingException("More than one element found in term.");
    01082
    01083                 // Parse the ci:term node
    01084                 DOMNodeList* termChildren = childNode->getChildNodes();
    01085                 unsigned int j = 0;
    01086
    01087                 for (j = 0; j < termChildren->getLength(); j++)
    01088                 {
    01089                         DOMNode* textNode = termChildren->item(j);
    01090
    01091                         if (textNode->getNodeType() != DOMNode::TEXT_NODE)
    01092                         {
    01093                                 cerr << "[warning] Unxpected node in term, expected only text."
    01094                                      << endl;
    01095                                 continue;
    01096                         }
    01097
    01098                         ParsedLiteral pLiteral = parseLiteral(
    01099                                 textNode, _ancestors, _model);
    01100
    01101                         list<ParsedLiteral>::const_iterator it = parsedLiterals.begin();
    01102
    01103                         // make sure we don't have duplicate literals. This happens sometimes
    01104                         // in xmpl.
    01105                         for (; it != parsedLiterals.end(); ++it) {
    01106                                 if (pLiteral.var == (*it).var &&
    01107                                                 pLiteral.val == (*it).val)
    01108                                         break;
    01109                         }
    01110
    01111                         // I will resist the goto...
    01112                         if (it != parsedLiterals.end())
    01113                                 break;
    01114
    01115                         if (pLiteral.valIsVariable) {
    01116                                 if (hasCompoundLiteral)
    01117                                         throw ParsingException(
    01118                                                 "Clause found with more than one compound literals");
    01119                                 parsedLiterals.push_back(pLiteral);
    01120                                 hasCompoundLiteral = true;
    01121                         }
    01122                         else
    01123                                 parsedLiterals.push_front(pLiteral);
    01124
    01125
    01126                         // terms only contain one text element, the literal, and we've
    01127                         // already processed it.
    01128                         break;
    01129
    01130                 }
    01131         }
    01132
    01133
    01134         // parse the compound literal, if one exists.
    01135         vector<CCAClause> compoundLit;
    01136
    01137         if (hasCompoundLiteral) {
    01138                 ParsedLiteral pLiteral = parsedLiterals.back();
    01139                 parsedLiterals.pop_back();
    01140
    01141                 compoundLit =
    01142                         createCompoundLiteral(pLiteral.isPositive,
    01143                         pLiteral.var, pLiteral.val, _model);
    01144
    01145         }
    01146
    01147         list<ParsedLiteral>::const_iterator it = parsedLiterals.begin();
    01148
    01149         for (; it != parsedLiterals.end(); ++it) {
    01150                 if (_inspectForModeAssociation
    01151                                 && _modeVariableName.compare((*it).var) == 0)
    01152                 {
    01153                         _modeValueAssociation = (*it).val;
    01154                         continue;
    01155                 }
    01156
    01157                 CCAAssignment lit = createSimpleLiteral(
    01158                         (*it).isPositive,       (*it).var, (*it).val, _model);
    01159
    01160                 if (!hasCompoundLiteral) {
    01161                         simpleClause.insert_assignment(lit);
    01162                 } else {
    01163                         vector<CCAClause>::iterator it = compoundLit.begin();
    01164
    01165                         for (; it != compoundLit.end(); ++it) {
    01166                                 (*it).insert_assignment(lit);
    01167                         }
    01168                 }
    01169         }
    01170
    01171         if (hasCompoundLiteral) {
    01172                 _clauses.insert(
    01173                         _clauses.end(),
    01174                         compoundLit.begin(),
    01175                         compoundLit.end()
    01176                 );
    01177         } else
    01178                 _clauses.push_back(simpleClause);
    01179
    01180         return (!hasCompoundLiteral);
    01181 }
    01182
    01183 XmplParser::ParsedLiteral
    01184 XmplParser::parseLiteral(
    01185                 const DOMNode* _node,
    01186                 const AncestorList &_ancestors,
    01187                 const CCAModel &_model)
    01188         throw (ParsingException)
    01189 {
    01190         ParsedLiteral pLiteral;
    01191         string text = getString(_node->getNodeValue());
    01192
    01193         pLiteral.isPositive = (text[0] == '!') ? false : true;
    01194         string equals;
    01195
    01196         int equalPos = text.find('=');
    01197
    01198         if (pLiteral.isPositive)
    01199                 pLiteral.var = text.substr(0, equalPos);
    01200         else
    01201                 pLiteral.var = text.substr(1, equalPos - 1);
    01202
    01203         pLiteral.var = _ancestors.qualify(pLiteral.var);
    01204
    01205         // qualify the variable name, and get it from the model
    01206         const CCAVariable * var = _model.get_variable_p(String(pLiteral.var.c_str()));
    01207         if (var == NULL)
    01208                 throw ParsingException(
    01209                         "Could not find '" + pLiteral.var + "' in term " + text);
    01210
    01211         string equalsStr = text.substr(equalPos + 1, text.size() - equalPos + 1);
    01212         string qualifiedEqualsStr(_ancestors.qualify(equalsStr));
    01213
    01214         // see if the rValue is a enum member or a variable
    01215         if (_model.get_variable_p(String(qualifiedEqualsStr.c_str())) == NULL)
    01216         {
    01217                 // if it is a enum member, make sure it exists in the
    01218                 // domain of the variable, and create the proposition
    01219                 const CCAValue * valuePtr = var->getDomain()->getValue(equalsStr.c_str());
    01220                 if (valuePtr == NULL)
    01221                         throw ParsingException("\"" + equalsStr + "\""
    01222                                 " is not in the domain of \"" + var->getName() + "\" and is not an identifiable variable");
    01223
    01224                 pLiteral.val = equalsStr;
    01225                 pLiteral.valIsVariable = false;
    01226         }
    01227         else
    01228         {
    01229                 // at this point we know the variable exists, so we need to create
    01230                 // the literals that are extrapolated from this var=var pairing.
    01231                 pLiteral.val = qualifiedEqualsStr;
    01232                 pLiteral.valIsVariable = true;
    01233         }
    01234
    01235         #ifdef __DEBUG
    01236                 cout << "Parsed Literal: " << (pLiteral.isPositive ? "(" : "!(")
    01237                      << pLiteral.var << " = " << pLiteral.val << ")" << endl;
    01238         #endif
    01239
    01240         return pLiteral;
    01241 }
    01242
    01243
    01244 CCAAssignment
    01245 XmplParser::createSimpleLiteral(
    01246                 bool _isPositive,
    01247                 const string &_var,
    01248                 const string &_val,
    01249                 const CCAModel &_model)
    01250 {
    01251         #ifdef __DEBUG
    01252                 cout << "Creating Simple Literal " << (_isPositive ? "(" : "!(")
    01253                      << _var << " = " << _val << ")" << endl;
    01254         #endif
    01255
    01256         CCAAssignment assign = _model.get_assignment(
    01257                         String(_var.c_str()), String(_val.c_str()));
    01258
    01259         return CCAAssignment(
    01260                 assign.getVariable(),
    01261                 assign.getValue(),
    01262                 (_isPositive ? CCAAssignment::POSITIVE : CCAAssignment::NEGATIVE)
    01263         );
    01264 }
    01265
    01266 vector<CCAClause>
    01267 XmplParser::createCompoundLiteral(
    01268                 bool isPositive,
    01269                 const string &_lhVar,
    01270                 const string &_rhVar,
    01271                 const CCAModel &_model)
    01272         throw (ParsingException)
    01273 {
    01274
    01275         const CCAVariable * lhVarPtr = _model.get_variable_p(String(_lhVar.c_str()));
    01276         const CCAVariable * rhVarPtr = _model.get_variable_p(String(_rhVar.c_str()));
    01277         assert(lhVarPtr);
    01278         assert(rhVarPtr);
    01279
    01280         const CCAValues * lhValuesPtr = lhVarPtr->getDomain();
    01281         const CCAValues * rhValuesPtr = rhVarPtr->getDomain();
    01282
    01283         // make sure the variables are of the same type
    01284         if (lhVarPtr->getDomain()->getName() != rhVarPtr->getDomain()->getName())
    01285                 throw ParsingException("malformed compound proposition");
    01286
    01287         vector<CCAClause> clauses;
    01288
    01289         // go through the entire domain
    01290         CCAValues::const_iterator lhValuesItr = lhValuesPtr->begin();
    01291         CCAValues::const_iterator rhValuesItr = rhValuesPtr->begin();
    01292         for ( ; lhValuesItr != lhValuesPtr->end();
    01293                   ++lhValuesItr, ++rhValuesItr)
    01294         {
    01295                 CCAAssignment lAssign = _model.get_assignment(
    01296                         String(_lhVar.c_str()), String((*lhValuesItr).getName()));
    01297                 CCAAssignment rAssign = _model.get_assignment(
    01298                         String(_rhVar.c_str()), String((*rhValuesItr).getName()));
    01299
    01300                 // (A != e1 | B != e1) & (A != e2 | B != e2) ...
    01301                 if (!isPositive)
    01302                 {
    01303                         CCAClause c1(CCAClause::DISJUNCTIVE);
    01304
    01305                         c1.insert_assignment(createSimpleLiteral(
    01306                                 false, _lhVar, (*lhValuesItr).getName(), _model));
    01307                         c1.insert_assignment(createSimpleLiteral(
    01308                                 false, _rhVar, (*rhValuesItr).getName(), _model));
    01309
    01310                         clauses.push_back(c1);
    01311                 }
    01312                 // (A = e1 | B != e1) & (B = e1 | A != e1) ...
    01313                 else
    01314                 {
    01315                         CCAClause c1(CCAClause::DISJUNCTIVE);
    01316                         CCAClause c2(CCAClause::DISJUNCTIVE);
    01317
    01318                         c1.insert_assignment(createSimpleLiteral(
    01319                                 true, _lhVar, (*lhValuesItr).getName(), _model));
    01320                         c1.insert_assignment(createSimpleLiteral(
    01321                                 false, _rhVar, (*rhValuesItr).getName(), _model));
    01322
    01323                         c2.insert_assignment(createSimpleLiteral(
    01324                                 true, _rhVar, (*rhValuesItr).getName(), _model));
    01325                         c2.insert_assignment(createSimpleLiteral(
    01326                                 false, _lhVar, (*lhValuesItr).getName(), _model));
    01327
    01328                         clauses.push_back(c1);
    01329                         clauses.push_back(c2);
    01330                 }
    01331         }
    01332
    01333         return clauses;
    01334 }
    01335
    01336
    01337 string
    01338 XmplParser::getAttribute(
    01339         const DOMNode* _node, const string &_attributeName, bool _failSilent)
    01340         throw (ParsingException)
    01341 {
    01342         bool errorOccured = false;
    01343
    01344         const DOMNamedNodeMap* attributes = _node->getAttributes();
    01345         const XMLCh* name = XMLString::transcode(_attributeName.c_str());
    01346
    01347         DOMNode* currAttribute = attributes->getNamedItem(name);
    01348
    01349         string nodeValue;
    01350         if (currAttribute == NULL
    01351             || currAttribute->getNodeType() != DOMNode::ATTRIBUTE_NODE){
    01352                         errorOccured = true;
    01353         }
    01354         else {
    01355                 nodeValue = getString(currAttribute->getNodeValue());
    01356
    01357                 // we always require non-empty strings
    01358                 if (nodeValue.length() <= 0)
    01359                         errorOccured = true;
    01360         }
    01361
    01362         if (!errorOccured)
    01363                 return nodeValue;
    01364
    01365         if (_failSilent)
    01366                 return string("");
    01367         else
    01368                 throw ParsingException(
    01369                         "attribute " + _attributeName + " does not have a value");
    01370 }
    01371
    01372 //------------------------------------------------------------------------------
    01373 // class: XmplParser::MyErrorHandler
    01374 //------------------------------------------------------------------------------
    01375 bool
    01376 XmplParser::MyErrorHandler::handleError(const DOMError & domError)
    01377 {
    01378         cerr << "[XML WARNING]: " << getString(domError.getMessage())
    01379                 << " at line: " << domError.getLocation()->getLineNumber() << endl;
    01380         return true;
    01381 }
    01382
    01383 //------------------------------------------------------------------------------
    01384 // class: XmplParser::AncestorList
    01385 //------------------------------------------------------------------------------
    01386 void
    01387 XmplParser::AncestorList::unit_test() {
    01388         string test1 = "root_name";
    01389         string test2 = "component1.sub1.sub2";
    01390         string child1 = "instance";
    01391
    01392         cout << "--<  Begin AncestorList::unit_test  >--" << endl << endl;
    01393
    01394         cout << "Pushing '" << test1 << "'" << endl;
    01395         push(test1);
    01396
    01397         cout << "Pushing '" << test2 << "'" << endl;
    01398         push(test2);
    01399
    01400         cout << "Root Qualifying '" << child1 << "' -> '"
    01401              << qualify(child1, ROOT) << "'" << endl;
    01402
    01403         cout << "All Qualifying '" << child1 << "' -> '"
    01404              << qualify(child1) << "'" << endl;
    01405
    01406         cout << "Root of Ancestor List: '" << root() << "'" << endl;
    01407         cout << "Peek of Ancestor List: '" << peek() << "'" << endl;
    01408
    01409         cout << "Ancestor List : ";
    01410
    01411         vector<string>::const_iterator it = _ancestors.begin();
    01412         for (; it != _ancestors.end(); ++it)
    01413         {
    01414                 cout << "'" << *it << "' ";
    01415         }
    01416
    01417         cout << endl << endl;
    01418         cout << "--<   End AncestorList::unit_test   >--" << endl;
    01419
    01420         popToRoot();
    01421         pop();
    01422 }
    01423
    01424
    01425 void
    01426 XmplParser::AncestorList::push(const string ancestor) {
    01427         string str(ancestor);
    01428         unsigned found = ancestor.find('.');
    01429
    01430         if (found >= string::npos) {
    01431                 _ancestors.push_back(ancestor);
    01432                 return;
    01433         }
    01434
    01435         while (found < string::npos) {
    01436                 str.replace(found, 1, " ");
    01437                 found = str.find(".", found + 1);
    01438         }
    01439
    01440         istringstream tokenizer(str);
    01441         string tok;
    01442
    01443         if (tokenizer.good()) {
    01444                 tokenizer >> tok;
    01445
    01446                 if (!isEmpty() && tok.compare(root()) != 0) {
    01447                         _ancestors.push_back(tok);
    01448                 }
    01449
    01450                 while (tokenizer.good()) {
    01451                         tokenizer >> tok;
    01452                         _ancestors.push_back(tok);
    01453                 }
    01454         }
    01455 }
    01456
    01457
    01458 string
    01459 XmplParser::AncestorList::pop() {
    01460         string ret = _ancestors.back();
    01461
    01462         // pop dosn't return a value?
    01463         _ancestors.pop_back();
    01464         return ret;
    01465 }
    01466
    01467
    01468 void
    01469 XmplParser::AncestorList::popToRoot() {
    01470         while (_ancestors.size() > 1) {
    01471                 pop();
    01472         }
    01473 }
    01474
    01475
    01476 string
    01477 XmplParser::AncestorList::peek() const {
    01478         return _ancestors.back();
    01479 }
    01480
    01481
    01482 string
    01483 XmplParser::AncestorList::root() const {
    01484         return _ancestors.front();
    01485 }
    01486
    01487
    01488 bool
    01489 XmplParser::AncestorList::isEmpty() const {
    01490         return _ancestors.size() == 0;
    01491 }
    01492
    01493
    01494 string
    01495 XmplParser::AncestorList::qualify(
    01496         const string &child, qualificationLevel level) const
    01497 {
    01498         // If there is no ancestor list built up, there is nothing to do
    01499         if (_ancestors.size() == 0)
    01500                 return child;
    01501
    01502         // ** Special Case **
    01503         // Although this is not currently the case in "official" XMPL, we will
    01504         // be making modifications s.t. certain items, which were defined
    01505         // relative to the containing entity before, will now be fully qualified.
    01506         // For example, compiling a guard clause converts a local dependent
    01507         // variable (e.g. "power-in") into a global state variable reference
    01508         // (e.g. "Model.battery.mode").
    01509         //
    01510         // In the case of an item that is already fully qualified, do not
    01511         // re-fully qualify it!
    01512         if (child.find(_ancestors[0]) == 0)
    01513                 return child;
    01514
    01515         string qualifiedStr("");
    01516
    01517         if (_fullyQualify)
    01518                 qualifiedStr += _ancestors[0] + ".";
    01519
    01520         if (level == ROOT || _ancestors.size() == 1)
    01521                 return qualifiedStr + child;
    01522
    01523         // @TODO: some caching?
    01524         vector<string>::const_iterator it = _ancestors.begin();
    01525         ++it;
    01526         for (; it != _ancestors.end(); ++it)
    01527         {
    01528                 qualifiedStr += *it + ".";
    01529         }
    01530
    01531         qualifiedStr += child;
    01532
    01533         return qualifiedStr;
    01534 }
    01535
    01536 //==============================================================================