From 7afc6a257e193986c9305364701085e65c4ccea5 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Thu, 4 Feb 2016 01:10:57 +0100 Subject: Preliminary support for SCXML invocations in generated C machines --- apps/uscxml-transform.cpp | 44 +- src/uscxml/DOMUtils.cpp | 92 +- src/uscxml/DOMUtils.h | 29 +- src/uscxml/Interpreter.cpp | 35 +- src/uscxml/interpreter/InterpreterFast.cpp | 10 +- src/uscxml/interpreter/InterpreterFast.h | 26 +- src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 1 + src/uscxml/transform/ChartToC.cpp | 1227 ++++++++++++-------- src/uscxml/transform/ChartToC.h | 26 +- src/uscxml/transform/ChartToVHDL.cpp | 230 ++-- src/uscxml/transform/ChartToVHDL.h | 19 +- src/uscxml/transform/Transformer.h | 24 +- test/ctest/CTestCustom.ctest.in | 74 +- test/src/test-c-machine.cpp | 1067 +++++++++-------- test/src/test-c-machine.machine.c | 722 +++++++----- 15 files changed, 2126 insertions(+), 1500 deletions(-) diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp index fcc9965..857a160 100644 --- a/apps/uscxml-transform.cpp +++ b/apps/uscxml-transform.cpp @@ -94,9 +94,9 @@ void printUsageAndExit(const char* progName) { printf("\t verbose - comments detailling state changes and transitions for content selection (-tflat only)\n"); printf("\t progress - insert comments documenting progress in dociment (-tmin only)\n"); printf("\t nocomment - surpress the generation of comments in output\n"); - printf("\t-X {PARAMETER} : pass additional parameters to the transformation\n"); - printf("\t prefix=ID - prefix all symbols and identifiers with ID (-tc)\n"); - printf("\t-v : be verbose\n"); + printf("\t-X {PARAMETER} : pass additional parameters to the transformation\n"); + printf("\t prefix=ID - prefix all symbols and identifiers with ID (-tc)\n"); + printf("\t-v : be verbose\n"); printf("\t-lN : Set loglevel to N\n"); printf("\t-i URL : Input file (defaults to STDIN)\n"); printf("\t-o FILE : Output file (defaults to STDOUT)\n"); @@ -113,8 +113,8 @@ int main(int argc, char** argv) { std::string inputFile; std::string outputFile; std::list options; - std::multimap extensions; - + std::multimap extensions; + #if defined(HAS_SIGNAL_H) && !defined(WIN32) signal(SIGPIPE, SIG_IGN); #endif @@ -129,8 +129,8 @@ int main(int argc, char** argv) { struct option longOptions[] = { {"verbose", no_argument, 0, 'v'}, {"type", required_argument, 0, 't'}, - {"annotate", required_argument, 0, 'a'}, - {"param", required_argument, 0, 'X'}, + {"annotate", required_argument, 0, 'a'}, + {"param", required_argument, 0, 'X'}, {"plugin-path", required_argument, 0, 'p'}, {"input-file", required_argument, 0, 'i'}, {"output-file", required_argument, 0, 'o'}, @@ -167,15 +167,15 @@ int main(int argc, char** argv) { case 'a': options = InterpreterImpl::tokenize(optarg, ','); break; - case 'X': { - std::list extension = InterpreterImpl::tokenize(optarg, '='); - if (extension.size() != 2) - printUsageAndExit(argv[0]); - std::string key = boost::trim_copy(*(extension.begin())); - std::string value = boost::trim_copy(*(++extension.begin())); - extensions.insert(std::pair(key, value)); - } - break; + case 'X': { + std::list extension = InterpreterImpl::tokenize(optarg, '='); + if (extension.size() != 2) + printUsageAndExit(argv[0]); + std::string key = boost::trim_copy(*(extension.begin())); + std::string value = boost::trim_copy(*(++extension.begin())); + extensions.insert(std::pair(key, value)); + } + break; case 'o': outputFile = optarg; break; @@ -288,9 +288,9 @@ int main(int argc, char** argv) { } if (outType == "c") { - Transformer transformer = ChartToC::transform(interpreter); - transformer.setExtensions(extensions); - transformer.setOptions(options); + Transformer transformer = ChartToC::transform(interpreter); + transformer.setExtensions(extensions); + transformer.setOptions(options); if (outputFile.size() == 0 || outputFile == "-") { transformer.writeTo(std::cout); } else { @@ -392,9 +392,9 @@ int main(int argc, char** argv) { } catch (Event e) { std::cout << e << std::endl; - } catch (const std::exception &e) { - std::cout << e.what() << std::endl; - } + } catch (const std::exception &e) { + std::cout << e.what() << std::endl; + } return EXIT_SUCCESS; } \ No newline at end of file diff --git a/src/uscxml/DOMUtils.cpp b/src/uscxml/DOMUtils.cpp index 97b84c8..414b5e7 100644 --- a/src/uscxml/DOMUtils.cpp +++ b/src/uscxml/DOMUtils.cpp @@ -129,50 +129,66 @@ std::string DOMUtils::xPathForNode(const Arabica::DOM::Node& node, return xPath; } -NodeSet DOMUtils::inPostFixOrder(const std::set& elements, const Element& root) { - NodeSet nodes; - inPostFixOrder(elements, root, nodes); - return nodes; +NodeSet DOMUtils::inPostFixOrder(const std::set& elements, + const Element& root, + const bool includeEmbeddedDoc) { + NodeSet nodes; + inPostFixOrder(elements, root, includeEmbeddedDoc, nodes); + return nodes; } -void DOMUtils::inPostFixOrder(const std::set& elements, const Element& root, NodeSet& nodes) { - NodeList children = root.getChildNodes(); - for (size_t i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Arabica::DOM::Element childElem(children.item(i)); - inPostFixOrder(elements, childElem, nodes); - - } - for (size_t i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Arabica::DOM::Element childElem(children.item(i)); - - if (elements.find(TAGNAME(childElem)) != elements.end()) { - nodes.push_back(childElem); - } - } +void DOMUtils::inPostFixOrder(const std::set& elements, + const Element& root, + const bool includeEmbeddedDoc, + NodeSet& nodes) { + NodeList children = root.getChildNodes(); + for (size_t i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element childElem(children.item(i)); + if (!includeEmbeddedDoc && LOCALNAME(childElem) == "scxml") + continue; + inPostFixOrder(elements, childElem, includeEmbeddedDoc, nodes); + + } + for (size_t i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element childElem(children.item(i)); + if (!includeEmbeddedDoc && LOCALNAME(childElem) == "scxml") + continue; + + if (elements.find(TAGNAME(childElem)) != elements.end()) { + nodes.push_back(childElem); + } + } } -NodeSet DOMUtils::inDocumentOrder(const std::set& elements, const Element& root) { - NodeSet nodes; - inDocumentOrder(elements, root, nodes); - return nodes; +NodeSet DOMUtils::inDocumentOrder(const std::set& elements, + const Element& root, + const bool includeEmbeddedDoc) { + NodeSet nodes; + inDocumentOrder(elements, root, includeEmbeddedDoc, nodes); + return nodes; } -void DOMUtils::inDocumentOrder(const std::set& elements, const Element& root, NodeSet& nodes) { - if (elements.find(TAGNAME(root)) != elements.end()) { - nodes.push_back(root); - } - - NodeList children = root.getChildNodes(); - for (size_t i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Arabica::DOM::Element childElem(children.item(i)); - inDocumentOrder(elements, childElem, nodes); - } +void DOMUtils::inDocumentOrder(const std::set& elements, + const Element& root, + const bool includeEmbeddedDoc, + NodeSet& nodes) { + if (elements.find(TAGNAME(root)) != elements.end()) { + nodes.push_back(root); + } + + NodeList children = root.getChildNodes(); + for (size_t i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (!includeEmbeddedDoc && LOCALNAME_CAST(children.item(i)) == "scxml") + continue; + Arabica::DOM::Element childElem(children.item(i)); + inDocumentOrder(elements, childElem, includeEmbeddedDoc, nodes); + } } std::list > DOMUtils::getElementsByType(const Arabica::DOM::Node& root, Arabica::DOM::Node_base::Type type) { diff --git a/src/uscxml/DOMUtils.h b/src/uscxml/DOMUtils.h index a94bd90..67bcd70 100644 --- a/src/uscxml/DOMUtils.h +++ b/src/uscxml/DOMUtils.h @@ -43,24 +43,29 @@ namespace uscxml { class USCXML_API DOMUtils { public: + static std::string xPathForNode(const Arabica::DOM::Node& node, const std::string& ns = ""); static std::list > getElementsByType(const Arabica::DOM::Node& root, Arabica::DOM::Node_base::Type type); static std::string idForNode(const Arabica::DOM::Node& node); // deprecated, use stringIsTrue from Convenience.h instead DEPRECATED static bool attributeIsTrue(const::std::string& value); - - static Arabica::XPath::NodeSet inPostFixOrder(const std::set& elements, - const Arabica::DOM::Element& root); - static Arabica::XPath::NodeSet inDocumentOrder(const std::set& elements, - const Arabica::DOM::Element& root); + + static Arabica::XPath::NodeSet inPostFixOrder(const std::set& elements, + const Arabica::DOM::Element& root, + const bool includeEmbeddedDoc = false); + static Arabica::XPath::NodeSet inDocumentOrder(const std::set& elements, + const Arabica::DOM::Element& root, + const bool includeEmbeddedDoc = false); protected: - static void inPostFixOrder(const std::set& elements, - const Arabica::DOM::Element& root, - Arabica::XPath::NodeSet& nodes); - - static void inDocumentOrder(const std::set& elements, - const Arabica::DOM::Element& root, - Arabica::XPath::NodeSet& nodes); + static void inPostFixOrder(const std::set& elements, + const Arabica::DOM::Element& root, + const bool includeEmbeddedDoc, + Arabica::XPath::NodeSet& nodes); + + static void inDocumentOrder(const std::set& elements, + const Arabica::DOM::Element& root, + const bool includeEmbeddedDoc, + Arabica::XPath::NodeSet& nodes); }; diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index a05fe39..2510ef4 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -779,7 +779,7 @@ NodeSet InterpreterImpl::getDocumentInitialTransitions() { } return initialTransitions; } - + InterpreterState InterpreterImpl::step(int waitForMS) { try { tthread::lock_guard lock(_mutex); @@ -2374,6 +2374,7 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Element& ele // see: http://www.w3.org/TR/scxml/#EventDescriptors bool InterpreterImpl::nameMatch(const std::string& eventDescs, const std::string& eventName) { +#if 1 if(eventDescs.length() == 0 || eventName.length() == 0) return false; @@ -2422,6 +2423,38 @@ NEXT_DESC: } } return false; +#else + const char* dPtr = eventDescs.c_str(); + const char* ePtr = eventName.c_str(); + while(*dPtr != 0) { + + if (*dPtr == '*' && *ePtr != 0) // something following + return true; + + // descriptor differs from event name + if (*dPtr != *ePtr) { + // move to next descriptor + while(*dPtr != ' ' && *dPtr != 0) { + dPtr++; + } + if (*dPtr == 0) + return false; + dPtr++; + ePtr = eventName.c_str(); + } else { + // move both pointers one character + dPtr++; + ePtr++; + + } + + // descriptor is done, return match + if (((*dPtr == 0 || *dPtr == ' ') && (*ePtr == 0 || *ePtr == ' ')) || // exact match, end of string + (*dPtr == ' ' && *ePtr == '.') || (*dPtr == 0 && *ePtr == '.')) // prefix match + return true; + } + return false; +#endif } diff --git a/src/uscxml/interpreter/InterpreterFast.cpp b/src/uscxml/interpreter/InterpreterFast.cpp index 0958c61..94fcdce 100644 --- a/src/uscxml/interpreter/InterpreterFast.cpp +++ b/src/uscxml/interpreter/InterpreterFast.cpp @@ -33,10 +33,10 @@ using namespace Arabica::DOM; void InterpreterFast::handleDOMEvent(Arabica::DOM::Events::Event& event) { - InterpreterImpl::handleDOMEvent(event); - - if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes - return; - + InterpreterImpl::handleDOMEvent(event); + + if (event.getType().compare("DOMAttrModified") == 0) // we do not care about attributes + return; + } } \ No newline at end of file diff --git a/src/uscxml/interpreter/InterpreterFast.h b/src/uscxml/interpreter/InterpreterFast.h index 589e899..5838dc0 100644 --- a/src/uscxml/interpreter/InterpreterFast.h +++ b/src/uscxml/interpreter/InterpreterFast.h @@ -23,25 +23,25 @@ #include "uscxml/Interpreter.h" namespace uscxml { - + class InterpreterFast : public InterpreterImpl { protected: - virtual void setupSets(); - virtual void handleDOMEvent(Arabica::DOM::Events::Event& event); - + virtual void setupSets(); + virtual void handleDOMEvent(Arabica::DOM::Events::Event& event); + private: - /* TODO: use post-order and document-order per STL comparator (sorted std::set?) */ - - std::vector > _states; - std::vector > _transitions; - - std::vector > _conflictingTransitions; - std::vector > _exitSets; - std::vector > _targetSets; + /* TODO: use post-order and document-order per STL comparator (sorted std::set?) */ + + std::vector > _states; + std::vector > _transitions; + + std::vector > _conflictingTransitions; + std::vector > _exitSets; + std::vector > _targetSets; }; - + } #endif /* end of include guard: INTERPRETERFAST_H_224A5F07 */ diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 53508e6..7bd40d9 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -125,6 +125,7 @@ void USCXMLInvoker::ParentQueue::push(const SendRequest& event) { if (_invoker->_cancelled) return; SendRequest copyEvent(event); + // this is somewhat hidden here! copyEvent.invokeid = _invoker->_invokeId; _invoker->_parentInterpreter->receive(copyEvent); } diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp index 710a2de..ea8d5df 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -23,6 +23,7 @@ #include #include #include "uscxml/UUID.h" +#include "uscxml/util/MD5.hpp" #include "uscxml/DOMUtils.h" #include #include @@ -44,10 +45,19 @@ Transformer ChartToC::transform(const Interpreter& other) { return boost::shared_ptr(c2c); } -ChartToC::ChartToC(const Interpreter& other) : TransformerImpl() { +ChartToC::ChartToC(const Interpreter& other) : TransformerImpl(), _topMostMachine(NULL), _parentMachine(NULL) { cloneFrom(other.getImpl()); + std::stringstream ss; + ss << _document; + _md5 = md5(ss.str()); + _prefix = "_scxml_" + _md5.substr(0, 8); + _allMachines.push_back(this); + + prepare(); + findNestedMachines(); + } - + void ChartToC::setHistoryCompletion() { std::set elements; elements.insert(_nsInfo.xmlNSPrefix + "history"); @@ -170,239 +180,243 @@ void ChartToC::resortStates(Arabica::DOM::Node& node) { } void ChartToC::setStateCompletion() { - setHistoryCompletion(); - - for (size_t i = 0; i < _states.size(); i++) { - Element state(_states[i]); - - if (isHistory(state)) { - // we already did in setHistoryCompletion - continue; - } - - NodeSet completion; - - if (isParallel(state)) { - completion = getChildStates(state); - - } else if (state.hasAttribute("initial")) { - completion = getStates(tokenizeIdRefs(state.getAttribute("initial"))); - - } else { - NodeSet initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state); - if(initElems.size() > 0 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) { - // initial element is first child - completion.push_back(initElems[0]); - } else { - // first child state - Arabica::XPath::NodeSet initStates; - NodeList childs = state.getChildNodes(); - for (size_t i = 0; i < childs.getLength(); i++) { - if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - if (isState(Element(childs.item(i)))) { - completion.push_back(childs.item(i)); - break; - } - } - } - } - - std::string completionBools; - for (size_t j = 0; j < _states.size(); j++) { - if (isMember(_states[j], completion)) { - completionBools += "1"; - } else { - completionBools += "0"; - } - } - state.setAttribute("completionBools", completionBools); - } + setHistoryCompletion(); + + for (size_t i = 0; i < _states.size(); i++) { + Element state(_states[i]); + + if (isHistory(state)) { + // we already did in setHistoryCompletion + continue; + } + + NodeSet completion; + + if (isParallel(state)) { + completion = getChildStates(state); + + } else if (state.hasAttribute("initial")) { + completion = getStates(tokenizeIdRefs(state.getAttribute("initial"))); + + } else { + NodeSet initElems = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state); + if(initElems.size() > 0 && !iequals(ATTR_CAST(initElems[0], "generated"), "true")) { + // initial element is first child + completion.push_back(initElems[0]); + } else { + // first child state + Arabica::XPath::NodeSet initStates; + NodeList childs = state.getChildNodes(); + for (size_t i = 0; i < childs.getLength(); i++) { + if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + if (isState(Element(childs.item(i)))) { + completion.push_back(childs.item(i)); + break; + } + } + } + } + + std::string completionBools; + for (size_t j = 0; j < _states.size(); j++) { + if (isMember(_states[j], completion)) { + completionBools += "1"; + } else { + completionBools += "0"; + } + } + state.setAttribute("completionBools", completionBools); + } } - + void ChartToC::prepare() { - _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); - _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : ""); - - // make sure initial and history elements always precede propoer states - resortStates(_scxml); - - std::set elements; - elements.insert(_nsInfo.xmlNSPrefix + "scxml"); - elements.insert(_nsInfo.xmlNSPrefix + "state"); - elements.insert(_nsInfo.xmlNSPrefix + "final"); - elements.insert(_nsInfo.xmlNSPrefix + "parallel"); - elements.insert(_nsInfo.xmlNSPrefix + "history"); - elements.insert(_nsInfo.xmlNSPrefix + "initial"); - elements.insert(_nsInfo.xmlNSPrefix + "parallel"); - _states = DOMUtils::inDocumentOrder(elements, _scxml); - - // set states' document order and parent attribute - for (size_t i = 0; i < _states.size(); i++) { - Element state(_states[i]); - state.setAttribute("documentOrder", toStr(i)); - if (state.getParentNode().getNodeType() == Node_base::ELEMENT_NODE && - HAS_ATTR_CAST(state.getParentNode(), "documentOrder")) { - state.setAttribute("parent", ATTR_CAST(state.getParentNode(), "documentOrder")); - } - - // set the states' children and whether it has a history - std::string childBools; - bool hasHistoryChild = false; - for (size_t j = 0; j < _states.size(); j++) { - if (_states[j].getParentNode() == state) { - if (isHistory(Element(_states[j]))) { - hasHistoryChild = true; - } - childBools += "1"; - } else { - childBools += "0"; - } - } - state.setAttribute("childBools", childBools); - if (hasHistoryChild) { - state.setAttribute("hasHistoryChild", "yes"); - } - - // ancestors - std::string ancBools; - for (size_t j = 0; j < _states.size(); j++) { - if (isDescendant(state, _states[j])) { - ancBools += "1"; - } else { - ancBools += "0"; - } - } - state.setAttribute("ancBools", ancBools); - - } - - // set transitions' document order and source attribute - elements.clear(); - elements.insert(_nsInfo.xmlNSPrefix + "transition"); - _transitions = DOMUtils::inDocumentOrder(elements, _scxml); - for (size_t i = 0; i < _transitions.size(); i++) { - Element transition(_transitions[i]); - transition.setAttribute("documentOrder", toStr(i)); - if (transition.getParentNode().getNodeType() == Node_base::ELEMENT_NODE && - HAS_ATTR_CAST(transition.getParentNode(), "documentOrder")) { - transition.setAttribute("source", ATTR_CAST(transition.getParentNode(), "documentOrder")); - } - } - - // set transitions' postfix order attribute - _transitions = DOMUtils::inPostFixOrder(elements, _scxml); - for (size_t i = 0; i < _transitions.size(); i++) { - Element transition(_transitions[i]); - transition.setAttribute("postFixOrder", toStr(i)); - - // and exit set - std::string exitSetBools; - NodeSet exitSet = computeExitSet(transition); - for (unsigned int j = 0; j < _states.size(); j++) { - Element state(_states[j]); - if (isMember(state, exitSet)) { - exitSetBools += "1"; - } else { - exitSetBools += "0"; - } - } - transition.setAttribute("exitSetBools", exitSetBools); - - // and conflicts - std::string conflictBools; - for (unsigned int j = 0; j < _transitions.size(); j++) { - Element t2(_transitions[j]); - if (hasIntersection(computeExitSet(transition), computeExitSet(t2)) || - (getSourceState(transition) == getSourceState(t2)) || - (isDescendant(getSourceState(transition), getSourceState(t2))) || - (isDescendant(getSourceState(t2), getSourceState(transition)))) { - conflictBools += "1"; - } else { - conflictBools += "0"; - } - } - transition.setAttribute("conflictBools", conflictBools); - - // and target - if (HAS_ATTR(transition, "target")) { - std::list targets = tokenize(ATTR(transition, "target")); - - std::string targetBools; - for (size_t j = 0; j < _states.size(); j++) { - Element state(_states[j]); - - if (HAS_ATTR(state, "id") && - std::find(targets.begin(), targets.end(), escape(ATTR(state, "id"))) != targets.end()) { - targetBools += "1"; - } else { - targetBools += "0"; - } - } - transition.setAttribute("targetBools", targetBools); - - } - } - // leave transitions in postfix order - - - - // set the completion of states and responsibility of history elements - setStateCompletion(); - - // how many bits do we need to represent the state array? - std::string seperator; - _stateCharArraySize = ceil((float)_states.size() / (float)8); - _stateCharArrayInit = "{"; - for (size_t i = 0; i < _stateCharArraySize; i++) { - _stateCharArrayInit += seperator + "0"; - seperator = ", "; - } - _stateCharArrayInit += "}"; - - if (false) { - } else if (_states.size() < (1UL << 8)) { - _stateDataType = "uint8_t"; - } else if (_states.size() < (1UL << 16)) { - _stateDataType = "uint16_t"; - } else if (_states.size() < (1UL << 32)) { - _stateDataType = "uint32_t"; - } else { - _stateDataType = "uint64_t"; - } - - seperator = ""; - _transCharArraySize = ceil((float)_transitions.size() / (float)8); - _transCharArrayInit = "{"; - for (size_t i = 0; i < _transCharArraySize; i++) { - _transCharArrayInit += seperator + "0"; - seperator = ", "; - } - _transCharArrayInit += "}"; - - if (false) { - } else if (_transitions.size() < (1UL << 8)) { - _transDataType = "uint8_t"; - } else if (_transitions.size() < (1UL << 16)) { - _transDataType = "uint16_t"; - } else if (_transitions.size() < (1UL << 32)) { - _transDataType = "uint32_t"; - } else { - _transDataType = "uint64_t"; - } - + _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); + _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : ""); + + // make sure initial and history elements always precede propoer states + resortStates(_scxml); + + std::set elements; + elements.insert(_nsInfo.xmlNSPrefix + "scxml"); + elements.insert(_nsInfo.xmlNSPrefix + "state"); + elements.insert(_nsInfo.xmlNSPrefix + "final"); + elements.insert(_nsInfo.xmlNSPrefix + "parallel"); + elements.insert(_nsInfo.xmlNSPrefix + "history"); + elements.insert(_nsInfo.xmlNSPrefix + "initial"); + elements.insert(_nsInfo.xmlNSPrefix + "parallel"); + _states = DOMUtils::inDocumentOrder(elements, _scxml); + + // set states' document order and parent attribute + for (size_t i = 0; i < _states.size(); i++) { + Element state(_states[i]); + state.setAttribute("documentOrder", toStr(i)); + if (state.getParentNode().getNodeType() == Node_base::ELEMENT_NODE && + HAS_ATTR_CAST(state.getParentNode(), "documentOrder")) { + state.setAttribute("parent", ATTR_CAST(state.getParentNode(), "documentOrder")); + } + + // set the states' children and whether it has a history + std::string childBools; + bool hasHistoryChild = false; + for (size_t j = 0; j < _states.size(); j++) { + if (_states[j].getParentNode() == state) { + if (isHistory(Element(_states[j]))) { + hasHistoryChild = true; + } + childBools += "1"; + } else { + childBools += "0"; + } + } + state.setAttribute("childBools", childBools); + if (hasHistoryChild) { + state.setAttribute("hasHistoryChild", "yes"); + } + + // ancestors + std::string ancBools; + for (size_t j = 0; j < _states.size(); j++) { + if (isDescendant(state, _states[j])) { + ancBools += "1"; + } else { + ancBools += "0"; + } + } + state.setAttribute("ancBools", ancBools); + + } + + // set transitions' document order and source attribute + elements.clear(); + elements.insert(_nsInfo.xmlNSPrefix + "transition"); + _transitions = DOMUtils::inDocumentOrder(elements, _scxml); + for (size_t i = 0; i < _transitions.size(); i++) { + Element transition(_transitions[i]); + transition.setAttribute("documentOrder", toStr(i)); + if (transition.getParentNode().getNodeType() == Node_base::ELEMENT_NODE && + HAS_ATTR_CAST(transition.getParentNode(), "documentOrder")) { + transition.setAttribute("source", ATTR_CAST(transition.getParentNode(), "documentOrder")); + } + } + + // set transitions' postfix order attribute + _transitions = DOMUtils::inPostFixOrder(elements, _scxml); + for (size_t i = 0; i < _transitions.size(); i++) { + Element transition(_transitions[i]); + transition.setAttribute("postFixOrder", toStr(i)); + + // and exit set + std::string exitSetBools; + NodeSet exitSet = computeExitSet(transition); + for (unsigned int j = 0; j < _states.size(); j++) { + Element state(_states[j]); + if (isMember(state, exitSet)) { + exitSetBools += "1"; + } else { + exitSetBools += "0"; + } + } + transition.setAttribute("exitSetBools", exitSetBools); + + // and conflicts + std::string conflictBools; + for (unsigned int j = 0; j < _transitions.size(); j++) { + Element t2(_transitions[j]); + if (hasIntersection(computeExitSet(transition), computeExitSet(t2)) || + (getSourceState(transition) == getSourceState(t2)) || + (isDescendant(getSourceState(transition), getSourceState(t2))) || + (isDescendant(getSourceState(t2), getSourceState(transition)))) { + conflictBools += "1"; + } else { + conflictBools += "0"; + } + } + transition.setAttribute("conflictBools", conflictBools); + + // and target + if (HAS_ATTR(transition, "target")) { + std::list targets = tokenize(ATTR(transition, "target")); + + std::string targetBools; + for (size_t j = 0; j < _states.size(); j++) { + Element state(_states[j]); + + if (HAS_ATTR(state, "id") && + std::find(targets.begin(), targets.end(), escape(ATTR(state, "id"))) != targets.end()) { + targetBools += "1"; + } else { + targetBools += "0"; + } + } + transition.setAttribute("targetBools", targetBools); + + } + } + // leave transitions in postfix order + + + + // set the completion of states and responsibility of history elements + setStateCompletion(); + + // how many bits do we need to represent the state array? + std::string seperator; + _stateCharArraySize = ceil((float)_states.size() / (float)8); + _stateCharArrayInit = "{"; + for (size_t i = 0; i < _stateCharArraySize; i++) { + _stateCharArrayInit += seperator + "0"; + seperator = ", "; + } + _stateCharArrayInit += "}"; + + if (false) { + } else if (_states.size() < (1UL << 8)) { + _stateDataType = "uint8_t"; + } else if (_states.size() < (1UL << 16)) { + _stateDataType = "uint16_t"; + } else if (_states.size() < (1UL << 32)) { + _stateDataType = "uint32_t"; + } else { + _stateDataType = "uint64_t"; + } + + seperator = ""; + _transCharArraySize = ceil((float)_transitions.size() / (float)8); + _transCharArrayInit = "{"; + for (size_t i = 0; i < _transCharArraySize; i++) { + _transCharArrayInit += seperator + "0"; + seperator = ", "; + } + _transCharArrayInit += "}"; + + if (false) { + } else if (_transitions.size() < (1UL << 8)) { + _transDataType = "uint8_t"; + } else if (_transitions.size() < (1UL << 16)) { + _transDataType = "uint16_t"; + } else if (_transitions.size() < (1UL << 32)) { + _transDataType = "uint32_t"; + } else { + _transDataType = "uint64_t"; + } + } void ChartToC::writeTo(std::ostream& stream) { - prepare(); writeIncludes(stream); writeMacros(stream); writeTypes(stream); - writeElementInfo(stream); - writeExecContent(stream); - writeStates(stream); - writeTransitions(stream); + for (std::list::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++) { + (*machIter)->writeElementInfo(stream); + (*machIter)->writeExecContentFinalize(stream); + (*machIter)->writeElementInfoInvocation(stream); + (*machIter)->writeExecContent(stream); + (*machIter)->writeStates(stream); + (*machIter)->writeTransitions(stream); + } + writeMachineInfo(stream); writeHelpers(stream); writeFSM(stream); @@ -410,6 +424,50 @@ void ChartToC::writeTo(std::ostream& stream) { } +void ChartToC::findNestedMachines() { + NodeSet invokes = InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); + + for (size_t i = 0; i < invokes.size(); i++) { + if(isInEmbeddedDocument(invokes[i])) + continue; + + Element invoke(invokes[i]); + if (HAS_ATTR(invoke, "type") && + ATTR(invoke, "type") != "scxml" && + ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/") + continue; + + ChartToC* c2c = NULL; + if (HAS_ATTR(invoke, "src")) { + c2c = new ChartToC(Interpreter::fromURL(ATTR(invoke, "src"))); + } else { + // is there a nested scxml machine inside? + NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", invoke); + if (contents.size() == 0) + continue; + NodeSet scxmls = filterChildElements(_nsInfo.xmlNSPrefix + "scxml", contents[0]); + if (scxmls.size() == 0) + continue; + + DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); + Arabica::DOM::Document doc = domFactory.createDocument(_document.getNamespaceURI(), "", 0); + Node imported = doc.importNode(scxmls[0], true); + doc.appendChild(imported); +// std::cout << doc << std::endl; + c2c = new ChartToC(Interpreter::fromDOM(doc, _nsInfo, _sourceURL)); + } + + if (c2c != NULL) { + invoke.setAttribute("md5sum", c2c->_md5); + ChartToC* topMostMachine = (_topMostMachine == NULL ? this : _topMostMachine); + c2c->_topMostMachine = topMostMachine; + c2c->_parentMachine = this; + _nestedMachines.push_back(c2c); + topMostMachine->_allMachines.push_back(c2c); + } + } +} + void ChartToC::writeIncludes(std::ostream& stream) { stream << "#include // explicit types" << std::endl; stream << "#include // NULL" << std::endl; @@ -431,6 +489,26 @@ void ChartToC::writeMacros(std::ostream& stream) { stream << "#endif" << std::endl; stream << std::endl; + stream << "#ifndef SCXML_NR_STATES_TYPE " << std::endl; + stream << "# define SCXML_NR_STATES_TYPE " << _stateDataType << std::endl; + stream << "#endif " << std::endl; + stream << std::endl; + + stream << "#ifndef SCXML_NR_TRANS_TYPE " << std::endl; + stream << "# define SCXML_NR_TRANS_TYPE " << _stateDataType << std::endl; + stream << "#endif " << std::endl; + stream << std::endl; + + stream << "#ifndef SCXML_MAX_NR_STATES_BYTES " << std::endl; + stream << "# define SCXML_MAX_NR_STATES_BYTES " << _stateCharArraySize << std::endl; + stream << "#endif " << std::endl; + stream << std::endl; + + stream << "#ifndef SCXML_MAX_NR_TRANS_BYTES " << std::endl; + stream << "# define SCXML_MAX_NR_TRANS_BYTES " << _transCharArraySize << std::endl; + stream << "#endif " << std::endl; + stream << std::endl; + stream << "// error return codes" << std::endl; stream << "#define SCXML_ERR_OK 0" << std::endl; stream << "#define SCXML_ERR_IDLE 1" << std::endl; @@ -443,9 +521,12 @@ void ChartToC::writeMacros(std::ostream& stream) { stream << "#define SCXML_ERR_UNSUPPORTED 8" << std::endl; stream << std::endl; - stream << "#define SCXML_MACHINE_NAME \"" << _name << "\"" << std::endl; - stream << "#define SCXML_NUMBER_STATES " << _states.size() << std::endl; - stream << "#define SCXML_NUMBER_TRANSITIONS " << _transitions.size() << std::endl; +// stream << "#define SCXML_NUMBER_STATES " << _states.size() << std::endl; +// stream << "#define SCXML_NUMBER_TRANS " << _transitions.size() << std::endl; + + stream << "#define SCXML_NUMBER_STATES (ctx->machine->nr_states)" << std::endl; + stream << "#define SCXML_NUMBER_TRANS (ctx->machine->nr_transitions)" << std::endl; + stream << std::endl; stream << "#define SCXML_TRANS_SPONTANEOUS 0x01" << std::endl; @@ -473,20 +554,23 @@ void ChartToC::writeMacros(std::ostream& stream) { stream << "#define SCXML_CTX_TRANSITION_FOUND 0x08" << std::endl; stream << std::endl; + + stream << "#define ELEM_DATA_IS_SET(data) (data->id != NULL)" << std::endl; stream << "#define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL)" << std::endl; stream << "#define ELEM_PARAM_IS_SET(param) (param->name != NULL)" << std::endl; + stream << "#define SCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0)" << std::endl; stream << std::endl; } void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; - stream << "typedef struct scxml_machine scxml_machine;" << std::endl; - stream << "typedef struct scxml_transition scxml_transition;" << std::endl; + stream << "typedef struct scxml_machine scxml_machine;" << std::endl; + stream << "typedef struct scxml_transition scxml_transition;" << std::endl; stream << "typedef struct scxml_state scxml_state;" << std::endl; stream << "typedef struct scxml_ctx scxml_ctx;" << std::endl; - stream << "typedef struct scxml_invoke scxml_invoke;" << std::endl; + stream << "typedef struct scxml_elem_invoke scxml_elem_invoke;" << std::endl; stream << std::endl; stream << "typedef struct scxml_elem_send scxml_elem_send;" << std::endl; @@ -502,7 +586,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << "typedef int (*is_true_t)(const scxml_ctx* ctx, const char* expr);" << std::endl; stream << "typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event);" << std::endl; stream << "typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata);" << std::endl; - stream << "typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x);" << std::endl; + stream << "typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke);" << std::endl; stream << std::endl; stream << "typedef int (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr);" << std::endl; @@ -514,30 +598,31 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << "typedef int (*exec_content_assign_t)(const scxml_ctx* ctx, const char* location, const char* expr);" << std::endl; stream << "typedef int (*exec_content_init_t)(const scxml_ctx* ctx, const scxml_elem_data* data);" << std::endl; stream << "typedef int (*exec_content_cancel_t)(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr);" << std::endl; - stream << "typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_invoke* invoker, const void* event);" << std::endl; + stream << "typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_elem_invoke* invoker, const void* event);" << std::endl; stream << "typedef int (*exec_content_script_t)(const scxml_ctx* ctx, const char* src, const char* content);" << std::endl; stream << std::endl; -#if 0 - stream << "struct scxml_machine {" << std::endl; - stream << " uint8_t flags;" << std::endl; - stream << " uint32_t nr_states;" << std::endl; - stream << " uint32_t nr_transitions;" << std::endl; - stream << " const char* name;" << std::endl; - stream << " const char* datamodel;" << std::endl; - stream << " const char* uuid;" << std::endl; - stream << " const scxml_elem_data* datas;" << std::endl; - stream << " const scxml_state* states;" << std::endl; - stream << " const scxml_transition* transitions;" << std::endl; - stream << " const scxml_foreach* foreachs;" << std::endl; - stream << " const scxml_elem_param* params;" << std::endl; - stream << " const scxml_elem_donedata* donedatas;" << std::endl; - stream << " const scxml_elem_invoke* invokes;" << std::endl; - stream << " const scxml_elem_send* sends;" << std::endl; - stream << "};" << std::endl; - stream << std::endl; +#if 1 + stream << "struct scxml_machine {" << std::endl; + stream << " uint8_t flags;" << std::endl; + stream << " SCXML_NR_STATES_TYPE nr_states;" << std::endl; + stream << " SCXML_NR_TRANS_TYPE nr_transitions;" << std::endl; + stream << " const char* name;" << std::endl; + stream << " const char* datamodel;" << std::endl; + stream << " const char* uuid;" << std::endl; + stream << " const scxml_state* states;" << std::endl; + stream << " const scxml_transition* transitions;" << std::endl; + stream << " const scxml_machine* parent;" << std::endl; + stream << " const scxml_elem_donedata* donedata;" << std::endl; + stream << " const exec_content_t script;" << std::endl; + stream << "};" << std::endl; + stream << std::endl; + + stream << "// forward declare machines to allow references" << std::endl; + stream << "extern const scxml_machine scxml_machines[" << toStr(_allMachines.size() + 1) << "];" << std::endl; + stream << std::endl; #endif - + stream << "struct scxml_elem_data {" << std::endl; stream << " const char* id;" << std::endl; stream << " const char* src;" << std::endl; @@ -552,9 +637,9 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << " const exec_content_t on_entry; // on entry handlers" << std::endl; stream << " const exec_content_t on_exit; // on exit handlers" << std::endl; stream << " const invoke_t invoke; // invocations" << std::endl; - stream << " const char children[" << _stateCharArraySize << "]; // all children" << std::endl; - stream << " const char completion[" << _stateCharArraySize << "]; // default completion" << std::endl; - stream << " const char ancestors[" << _stateCharArraySize << "]; // all ancestors" << std::endl; + stream << " const char children[SCXML_MAX_NR_STATES_BYTES]; // all children" << std::endl; + stream << " const char completion[SCXML_MAX_NR_STATES_BYTES]; // default completion" << std::endl; + stream << " const char ancestors[SCXML_MAX_NR_STATES_BYTES]; // all ancestors" << std::endl; stream << " const scxml_elem_data* data;" << std::endl; stream << " const uint8_t type; // atomic, parallel, compound, final, history" << std::endl; stream << "};" << std::endl; @@ -562,13 +647,13 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << "struct scxml_transition {" << std::endl; stream << " const " << _stateDataType << " source;" << std::endl; - stream << " const char target[" << _stateCharArraySize << "];" << std::endl; + stream << " const char target[SCXML_MAX_NR_STATES_BYTES];" << std::endl; stream << " const char* event;" << std::endl; stream << " const char* condition;" << std::endl; stream << " const exec_content_t on_transition;" << std::endl; stream << " const uint8_t type;" << std::endl; - stream << " const char conflicts[" << _transCharArraySize << "];" << std::endl; - stream << " const char exit_set[" << _stateCharArraySize << "];" << std::endl; + stream << " const char conflicts[SCXML_MAX_NR_TRANS_BYTES];" << std::endl; + stream << " const char exit_set[SCXML_MAX_NR_STATES_BYTES];" << std::endl; stream << "};" << std::endl; stream << std::endl; @@ -595,8 +680,8 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "struct scxml_elem_invoke {" << std::endl; - stream << " const char* uuid;" << std::endl; - stream << " const char* type;" << std::endl; + stream << " const scxml_machine* machine;" << std::endl; + stream << " const char* type;" << std::endl; stream << " const char* typeexpr;" << std::endl; stream << " const char* src;" << std::endl; stream << " const char* srcexpr;" << std::endl; @@ -605,7 +690,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << " const char* namelist;" << std::endl; stream << " const uint8_t autoforward;" << std::endl; stream << " const scxml_elem_param* params;" << std::endl; - stream << " const exec_content_finalize_t* finalize;" << std::endl; + stream << " exec_content_finalize_t finalize;" << std::endl; stream << " const char* content;" << std::endl; stream << " const char* contentexpr;" << std::endl; stream << "};" << std::endl; @@ -630,12 +715,13 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "struct scxml_ctx {" << std::endl; - stream << " uint8_t flags;" << std::endl; + stream << " uint8_t flags;" << std::endl; + stream << " const scxml_machine* machine;" << std::endl; stream << std::endl; - stream << " char config[" << _stateCharArraySize << "];" << std::endl; - stream << " char history[" << _stateCharArraySize << "];" << std::endl; - stream << " char pending_invokes[" << _stateCharArraySize << "];" << std::endl; - stream << " char initialized_data[" << _stateCharArraySize << "];" << std::endl; + stream << " char config[SCXML_MAX_NR_STATES_BYTES];" << std::endl; + stream << " char history[SCXML_MAX_NR_STATES_BYTES];" << std::endl; + stream << " char invocations[SCXML_MAX_NR_STATES_BYTES];" << std::endl; + stream << " char initialized_data[SCXML_MAX_NR_STATES_BYTES];" << std::endl; stream << std::endl; stream << " void* user_data;" << std::endl; stream << " void* event;" << std::endl; @@ -663,12 +749,12 @@ void ChartToC::writeTypes(std::ostream& stream) { void ChartToC::writeHelpers(std::ostream& stream) { stream << "#ifdef SCXML_VERBOSE" << std::endl; - stream << "static void printStateNames(const char* a) {" << std::endl; - stream << " size_t i;" << std::endl; - stream << " const char* seperator = \"\";" << std::endl; - stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl; + stream << "static void printStateNames(const scxml_ctx* ctx, const char* a, size_t length) {" << std::endl; + stream << " size_t i;" << std::endl; + stream << " const char* seperator = \"\";" << std::endl; + stream << " for (i = 0; i < length; i++) {" << std::endl; stream << " if (BIT_HAS(i, a)) {" << std::endl; - stream << " printf(\"%s%s\", seperator, (scxml_states[i].name != NULL ? scxml_states[i].name : \"UNK\"));" << std::endl; + stream << " printf(\"%s%s\", seperator, (ctx->machine->states[i].name != NULL ? ctx->machine->states[i].name : \"UNK\"));" << std::endl; stream << " seperator = \", \";" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -677,7 +763,7 @@ void ChartToC::writeHelpers(std::ostream& stream) { stream << std::endl; stream << "static void printBitsetIndices(const char* a, size_t length) {" << std::endl; - stream << " size_t i;" << std::endl; + stream << " size_t i;" << std::endl; stream << " const char* seperator = \"\";" << std::endl; stream << " for (i = 0; i < length; i++) {" << std::endl; stream << " if (BIT_HAS(i, a)) {" << std::endl; @@ -692,53 +778,81 @@ void ChartToC::writeHelpers(std::ostream& stream) { stream << std::endl; stream << "static int bit_has_and(const char* a, const char* b, size_t i) {" << std::endl; - stream << " do {" << std::endl; - stream << " if (a[i - 1] & b[i - 1])" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " if (a[i] & b[i])" << std::endl; stream << " return 1;" << std::endl; - stream << " } while(--i);" << std::endl; + stream << " }" << std::endl; stream << " return 0;" << std::endl; stream << "}" << std::endl; stream << std::endl; + stream << "static void bit_clear_all(char* a, size_t i) {" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " a[i] = 0;" << std::endl; + stream << " }" << std::endl; + stream << "}" << std::endl; + stream << std::endl; + stream << "static int bit_has_any(const char* a, size_t i) {" << std::endl; - stream << " do {" << std::endl; - stream << " if (a[i - 1] > 0)" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " if (a[i] > 0)" << std::endl; stream << " return 1;" << std::endl; - stream << " } while(--i);" << std::endl; + stream << " }" << std::endl; stream << " return 0;" << std::endl; stream << "}" << std::endl; stream << std::endl; stream << "static void bit_or(char* dest, const char* mask, size_t i) {" << std::endl; - stream << " do {" << std::endl; - stream << " dest[i - 1] |= mask[i - 1];" << std::endl; - stream << " } while(--i);" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " dest[i] |= mask[i];" << std::endl; + stream << " }" << std::endl; stream << "}" << std::endl; stream << std::endl; stream << "static void bit_copy(char* dest, const char* source, size_t i) {" << std::endl; - stream << " do {" << std::endl; - stream << " dest[i - 1] = source[i - 1];" << std::endl; - stream << " } while(--i);" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " dest[i] = source[i];" << std::endl; + stream << " }" << std::endl; stream << "}" << std::endl; stream << std::endl; stream << "static void bit_and_not(char* dest, const char* mask, size_t i) {" << std::endl; - stream << " do {" << std::endl; - stream << " dest[i - 1] &= ~mask[i - 1];" << std::endl; - stream << " } while(--i);" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " dest[i] &= ~mask[i];" << std::endl; + stream << " }" << std::endl; stream << "}" << std::endl; stream << std::endl; stream << "static void bit_and(char* dest, const char* mask, size_t i) {" << std::endl; - stream << " do {" << std::endl; - stream << " dest[i - 1] &= mask[i - 1];" << std::endl; - stream << " } while(--i);" << std::endl; + stream << " while(i--) {" << std::endl; + stream << " dest[i] &= mask[i];" << std::endl; + stream << " };" << std::endl; stream << "}" << std::endl; stream << std::endl; } +void ChartToC::writeExecContentFinalize(std::ostream& stream) { + // needs to be written prior to invocation elem info + NodeSet finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", _scxml, true); + for (size_t i = 0; i < finalizes.size(); i++) { + Element finalize(finalizes[i]); + NodeSet execContent = filterChildType(Node_base::ELEMENT_NODE, finalize); + + if (execContent.size() > 0) { + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(finalize) << "(const scxml_ctx* ctx, const scxml_elem_invoke* invocation, const void* event) {" << std::endl; + stream << " int err = SCXML_ERR_OK;" << std::endl; + for (size_t j = 0; j < execContent.size(); j++) { + writeExecContent(stream, Element(execContent[j]), 1); + } + stream << " return SCXML_ERR_OK;" << std::endl; + stream << "}" << std::endl; + stream << std::endl; + } + } + +} + void ChartToC::writeExecContent(std::ostream& stream) { for (size_t i = 0; i < _states.size(); i++) { Element state(_states[i]); @@ -746,26 +860,28 @@ void ChartToC::writeExecContent(std::ostream& stream) { if (i == 0) { // root state - we need to perform some initialization here NodeSet globalScripts = filterChildElements(_nsInfo.xmlNSPrefix + "script", state); - for (size_t j = 0; j < globalScripts.size(); j++) { - stream << "static int global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; - stream << " int err = SCXML_ERR_OK;" << std::endl; - writeExecContent(stream, globalScripts[j], 1); + if (globalScripts.size() > 0) { + for (size_t j = 0; j < globalScripts.size(); j++) { + stream << "static int " << _prefix << "_global_script_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + stream << " int err = SCXML_ERR_OK;" << std::endl; + writeExecContent(stream, globalScripts[j], 1); + stream << " return SCXML_ERR_OK;" << std::endl; + stream << "}" << std::endl; + } + + stream << "static int " << _prefix << "_global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + for (size_t j = 0; j < globalScripts.size(); j++) { + stream << " " << _prefix << "_global_script_" << toStr(j) << "(ctx, state, event);" << std::endl; + } stream << " return SCXML_ERR_OK;" << std::endl; stream << "}" << std::endl; + stream << std::endl; } - - stream << "static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; - for (size_t j = 0; j < globalScripts.size(); j++) { - stream << " global_script_" << toStr(j) << "(ctx, state, event);" << std::endl; - } - stream << " return SCXML_ERR_OK;" << std::endl; - stream << "}" << std::endl; - stream << std::endl; } NodeSet onexit = filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state); for (size_t j = 0; j < onexit.size(); j++) { - stream << "static int " << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; stream << " int err = SCXML_ERR_OK;" << std::endl; writeExecContent(stream, onexit[j], 1); stream << " return SCXML_ERR_OK;" << std::endl; @@ -774,9 +890,9 @@ void ChartToC::writeExecContent(std::ostream& stream) { } if (onexit.size() > 0) { - stream << "static int " << DOMUtils::idForNode(state) << "_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_exit(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; for (size_t j = 0; j < onexit.size(); j++) { - stream << " " << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(ctx, state, event);" << std::endl; + stream << " " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_exit_" << toStr(j) << "(ctx, state, event);" << std::endl; } stream << " return SCXML_ERR_OK;" << std::endl; stream << "}" << std::endl; @@ -786,7 +902,7 @@ void ChartToC::writeExecContent(std::ostream& stream) { NodeSet onentry = filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state); for (size_t j = 0; j < onentry.size(); j++) { - stream << "static int " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; stream << " int err = SCXML_ERR_OK;" << std::endl; writeExecContent(stream, onentry[j], 1); stream << " return SCXML_ERR_OK;" << std::endl; @@ -794,31 +910,10 @@ void ChartToC::writeExecContent(std::ostream& stream) { stream << std::endl; } - /* - gen/c/ecma/test412.scxml (Failed) - gen/c/ecma/test579.scxml (Failed) - */ -#if 0 - bool hasInitialState = false; - NodeSet initial = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state); - if (initial.size() > 0) { - NodeSet initialTransition = filterChildElements(_nsInfo.xmlNSPrefix + "transition", initial); - if (initialTransition.size() > 0) { - hasInitialState = true; - stream << "static int " << DOMUtils::idForNode(state) << "_initial" << "(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; - stream << " int err = SCXML_ERR_OK;" << std::endl; - writeExecContent(stream, initialTransition[0], 1); - stream << " return SCXML_ERR_OK;" << std::endl; - stream << "}" << std::endl; - stream << std::endl; - } - } -#endif - if (onentry.size() > 0) { - stream << "static int " << DOMUtils::idForNode(state) << "_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; for (size_t j = 0; j < onentry.size(); j++) { - stream << " " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(ctx, state, event);" << std::endl; + stream << " " << _prefix << "_" << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(ctx, state, event);" << std::endl; } stream << " return SCXML_ERR_OK;" << std::endl; @@ -827,25 +922,25 @@ void ChartToC::writeExecContent(std::ostream& stream) { } - NodeSet invoke = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state); - if (invoke.size() > 0) { - stream << "static int " << DOMUtils::idForNode(state) << "_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x) {" << std::endl; - for (size_t j = 0; j < invoke.size(); j++) { - stream << " ctx->invoke(ctx, s, x);" << std::endl; - stream << " return SCXML_ERR_OK;" << std::endl; + NodeSet invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state); + if (invokes.size() > 0) { + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(state) << "_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) {" << std::endl; + for (size_t j = 0; j < invokes.size(); j++) { + Element invoke(invokes[j]); + stream << " ctx->invoke(ctx, s, &" << _prefix << "_elem_invokes[" << ATTR(invoke, "documentOrder") << "], uninvoke);" << std::endl; stream << std::endl; } + stream << " return SCXML_ERR_OK;" << std::endl; stream << "}" << std::endl; } } for (size_t i = 0; i < _transitions.size(); i++) { Element transition(_transitions[i]); - NodeSet execContent = filterChildType(Node_base::ELEMENT_NODE, transition); if (execContent.size() > 0) { - stream << "static int " << DOMUtils::idForNode(transition) << "_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; + stream << "static int " << _prefix << "_" << DOMUtils::idForNode(transition) << "_on_trans(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; stream << " int err = SCXML_ERR_OK;" << std::endl; for (size_t j = 0; j < execContent.size(); j++) { writeExecContent(stream, Element(execContent[j]), 1); @@ -855,6 +950,7 @@ void ChartToC::writeExecContent(std::ostream& stream) { stream << std::endl; } } + } void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node& node, int indent) { @@ -927,15 +1023,15 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Nodeexec_content_foreach_done != NULL) {" << std::endl; stream << std::endl; - stream << padding << " if unlikely((ctx->exec_content_foreach_init(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl; - stream << padding << " while (ctx->exec_content_foreach_next(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "]) == SCXML_ERR_OK) {" << std::endl; + stream << padding << " if unlikely((ctx->exec_content_foreach_init(ctx, &" << _prefix << "_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl; + stream << padding << " while (ctx->exec_content_foreach_next(ctx, &" << _prefix << "_elem_foreachs[" << ATTR(elem, "documentOrder") << "]) == SCXML_ERR_OK) {" << std::endl; Arabica::DOM::Node child = node.getFirstChild(); while(child) { writeExecContent(stream, child, indent + 2); child = child.getNextSibling(); } stream << padding << " }" << std::endl; - stream << padding << " if ((ctx->exec_content_foreach_done(ctx, &scxml_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl; + stream << padding << " if ((ctx->exec_content_foreach_done(ctx, &" << _prefix << "_elem_foreachs[" << ATTR(elem, "documentOrder") << "])) != SCXML_ERR_OK) return err;" << std::endl; stream << padding << "} else {" << std::endl; stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl; stream << padding << "}" << std::endl; @@ -1002,7 +1098,7 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Nodeexec_content_send != NULL) {" << std::endl; stream << padding; - stream << " if ((ctx->exec_content_send(ctx, &scxml_elem_sends[" << ATTR(elem, "documentOrder") << "]"; + stream << " if ((ctx->exec_content_send(ctx, &" << _prefix << "_elem_sends[" << ATTR(elem, "documentOrder") << "]"; stream << ")) != SCXML_ERR_OK) return err;" << std::endl; stream << padding << "} else {" << std::endl; stream << padding << " return SCXML_ERR_MISSING_CALLBACK;" << std::endl; @@ -1027,10 +1123,128 @@ void ChartToC::writeExecContent(std::ostream& stream, const Arabica::DOM::Node invokes = filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); + if (invokes.size() > 0) { + _hasElement.insert("invoke"); + stream << "static const scxml_elem_invoke " << _prefix << "_elem_invokes[" << invokes.size() << "] = {" << std::endl; + for (size_t i = 0; i < invokes.size(); i++) { + Element invoke(invokes[i]); + + /* + stream << "struct scxml_elem_invoke {" << std::endl; + stream << " const char* machine;" << std::endl; + stream << " const char* type;" << std::endl; + stream << " const char* typeexpr;" << std::endl; + stream << " const char* src;" << std::endl; + stream << " const char* srcexpr;" << std::endl; + stream << " const char* id;" << std::endl; + stream << " const char* idlocation;" << std::endl; + stream << " const char* namelist;" << std::endl; + stream << " const uint8_t autoforward;" << std::endl; + stream << " const scxml_elem_param* params;" << std::endl; + stream << " const exec_content_finalize_t* finalize;" << std::endl; + stream << " const char* content;" << std::endl; + stream << " const char* contentexpr;" << std::endl; + stream << "};" << std::endl; + */ + + stream << " { " << std::endl; + + stream << " /* machine */ "; + if (HAS_ATTR(invoke, "md5sum")) { + size_t machIdx = 0; + for (std::list::iterator machIter = _allMachines.begin(); machIter != _allMachines.end(); machIter++, machIdx++) { + if ((*machIter)->_md5 == ATTR(invoke, "md5sum")) { + stream << "&scxml_machines[" << toStr(machIdx) << "]"; + break; + } + } + } else { + stream << "NULL"; + } + stream << ", " << std::endl; + + stream << " /* type */ "; + stream << (HAS_ATTR(invoke, "type") ? "\"" + escape(ATTR(invoke, "type")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* typeexpr */ "; + stream << (HAS_ATTR(invoke, "typeexpr") ? "\"" + escape(ATTR(invoke, "typeexpr")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* src */ "; + stream << (HAS_ATTR(invoke, "src") ? "\"" + escape(ATTR(invoke, "src")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* srcexpr */ "; + stream << (HAS_ATTR(invoke, "srcexpr") ? "\"" + escape(ATTR(invoke, "srcexpr")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* id */ "; + stream << (HAS_ATTR(invoke, "id") ? "\"" + escape(ATTR(invoke, "id")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* idlocation */ "; + stream << (HAS_ATTR(invoke, "idlocation") ? "\"" + escape(ATTR(invoke, "idlocation")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* namelist */ "; + stream << (HAS_ATTR(invoke, "namelist") ? "\"" + escape(ATTR(invoke, "namelist")) + "\"" : "NULL"); + stream << ", " << std::endl; + + stream << " /* autoforward */ "; + stream << (HAS_ATTR(invoke, "autoforward") && stringIsTrue(ATTR(invoke, "autoforward")) ? "1" : "0"); + stream << ", " << std::endl; + + stream << " /* params */ "; + if (HAS_ATTR(invoke, "paramIndex")) { + stream << "&" << _prefix << "_elem_params[" << escape(ATTR(invoke, "paramIndex")) << "]"; + } else { + stream << "NULL"; + } + stream << ", " << std::endl; + + stream << " /* finalize */ "; + NodeSet finalizes = filterChildElements(_nsInfo.xmlNSPrefix + "finalize", invoke); + if (finalizes.size() > 0) { + stream << _prefix << "_" << DOMUtils::idForNode(finalizes[0]); + } else { + stream << "NULL"; + } + stream << ", " << std::endl; + + NodeSet contents = filterChildElements(_nsInfo.xmlNSPrefix + "content", invoke); + if (contents.size() > 0 && !HAS_ATTR(invoke, "md5sum")) { + std::stringstream ss; + NodeList cChilds = contents[0].getChildNodes(); + for (size_t j = 0; j < cChilds.getLength(); j++) { + ss << cChilds.item(j); + } + stream << " /* content */ "; + stream << (ss.str().size() > 0 ? "\"" + escape(ss.str()) + "\", " : "NULL, ") << std::endl; + stream << " /* contentexpr */ "; + stream << (HAS_ATTR_CAST(contents[0], "expr") ? "\"" + ATTR_CAST(contents[0], "expr") + "\", " : "NULL, ") << std::endl; + } else { + stream << " /* content */ NULL," << std::endl; + stream << " /* contentexpr */ NULL," << std::endl; + } + + stream << " }" << (i + 1 < invokes.size() ? ",": "") << std::endl; + invoke.setAttribute("documentOrder", toStr(i)); + + } + stream << "};" << std::endl; + stream << std::endl; + } + +} + void ChartToC::writeElementInfo(std::ostream& stream) { NodeSet foreachs = filterChildElements(_nsInfo.xmlNSPrefix + "foreach", _scxml, true); if (foreachs.size() > 0) { - stream << "static const scxml_elem_foreach scxml_elem_foreachs[" << foreachs.size() << "] = {" << std::endl; + _hasElement.insert("foreach"); + stream << "static const scxml_elem_foreach " << _prefix << "_elem_foreachs[" << foreachs.size() << "] = {" << std::endl; stream << " /* array, item, index */" << std::endl; for (size_t i = 0; i < foreachs.size(); i++) { Element foreach(foreachs[i]); @@ -1047,6 +1261,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { NodeSet datas = filterChildElements(_nsInfo.xmlNSPrefix + "data", _scxml, true); if (datas.size() > 0) { + _hasElement.insert("data"); size_t dataIndexOffset = 0; Node parent; size_t distinctParents = 0; @@ -1065,7 +1280,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { parent = Node(); - stream << "static const scxml_elem_data scxml_elem_datas[" << datas.size() + distinctParents << "] = {" << std::endl; + stream << "static const scxml_elem_data " << _prefix << "_elem_datas[" << datas.size() + distinctParents << "] = {" << std::endl; stream << " /* id, src, expr, content */" << std::endl; for (size_t i = 0; i < datas.size(); i++) { Element data(datas[i]); @@ -1103,6 +1318,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { NodeSet params = filterChildElements(_nsInfo.xmlNSPrefix + "param", _scxml, true); if (params.size() > 0) { + _hasElement.insert("param"); Node parent; size_t distinctParents = 0; for (size_t i = 0; i < params.size(); i++) { @@ -1113,7 +1329,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { } parent = Node(); - stream << "static const scxml_elem_param scxml_elem_params[" << params.size() + distinctParents << "] = {" << std::endl; + stream << "static const scxml_elem_param " << _prefix << "_elem_params[" << params.size() + distinctParents << "] = {" << std::endl; stream << " /* name, expr, location */" << std::endl; for (size_t i = 0; i < params.size(); i++) { Element param(params[i]); @@ -1138,7 +1354,8 @@ void ChartToC::writeElementInfo(std::ostream& stream) { NodeSet sends = filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true); if (sends.size() > 0) { - stream << "static const scxml_elem_send scxml_elem_sends[" << sends.size() << "] = {" << std::endl; + _hasElement.insert("send"); + stream << "static const scxml_elem_send " << _prefix << "_elem_sends[" << sends.size() << "] = {" << std::endl; for (size_t i = 0; i < sends.size(); i++) { Element send(sends[i]); stream << " { "; @@ -1186,7 +1403,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << std::endl << " /* params */ "; if (HAS_ATTR(send, "paramIndex")) { - stream << "&scxml_elem_params[" << escape(ATTR(send, "paramIndex")) << "] "; + stream << "&" << _prefix << "_elem_params[" << escape(ATTR(send, "paramIndex")) << "] "; } else { stream << "NULL "; } @@ -1199,9 +1416,10 @@ void ChartToC::writeElementInfo(std::ostream& stream) { } NodeSet donedatas = filterChildElements(_nsInfo.xmlNSPrefix + "donedata", _scxml, true); - stream << "static const scxml_elem_donedata scxml_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl; + stream << "static const scxml_elem_donedata " << _prefix << "_elem_donedatas[" << donedatas.size() + 1 << "] = {" << std::endl; stream << " /* source, content, contentexpr, params */" << std::endl; for (size_t i = 0; i < donedatas.size(); i++) { + _hasElement.insert("donedata"); Element donedata(donedatas[i]); stream << " { "; @@ -1222,7 +1440,7 @@ void ChartToC::writeElementInfo(std::ostream& stream) { } if (HAS_ATTR(donedata, "paramIndex")) { - stream << "&scxml_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]"; + stream << "&" << _prefix << "_elem_params[" << escape(ATTR(donedata, "paramIndex")) << "]"; } else { stream << "NULL"; } @@ -1236,11 +1454,57 @@ void ChartToC::writeElementInfo(std::ostream& stream) { } +void ChartToC::writeMachineInfo(std::ostream& stream) { + if (_topMostMachine != NULL) + return; + + stream << "const scxml_machine scxml_machines[" << _allMachines.size() + 1<< "] = {" << std::endl; + for (std::list::iterator machineIter = _allMachines.begin(); machineIter != _allMachines.end(); machineIter++) { + ChartToC* m = (*machineIter); + stream << " {" << std::endl; + stream << " /* flags */ 0," << std::endl; + stream << " /* nr_states */ " << m->_states.size() << "," << std::endl; + stream << " /* nr_transitions */ " << m->_transitions.size() << "," << std::endl; + stream << " /* name */ \"" << escape(m->_name) << "\"," << std::endl; + stream << " /* datamodel */ \"" << (HAS_ATTR(m->_scxml, "datamodel") ? ATTR(m->_scxml, "datamodel") : "null") << "\"," << std::endl; + stream << " /* uuid */ \"" << m->_md5 << "\"," << std::endl; + stream << " /* states */ " << "&" << m->_prefix << "_states[0], " << std::endl; + stream << " /* transitions */ " << "&" << m->_prefix << "_transitions[0], " << std::endl; + stream << " /* parent */ "; + if (m->_parentMachine != NULL) { + size_t parentIndex = 0; + for (std::list::iterator parentIter = _allMachines.begin(); parentIter != _allMachines.end(); parentIter++, parentIndex++) { + if (*parentIter == m->_parentMachine) { + stream << "&scxml_machines[" << toStr(parentIndex) << "]"; + } + } + } else { + stream << "NULL"; + } + stream << "," << std::endl; + + stream << " /* donedata */ " << "&" << m->_prefix << "_elem_donedatas[0], " << std::endl; + stream << " /* script */ "; + if (filterChildElements(_nsInfo.xmlNSPrefix + "script", _scxml).size() > 0) { + stream << m->_prefix << "_global_script" << std::endl; + } else { + stream << "NULL"; + } + stream << std::endl; + + stream << " }," << std::endl; + + } + stream << " {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }" << std::endl; + stream << "};" << std::endl; + stream << std::endl; +} + void ChartToC::writeStates(std::ostream& stream) { - stream << "static const scxml_state scxml_states[" << toStr(_states.size()) << "] = {" << std::endl; + stream << "static const scxml_state " << _prefix << "_states[" << toStr(_states.size()) << "] = {" << std::endl; for (size_t i = 0; i < _states.size(); i++) { Element state(_states[i]); - + stream << " { /* state number " << toStr(i) << " */" << std::endl; // name @@ -1255,17 +1519,17 @@ void ChartToC::writeStates(std::ostream& stream) { // onentry stream << " /* onentry */ "; - stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state).size() > 0 ? DOMUtils::idForNode(state) + "_on_entry" : "NULL"); + stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onentry", state).size() > 0 ? _prefix + "_" + DOMUtils::idForNode(state) + "_on_entry" : "NULL"); stream << "," << std::endl; // onexit stream << " /* onexit */ "; - stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state).size() > 0 ? DOMUtils::idForNode(state) + "_on_exit" : "NULL"); + stream << (filterChildElements(_nsInfo.xmlNSPrefix + "onexit", state).size() > 0 ? _prefix + "_" + DOMUtils::idForNode(state) + "_on_exit" : "NULL"); stream << "," << std::endl; // invokers stream << " /* invoke */ "; - stream << (filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state).size() > 0 ? DOMUtils::idForNode(state) + "_invoke" : "NULL"); + stream << (filterChildElements(_nsInfo.xmlNSPrefix + "invoke", state).size() > 0 ? _prefix + "_" + DOMUtils::idForNode(state) + "_invoke" : "NULL"); stream << "," << std::endl; // children @@ -1279,15 +1543,15 @@ void ChartToC::writeStates(std::ostream& stream) { stream << " /* " << ATTR(state, "completionBools") << " */ }, \t" << std::endl; stream << " /* ancestors */ { "; - writeCharArrayInitList(stream, ATTR(state, "ancBools")); + writeCharArrayInitList(stream, ATTR(state, "ancBools")); stream << " /* " << ATTR(state, "ancBools") << " */ }," << std::endl; stream << " /* data */ "; - stream << (HAS_ATTR(state, "dataIndex") ? "&scxml_elem_datas[" + escape(ATTR(state, "dataIndex")) + "]" : "NULL"); + stream << (HAS_ATTR(state, "dataIndex") ? "&" + _prefix + "_elem_datas[" + escape(ATTR(state, "dataIndex")) + "]" : "NULL"); stream << "," << std::endl; stream << " /* type */ "; - + if (false) { } else if (iequals(TAGNAME(state), "initial")) { stream << "SCXML_STATE_INITIAL"; @@ -1328,25 +1592,14 @@ void ChartToC::writeTransitions(std::ostream& stream) { elements.insert(_nsInfo.xmlNSPrefix + "transition"); NodeSet transDocOrder = DOMUtils::inDocumentOrder(elements, _scxml); - stream << "static const scxml_transition scxml_transitions[" << toStr(_transitions.size()) << "] = {" << std::endl; + stream << "static const scxml_transition " << _prefix << "_transitions[" << toStr(_transitions.size()) << "] = {" << std::endl; for (size_t i = 0; i < _transitions.size(); i++) { Element transition(_transitions[i]); - + stream << " { /* transition number " << ATTR(transition, "documentOrder") << " with priority " << toStr(i) << std::endl; stream << " target: " << ATTR(transition, "target") << std::endl; stream << " */" << std::endl; - /** - uint16_t source; - target[SCXML_NUMBER_STATES / 8 + 1]; - const char* event; - const char* condition; - exec_content_t on_transition; - uint8_t type; - char conflicts[SCXML_NUMBER_STATES / 8 + 1]; - char exit_set[SCXML_NUMBER_STATES / 8 + 1]; - */ - // source stream << " /* source */ "; stream << ATTR_CAST(transition.getParentNode(), "documentOrder"); @@ -1375,7 +1628,7 @@ void ChartToC::writeTransitions(std::ostream& stream) { // on transition handlers stream << " /* ontrans */ "; if (filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, transition).size() > 0) { - stream << DOMUtils::idForNode(transition) + "_on_trans"; + stream << _prefix << "_" << DOMUtils::idForNode(transition) + "_on_trans"; } else { stream << "NULL"; } @@ -1481,10 +1734,13 @@ void ChartToC::writeCharArrayInitList(std::ostream& stream, const std::string& b } std::string seperator = ""; + std::ios::fmtflags f(stream.flags()); + for (std::string::const_iterator cIter = charArray.begin(); cIter != charArray.end(); cIter++) { stream << seperator << "0x" << std::setw(2) << std::setfill('0') << std::hex << int(*cIter & 0xFF); seperator = ", "; } + stream.flags(f); } void ChartToC::writeFSM(std::ostream& stream) { @@ -1493,31 +1749,33 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Config: \");" << std::endl; - stream << " printStateNames(ctx->config);" << std::endl; + stream << " printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES);" << std::endl; stream << "#endif" << std::endl; stream << std::endl; - stream << "// MACRO_STEP:" << std::endl; -// stream << " ctx->flags &= ~SCXML_CTX_TRANSITION_FOUND;" << std::endl; - stream << std::endl; - stream << " if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) " << std::endl; stream << " return SCXML_ERR_DONE; " << std::endl; stream << std::endl; - stream << " size_t i, j, k;" << std::endl; - stream << " int err = SCXML_ERR_OK;" << std::endl; - stream << " char conflicts[" << _transCharArraySize << "] = " << _transCharArrayInit << ";" << std::endl; - stream << " char target_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl; - stream << " char exit_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl; - stream << " char trans_set[" << _transCharArraySize << "] = " << _transCharArrayInit << ";" << std::endl; - stream << " char entry_set[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl; - stream << " char tmp_states[" << _stateCharArraySize << "] = " << _stateCharArrayInit << ";" << std::endl; + stream << " " << (_states.size() > _transitions.size() ? "SCXML_NR_STATES_TYPE" : "SCXML_NR_TRANS_TYPE") << " i, j, k;" << std::endl; + stream << " SCXML_NR_STATES_TYPE nr_states_bytes = ((SCXML_NUMBER_STATES + 7) & ~7) >> 3;" << std::endl; + stream << " SCXML_NR_TRANS_TYPE nr_trans_bytes = ((SCXML_NUMBER_TRANS + 7) & ~7) >> 3;" << std::endl; + stream << " int err = SCXML_ERR_OK;" << std::endl; + + stream << " char conflicts [SCXML_MAX_NR_TRANS_BYTES];" << std::endl; + stream << " char trans_set [SCXML_MAX_NR_TRANS_BYTES];" << std::endl; + stream << " char target_set [SCXML_MAX_NR_STATES_BYTES];" << std::endl; + stream << " char exit_set [SCXML_MAX_NR_STATES_BYTES];" << std::endl; + stream << " char entry_set [SCXML_MAX_NR_STATES_BYTES];" << std::endl; + stream << " char tmp_states [SCXML_MAX_NR_STATES_BYTES];" << std::endl; stream << std::endl; + stream << " bit_clear_all(target_set, nr_states_bytes);" << std::endl; + stream << " bit_clear_all(trans_set, nr_trans_bytes);" << std::endl; stream << " if unlikely(ctx->flags == SCXML_CTX_PRISTINE) {" << std::endl; - stream << " global_script(ctx, &scxml_states[0], NULL);" << std::endl; - stream << " bit_or(target_set, scxml_states[0].completion, " << _stateCharArraySize << ");" << std::endl; + stream << " if (ctx->machine->script != NULL)" << std::endl; + stream << " ctx->machine->script(ctx, &ctx->machine->states[0], NULL);" << std::endl; + stream << " bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes);" << std::endl; stream << " ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED;" << std::endl; stream << " goto ESTABLISH_ENTRY_SET;" << std::endl; stream << " }" << std::endl; @@ -1530,42 +1788,63 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl; stream << " goto SELECT_TRANSITIONS;" << std::endl; stream << " }" << std::endl; + stream << std::endl; + + stream << " // manage invocations" << std::endl; + stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl; + stream << " // uninvoke" << std::endl; + stream << " if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) {" << std::endl; + stream << " if (ctx->machine->states[i].invoke != NULL)" << std::endl; + stream << " ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 1);" << std::endl; + stream << " BIT_CLEAR(i, ctx->invocations)" << std::endl; + stream << " }" << std::endl; + stream << " // invoke" << std::endl; + stream << " if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) {" << std::endl; + stream << " if (ctx->machine->states[i].invoke != NULL)" << std::endl; + stream << " ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 0);" << std::endl; + stream << " BIT_SET_AT(i, ctx->invocations)" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; + stream << " if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl; stream << " goto SELECT_TRANSITIONS;" << std::endl; stream << " }" << std::endl; stream << std::endl; stream << "SELECT_TRANSITIONS:" << std::endl; - stream << " for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl; + stream << " bit_clear_all(conflicts, nr_trans_bytes);" << std::endl; + stream << " bit_clear_all(exit_set, nr_states_bytes);" << std::endl; + stream << " for (i = 0; i < SCXML_NUMBER_TRANS; i++) {" << std::endl; stream << " // never select history or initial transitions automatically" << std::endl; - stream << " if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))" << std::endl; + stream << " if unlikely(ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL))" << std::endl; stream << " continue;" << std::endl; stream << std::endl; stream << " // is the transition active?" << std::endl; - stream << " if (BIT_HAS(scxml_transitions[i].source, ctx->config)) {" << std::endl; + stream << " if (BIT_HAS(ctx->machine->transitions[i].source, ctx->config)) {" << std::endl; stream << " // is it non-conflicting?" << std::endl; stream << " if (!BIT_HAS(i, conflicts)) {" << std::endl; stream << " // is it enabled?" << std::endl; - stream << " if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) {" << std::endl; + stream << " if (ctx->is_enabled(ctx, &ctx->machine->transitions[i], ctx->event) > 0) {" << std::endl; stream << " // remember that we found a transition" << std::endl; stream << " ctx->flags |= SCXML_CTX_TRANSITION_FOUND;" << std::endl; stream << std::endl; stream << " // transitions that are pre-empted" << std::endl; - stream << " bit_or(conflicts, scxml_transitions[i].conflicts, " << _transCharArraySize << ");" << std::endl; + stream << " bit_or(conflicts, ctx->machine->transitions[i].conflicts, nr_trans_bytes);" << std::endl; stream << std::endl; stream << " // states that are directly targeted (resolve as entry-set later)" << std::endl; - stream << " bit_or(target_set, scxml_transitions[i].target, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_or(target_set, ctx->machine->transitions[i].target, nr_states_bytes);" << std::endl; stream << std::endl; stream << " // states that will be left" << std::endl; - stream << " bit_or(exit_set, scxml_transitions[i].exit_set, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_or(exit_set, ctx->machine->transitions[i].exit_set, nr_states_bytes);" << std::endl; stream << std::endl; stream << " BIT_SET_AT(i, trans_set);" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; - stream << " bit_and(exit_set, ctx->config, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_and(exit_set, ctx->config, nr_states_bytes);" << std::endl; stream << std::endl; stream << " if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) {" << std::endl; @@ -1579,38 +1858,38 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Targets: \");" << std::endl; - stream << " printStateNames(target_set);" << std::endl; + stream << " printStateNames(ctx, target_set, SCXML_NUMBER_STATES);" << std::endl; stream << "#endif" << std::endl; stream << std::endl; stream << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Exiting: \");" << std::endl; - stream << " printStateNames(exit_set);" << std::endl; + stream << " printStateNames(ctx, exit_set, SCXML_NUMBER_STATES);" << std::endl; stream << "#endif" << std::endl; stream << std::endl; stream << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"History: \");" << std::endl; - stream << " printStateNames(ctx->history);" << std::endl; + stream << " printStateNames(ctx, ctx->history, SCXML_NUMBER_STATES);" << std::endl; stream << "#endif" << std::endl; stream << std::endl; stream << "// REMEMBER_HISTORY:" << std::endl; stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl; - stream << " if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl; - stream << " SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP) {" << std::endl; + stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl; + stream << " SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP) {" << std::endl; stream << " // a history state whose parent is about to be exited" << std::endl; - stream << " if unlikely(BIT_HAS(scxml_states[i].parent, exit_set)) {" << std::endl; - stream << " bit_copy(tmp_states, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl; + stream << " if unlikely(BIT_HAS(ctx->machine->states[i].parent, exit_set)) {" << std::endl; + stream << " bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl; stream << std::endl; stream << " // set those states who were enabled" << std::endl; - stream << " bit_and(tmp_states, ctx->config, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_and(tmp_states, ctx->config, nr_states_bytes);" << std::endl; stream << std::endl; stream << " // clear current history with completion mask" << std::endl; - stream << " bit_and_not(ctx->history, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_and_not(ctx->history, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl; stream << std::endl; stream << " // set history" << std::endl; - stream << " bit_or(ctx->history, tmp_states, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_or(ctx->history, tmp_states, nr_states_bytes);" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -1618,12 +1897,12 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "ESTABLISH_ENTRY_SET:" << std::endl; stream << " // calculate new entry set" << std::endl; - stream << " bit_copy(entry_set, target_set, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_copy(entry_set, target_set, nr_states_bytes);" << std::endl; stream << std::endl; stream << " // iterate for ancestors" << std::endl; stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl; stream << " if (BIT_HAS(i, entry_set)) {" << std::endl; - stream << " bit_or(entry_set, scxml_states[i].ancestors, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[i].ancestors, nr_states_bytes);" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << std::endl; @@ -1631,24 +1910,24 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " // iterate for descendants" << std::endl; stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl; stream << " if (BIT_HAS(i, entry_set)) {" << std::endl; - stream << " switch (SCXML_STATE_MASK(scxml_states[i].type)) {" << std::endl; + stream << " switch (SCXML_STATE_MASK(ctx->machine->states[i].type)) {" << std::endl; stream << " case SCXML_STATE_PARALLEL: {" << std::endl; - stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl; stream << " break;" << std::endl; stream << " }" << std::endl; stream << " case SCXML_STATE_HISTORY_SHALLOW:" << std::endl; stream << " case SCXML_STATE_HISTORY_DEEP: {" << std::endl; - stream << " if (!bit_has_and(scxml_states[i].completion, ctx->history, " << _stateCharArraySize << ") &&" << std::endl; - stream << " !BIT_HAS(scxml_states[i].parent, ctx->config)) {" << std::endl; + stream << " if (!bit_has_and(ctx->machine->states[i].completion, ctx->history, nr_states_bytes) &&" << std::endl; + stream << " !BIT_HAS(ctx->machine->states[i].parent, ctx->config)) {" << std::endl; stream << " // nothing set for history, look for a default transition" << std::endl; - stream << " for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl; - stream << " if unlikely(scxml_transitions[j].source == i) {" << std::endl; - stream << " bit_or(entry_set, scxml_transitions[j].target, " << _stateCharArraySize << ");" << std::endl; - stream << " if(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP &&" << std::endl; - stream << " !bit_has_and(scxml_transitions[j].target, scxml_states[i].children, " << _stateCharArraySize << ")) {" << std::endl; + stream << " for (j = 0; j < SCXML_NUMBER_TRANS; j++) {" << std::endl; + stream << " if unlikely(ctx->machine->transitions[j].source == i) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl; + stream << " if(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP &&" << std::endl; + stream << " !bit_has_and(ctx->machine->transitions[j].target, ctx->machine->states[i].children, nr_states_bytes)) {" << std::endl; stream << " for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {" << std::endl; - stream << " if (BIT_HAS(k, scxml_transitions[j].target)) {" << std::endl; - stream << " bit_or(entry_set, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl; + stream << " if (BIT_HAS(k, ctx->machine->transitions[j].target)) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl; stream << " break;" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -1659,20 +1938,20 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " // Note: SCXML mandates every history to have a transition!" << std::endl; stream << " }" << std::endl; stream << " } else {" << std::endl; - stream << " bit_copy(tmp_states, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl; - stream << " bit_and(tmp_states, ctx->history, " << _stateCharArraySize << ");" << std::endl; - stream << " bit_or(entry_set, tmp_states, " << _stateCharArraySize << ");" << std::endl; - stream << " if (scxml_states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {" << std::endl; + stream << " bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl; + stream << " bit_and(tmp_states, ctx->history, nr_states_bytes);" << std::endl; + stream << " bit_or(entry_set, tmp_states, nr_states_bytes);" << std::endl; + stream << " if (ctx->machine->states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) {" << std::endl; stream << " // a deep history state with nested histories -> more completion" << std::endl; stream << " for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {" << std::endl; - stream << " if (BIT_HAS(j, scxml_states[i].completion) &&" << std::endl; + stream << " if (BIT_HAS(j, ctx->machine->states[i].completion) &&" << std::endl; stream << " BIT_HAS(j, entry_set) &&" << std::endl; - stream << " (scxml_states[j].type & SCXML_STATE_HAS_HISTORY)) {" << std::endl; + stream << " (ctx->machine->states[j].type & SCXML_STATE_HAS_HISTORY)) {" << std::endl; stream << " for (k = j + 1; k < SCXML_NUMBER_STATES; k++) {" << std::endl; stream << " // add nested history to entry_set" << std::endl; - stream << " if ((SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl; - stream << " SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&" << std::endl; - stream << " BIT_HAS(k, scxml_states[j].children)) {" << std::endl; + stream << " if ((SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl; + stream << " SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_SHALLOW) &&" << std::endl; + stream << " BIT_HAS(k, ctx->machine->states[j].children)) {" << std::endl; stream << " // a nested history state" << std::endl; stream << " BIT_SET_AT(k, entry_set);" << std::endl; stream << " }" << std::endl; @@ -1684,14 +1963,14 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " break;" << std::endl; stream << " }" << std::endl; stream << " case SCXML_STATE_INITIAL: {" << std::endl; - stream << " for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl; - stream << " if (scxml_transitions[j].source == i) {" << std::endl; + stream << " for (j = 0; j < SCXML_NUMBER_TRANS; j++) {" << std::endl; + stream << " if (ctx->machine->transitions[j].source == i) {" << std::endl; stream << " BIT_SET_AT(j, trans_set);" << std::endl; stream << " BIT_CLEAR(i, entry_set);" << std::endl; - stream << " bit_or(entry_set, scxml_transitions[j].target, " << _stateCharArraySize << ");" << std::endl; + stream << " bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl; stream << " for (k = i + 1; k < SCXML_NUMBER_STATES; k++) {" << std::endl; - stream << " if (BIT_HAS(k, scxml_transitions[j].target)) {" << std::endl; - stream << " bit_or(entry_set, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl; + stream << " if (BIT_HAS(k, ctx->machine->transitions[j].target)) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -1699,16 +1978,16 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " break;" << std::endl; stream << " }" << std::endl; stream << " case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set" << std::endl; - stream << " if (!bit_has_and(entry_set, scxml_states[i].children, " << _stateCharArraySize << ") &&" << std::endl; - stream << " (!bit_has_and(ctx->config, scxml_states[i].children, " << _stateCharArraySize << ") ||" << std::endl; - stream << " bit_has_and(exit_set, scxml_states[i].children, " << _stateCharArraySize << ")))" << std::endl; + stream << " if (!bit_has_and(entry_set, ctx->machine->states[i].children, nr_states_bytes) &&" << std::endl; + stream << " (!bit_has_and(ctx->config, ctx->machine->states[i].children, nr_states_bytes) ||" << std::endl; + stream << " bit_has_and(exit_set, ctx->machine->states[i].children, nr_states_bytes)))" << std::endl; stream << " {" << std::endl; - stream << " bit_or(entry_set, scxml_states[i].completion, " << _stateCharArraySize << ");" << std::endl; - stream << " if (!bit_has_and(scxml_states[i].completion, scxml_states[i].children, " << _stateCharArraySize << ")) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes);" << std::endl; + stream << " if (!bit_has_and(ctx->machine->states[i].completion, ctx->machine->states[i].children, nr_states_bytes)) {" << std::endl; stream << " // deep completion" << std::endl; stream << " for (j = i + 1; j < SCXML_NUMBER_STATES; j++) {" << std::endl; - stream << " if (BIT_HAS(j, scxml_states[i].completion)) {" << std::endl; - stream << " bit_or(entry_set, scxml_states[j].ancestors, " << _stateCharArraySize << ");" << std::endl; + stream << " if (BIT_HAS(j, ctx->machine->states[i].completion)) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes);" << std::endl; stream << " break; // completion of compound is single state" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -1723,7 +2002,7 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Transitions: \");" << std::endl; - stream << " printBitsetIndices(trans_set, sizeof(char) * 8 * " << _transCharArraySize << ");" << std::endl; + stream << " printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes);" << std::endl; stream << "#endif" << std::endl; stream << std::endl; @@ -1732,8 +2011,8 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " while(i-- > 0) {" << std::endl; stream << " if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) {" << std::endl; stream << " // call all on exit handlers" << std::endl; - stream << " if (scxml_states[i].on_exit != NULL) {" << std::endl; - stream << " if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl; + stream << " if (ctx->machine->states[i].on_exit != NULL) {" << std::endl; + stream << " if unlikely((err = ctx->machine->states[i].on_exit(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl; stream << " return err;" << std::endl; stream << " }" << std::endl; stream << " BIT_CLEAR(i, ctx->config);" << std::endl; @@ -1742,13 +2021,13 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << std::endl; stream << "// TAKE_TRANSITIONS:" << std::endl; - stream << " for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl; - stream << " if (BIT_HAS(i, trans_set) && (scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {" << std::endl; + stream << " for (i = 0; i < SCXML_NUMBER_TRANS; i++) {" << std::endl; + stream << " if (BIT_HAS(i, trans_set) && (ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {" << std::endl; stream << " // call executable content in transition" << std::endl; - stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl; - stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl; - stream << " &scxml_states[scxml_transitions[i].source]," << std::endl; - stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl; + stream << " if (ctx->machine->transitions[i].on_transition != NULL) {" << std::endl; + stream << " if unlikely((err = ctx->machine->transitions[i].on_transition(ctx," << std::endl; + stream << " &ctx->machine->states[ctx->machine->transitions[i].source]," << std::endl; + stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl; stream << " return err;" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -1757,7 +2036,7 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "#ifdef SCXML_VERBOSE" << std::endl; stream << " printf(\"Entering: \");" << std::endl; - stream << " printStateNames(entry_set);" << std::endl; + stream << " printStateNames(ctx, entry_set, SCXML_NUMBER_STATES);" << std::endl; stream << "#endif" << std::endl; stream << std::endl; @@ -1765,9 +2044,9 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " for (i = 0; i < SCXML_NUMBER_STATES; i++) {" << std::endl; stream << " if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) {" << std::endl; stream << " // these are no proper states" << std::endl; - stream << " if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl; - stream << " SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl; - stream << " SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_INITIAL)" << std::endl; + stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP ||" << std::endl; + stream << " SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW ||" << std::endl; + stream << " SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_INITIAL)" << std::endl; stream << " continue;" << std::endl; stream << std::endl; @@ -1776,29 +2055,29 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " // initialize data" << std::endl; stream << " if (!BIT_HAS(i, ctx->initialized_data)) {" << std::endl; - stream << " if unlikely(scxml_states[i].data != NULL && ctx->exec_content_init != NULL) {" << std::endl; - stream << " ctx->exec_content_init(ctx, scxml_states[i].data);" << std::endl; + stream << " if unlikely(ctx->machine->states[i].data != NULL && ctx->exec_content_init != NULL) {" << std::endl; + stream << " ctx->exec_content_init(ctx, ctx->machine->states[i].data);" << std::endl; stream << " }" << std::endl; stream << " BIT_SET_AT(i, ctx->initialized_data);" << std::endl; stream << " }" << std::endl; stream << std::endl; - stream << " if (scxml_states[i].on_entry != NULL) {" << std::endl; - stream << " if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl; + stream << " if (ctx->machine->states[i].on_entry != NULL) {" << std::endl; + stream << " if unlikely((err = ctx->machine->states[i].on_entry(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK)" << std::endl; stream << " return err;" << std::endl; stream << " }" << std::endl; stream << std::endl; stream << " // take history and initial transitions" << std::endl; - stream << " for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl; + stream << " for (j = 0; j < SCXML_NUMBER_TRANS; j++) {" << std::endl; stream << " if unlikely(BIT_HAS(j, trans_set) &&" << std::endl; - stream << " (scxml_transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&" << std::endl; - stream << " scxml_states[scxml_transitions[j].source].parent == i) {" << std::endl; + stream << " (ctx->machine->transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&" << std::endl; + stream << " ctx->machine->states[ctx->machine->transitions[j].source].parent == i) {" << std::endl; stream << " // call executable content in transition" << std::endl; - stream << " if (scxml_transitions[j].on_transition != NULL) {" << std::endl; - stream << " if unlikely((err = scxml_transitions[j].on_transition(ctx," << std::endl; - stream << " &scxml_states[i]," << std::endl; - stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl; + stream << " if (ctx->machine->transitions[j].on_transition != NULL) {" << std::endl; + stream << " if unlikely((err = ctx->machine->transitions[j].on_transition(ctx," << std::endl; + stream << " &ctx->machine->states[i]," << std::endl; + stream << " ctx->event)) != SCXML_ERR_OK)" << std::endl; stream << " return err;" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; @@ -1806,18 +2085,18 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << std::endl; stream << " // handle final states" << std::endl; - stream << " if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_FINAL) {" << std::endl; - stream << " if unlikely(scxml_states[i].ancestors[0] == 0x01) {" << std::endl; + stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_FINAL) {" << std::endl; + stream << " if unlikely(ctx->machine->states[i].ancestors[0] == 0x01) {" << std::endl; stream << " ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL;" << std::endl; stream << " } else {" << std::endl; stream << " // raise done event" << std::endl; - stream << " const scxml_elem_donedata* donedata = &scxml_elem_donedatas[0];" << std::endl; + stream << " const scxml_elem_donedata* donedata = &ctx->machine->donedata[0];" << std::endl; stream << " while(ELEM_DONEDATA_IS_SET(donedata)) {" << std::endl; stream << " if unlikely(donedata->source == i)" << std::endl; stream << " break;" << std::endl; stream << " donedata++;" << std::endl; stream << " }" << std::endl; - stream << " ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl; + stream << " ctx->raise_done_event(ctx, &ctx->machine->states[ctx->machine->states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl; stream << " }" << std::endl; stream << std::endl; @@ -1829,20 +2108,20 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl; stream << " */" << std::endl; stream << " for (j = 0; j < SCXML_NUMBER_STATES; j++) {" << std::endl; - stream << " if unlikely(SCXML_STATE_MASK(scxml_states[j].type) == SCXML_STATE_PARALLEL &&" << std::endl; - stream << " BIT_HAS(j, scxml_states[i].ancestors)) {" << std::endl; - stream << " bit_and_not(tmp_states, tmp_states, " << _stateCharArraySize << ");" << std::endl; + stream << " if unlikely(SCXML_STATE_MASK(ctx->machine->states[j].type) == SCXML_STATE_PARALLEL &&" << std::endl; + stream << " BIT_HAS(j, ctx->machine->states[i].ancestors)) {" << std::endl; + stream << " bit_clear_all(tmp_states, nr_states_bytes);" << std::endl; stream << " for (k = 0; k < SCXML_NUMBER_STATES; k++) {" << std::endl; - stream << " if unlikely(BIT_HAS(j, scxml_states[k].ancestors) && BIT_HAS(k, ctx->config)) {" << std::endl; - stream << " if (SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_FINAL) {" << std::endl; - stream << " bit_and_not(tmp_states, scxml_states[k].ancestors, " << _stateCharArraySize << ");" << std::endl; + stream << " if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {" << std::endl; + stream << " if (SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_FINAL) {" << std::endl; + stream << " bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl; stream << " } else {" << std::endl; stream << " BIT_SET_AT(k, tmp_states);" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; - stream << " if unlikely(!bit_has_any(tmp_states, " << _stateCharArraySize << ")) {" << std::endl; - stream << " ctx->raise_done_event(ctx, &scxml_states[j], NULL);" << std::endl; + stream << " if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) {" << std::endl; + stream << " ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL);" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; stream << " }" << std::endl; diff --git a/src/uscxml/transform/ChartToC.h b/src/uscxml/transform/ChartToC.h index 1ac59f3..f9b9599 100644 --- a/src/uscxml/transform/ChartToC.h +++ b/src/uscxml/transform/ChartToC.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace uscxml { @@ -42,14 +43,18 @@ public: protected: ChartToC(const Interpreter& other); - + void writeIncludes(std::ostream& stream); void writeMacros(std::ostream& stream); void writeTypes(std::ostream& stream); void writeHelpers(std::ostream& stream); void writeExecContent(std::ostream& stream); + void writeExecContentFinalize(std::ostream& stream); + void writeElementInfoInvocation(std::ostream& stream); + void writeElementInfo(std::ostream& stream); + void writeMachineInfo(std::ostream& stream); void writeStates(std::ostream& stream); void writeTransitions(std::ostream& stream); void writeFSM(std::ostream& stream); @@ -61,16 +66,20 @@ protected: void resortStates(Arabica::DOM::Node& node); void setHistoryCompletion(); - void setStateCompletion(); - void prepare(); - + void setStateCompletion(); + void prepare(); + + void findNestedMachines(); + Interpreter interpreter; Arabica::XPath::NodeSet _states; Arabica::XPath::NodeSet _transitions; -// std::string md5sum; - + std::string _md5; + std::string _prefix; + std::set _hasElement; + size_t _transCharArraySize; std::string _transCharArrayInit; std::string _transDataType; @@ -78,6 +87,11 @@ protected: size_t _stateCharArraySize; std::string _stateCharArrayInit; std::string _stateDataType; + + ChartToC* _topMostMachine; + ChartToC* _parentMachine; + std::list _nestedMachines; + std::list _allMachines; }; } diff --git a/src/uscxml/transform/ChartToVHDL.cpp b/src/uscxml/transform/ChartToVHDL.cpp index 7631619..8e7f43f 100644 --- a/src/uscxml/transform/ChartToVHDL.cpp +++ b/src/uscxml/transform/ChartToVHDL.cpp @@ -53,89 +53,93 @@ ChartToVHDL::~ChartToVHDL() { } void ChartToVHDL::checkDocument() { - // filter unsupported stuff - Arabica::XPath::NodeSet unsupported; - - std::set elements; - elements.insert(_nsInfo.xmlNSPrefix + "datamodel"); - elements.insert(_nsInfo.xmlNSPrefix + "data"); - elements.insert(_nsInfo.xmlNSPrefix + "assign"); - elements.insert(_nsInfo.xmlNSPrefix + "donedata"); - elements.insert(_nsInfo.xmlNSPrefix + "content"); - elements.insert(_nsInfo.xmlNSPrefix + "param"); - elements.insert(_nsInfo.xmlNSPrefix + "script"); - - elements.insert(_nsInfo.xmlNSPrefix + "parallel"); - elements.insert(_nsInfo.xmlNSPrefix + "history"); - - elements.insert(_nsInfo.xmlNSPrefix + "if"); // implicit elseif und else - elements.insert(_nsInfo.xmlNSPrefix + "foreach"); - elements.insert(_nsInfo.xmlNSPrefix + "send"); - elements.insert(_nsInfo.xmlNSPrefix + "cancel"); - elements.insert(_nsInfo.xmlNSPrefix + "invoke"); - elements.insert(_nsInfo.xmlNSPrefix + "finalize"); - unsupported = DOMUtils::inDocumentOrder(elements, _scxml); - - std::stringstream ss; - if (unsupported.size() > 0) { - for (int i = 0; i < unsupported.size(); i++) { - ss << " " << DOMUtils::xPathForNode(unsupported[i]) << " unsupported" << std::endl; - } - throw std::runtime_error("Unsupported elements found:\n" + ss.str()); - } - - elements.clear(); - elements.insert(_nsInfo.xmlNSPrefix + "transition"); - unsupported = DOMUtils::inDocumentOrder(elements, _scxml); - - for (int i = 0; i < unsupported.size(); i++) { - Element transition(unsupported[i]); - if (HAS_ATTR(transition, "cond")) { - ERROR_PLATFORM_THROW("transition with conditions not supported!"); - } - if (!HAS_ATTR(transition, "target")) { - ERROR_PLATFORM_THROW("targetless transition not supported!"); - } - } + // filter unsupported stuff + Arabica::XPath::NodeSet unsupported; + + std::set elements; + elements.insert(_nsInfo.xmlNSPrefix + "datamodel"); + elements.insert(_nsInfo.xmlNSPrefix + "data"); + elements.insert(_nsInfo.xmlNSPrefix + "assign"); + elements.insert(_nsInfo.xmlNSPrefix + "donedata"); + elements.insert(_nsInfo.xmlNSPrefix + "content"); + elements.insert(_nsInfo.xmlNSPrefix + "param"); + elements.insert(_nsInfo.xmlNSPrefix + "script"); + + elements.insert(_nsInfo.xmlNSPrefix + "parallel"); + elements.insert(_nsInfo.xmlNSPrefix + "history"); + + elements.insert(_nsInfo.xmlNSPrefix + "if"); // implicit elseif und else + elements.insert(_nsInfo.xmlNSPrefix + "foreach"); + elements.insert(_nsInfo.xmlNSPrefix + "send"); + elements.insert(_nsInfo.xmlNSPrefix + "cancel"); + elements.insert(_nsInfo.xmlNSPrefix + "invoke"); + elements.insert(_nsInfo.xmlNSPrefix + "finalize"); + unsupported = DOMUtils::inDocumentOrder(elements, _scxml); + + std::stringstream ss; + if (unsupported.size() > 0) { + for (int i = 0; i < unsupported.size(); i++) { + ss << " " << DOMUtils::xPathForNode(unsupported[i]) << " unsupported" << std::endl; + } + throw std::runtime_error("Unsupported elements found:\n" + ss.str()); + } + + elements.clear(); + elements.insert(_nsInfo.xmlNSPrefix + "transition"); + unsupported = DOMUtils::inDocumentOrder(elements, _scxml); + + for (int i = 0; i < unsupported.size(); i++) { + Element transition(unsupported[i]); + if (HAS_ATTR(transition, "cond")) { + ERROR_PLATFORM_THROW("transition with conditions not supported!"); + } + if (!HAS_ATTR(transition, "target")) { + ERROR_PLATFORM_THROW("targetless transition not supported!"); + } + } } void ChartToVHDL::findEvents() { - // elements with an event attribute - NodeSet withEvent; - withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "raise", _scxml, true)); - withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true)); - withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true)); - - for (size_t i = 0; i < withEvent.size(); i++) { - if (HAS_ATTR_CAST(withEvent[i], "event")) { - _eventTrie.addWord(ATTR_CAST(withEvent[i], "event")); - } - } + // elements with an event attribute + NodeSet withEvent; + withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "raise", _scxml, true)); + withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "send", _scxml, true)); + withEvent.push_back(InterpreterImpl::filterChildElements(_nsInfo.xmlNSPrefix + "transition", _scxml, true)); + + for (size_t i = 0; i < withEvent.size(); i++) { + if (HAS_ATTR_CAST(withEvent[i], "event")) { + // TODO: tokenize! + if (ATTR_CAST(withEvent[i], "event") != "*") + _eventTrie.addWord(ATTR_CAST(withEvent[i], "event")); + } + } } - + void ChartToVHDL::writeTo(std::ostream& stream) { - // same preparations as the C transformation - prepare(); - + // same preparations as the C transformation + prepare(); + // checkDocument(); - findEvents(); - _eventTrie.dump(); - + findEvents(); +// _eventTrie.dump(); + + + writeOptimalTransitionSetSelection(stream); writeTypes(stream); - writeFiFo(stream); - writeTransitionSet(stream); - writeExitSet(stream); - writeEntrySet(stream); + writeFiFo(stream); + writeTransitionSet(stream); + writeExitSet(stream); + writeEntrySet(stream); writeFSM(stream); } void ChartToVHDL::writeTransitionSet(std::ostream & stream) { - for (size_t i = 0; i < _transitions.size(); i++) { - Element transition(_transitions[i]); - std::string name = DOMUtils::idForNode(transition); - - } + for (size_t i = 0; i < _transitions.size(); i++) { + Element transition(_transitions[i]); + std::string name = DOMUtils::idForNode(transition); + + } } void ChartToVHDL::writeExitSet(std::ostream & stream) { @@ -188,6 +192,7 @@ void ChartToVHDL::writeFSM(std::ostream & stream) { stream << "-- END FSM Logic" << std::endl; } +#if 0 void ChartToVHDL::writeTopDown(std::ostream & stream) { // create hardware top level stream << "-- top level" << std::endl; @@ -224,15 +229,16 @@ void ChartToVHDL::writeTopDown(std::ostream & stream) { stream << std::endl; stream << "end behavioral; " << std::endl; } +#endif void ChartToVHDL::writeTypes(std::ostream & stream) { std::string seperator = ""; - stream << "-- needed global types" << std::endl; + stream << "-- required global types" << std::endl; stream << "library IEEE;" << std::endl; stream << "use IEEE.std_logic_1164.all;" << std::endl; stream << std::endl; - stream << "package generated_p1 is" << std::endl; + stream << "package machine" << _md5 << " is" << std::endl; // create state type stream << " type state_type is std_logic_vector( "; stream << _states.size() - 1; @@ -252,7 +258,7 @@ void ChartToVHDL::writeTypes(std::ostream & stream) { } stream << ");" << std::endl; - stream << "end generated_p1;" << std::endl; + stream << "end machine" << _md5 << ";" << std::endl; stream << std::endl; stream << "-- END needed global types" << std::endl; } @@ -261,7 +267,7 @@ void ChartToVHDL::writeIncludes(std::ostream & stream) { // Add controler specific stuff here stream << "library IEEE;" << std::endl; stream << "use IEEE.std_logic_1164.all;" << std::endl; - stream << "use work.generated_p1.all;" << std::endl; + stream << "use work.machine" << _md5 << ".all;" << std::endl; stream << std::endl; } @@ -392,7 +398,7 @@ void ChartToVHDL::writeSignals(std::ostream & stream) { for (int i = 0; i < _transitions.size(); i++) { Element transition(_transitions[i]); - stream << "signal " << ATTR(transition, "id") << "_sig : std_logic;" + stream << "signal in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig : std_logic;" << std::endl; } @@ -462,6 +468,46 @@ void ChartToVHDL::writeErrorHandler(std::ostream & stream) { stream << std::endl; } +std::string ChartToVHDL::eventNameEscape(const std::string& eventName) { + std::string escaped = escape(eventName); + boost::replace_all(escaped, ".", "_"); + return escaped; +} + +void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream & stream) { + stream << "-- write optimal transition set selection" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + Element transition(_transitions[i]); + std::string conflicts = ATTR(transition, "conflictBools"); + + stream << "in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig " + << "<= " << (HAS_ATTR(transition, "event") ? "(not spontaneous_sig)" : "spontaneous_sig") << " and " << std::endl + << " state_active_" << ATTR(transition, "source") << "_sig and not ( 0 " << std::endl; + for (size_t j = 0; j < i; j++) { + if (conflicts[j] == '1') { + stream << " or in_optimal_transition_set_" << toStr(j) << "_sig" << std::endl; + } + } + stream << " )"; + if (HAS_ATTR(transition, "event")) { + stream << " and ( 0 " << std::endl;; + + // find all matching event literals + std::list eventDescs = tokenizeIdRefs(ATTR(transition, "event")); + for (std::list::iterator descIter = eventDescs.begin(); descIter != eventDescs.end(); descIter++) { + std::list eventNames = _eventTrie.getWordsWithPrefix((*descIter) == "*" ? "" : *descIter); + for (std::list::iterator eventIter = eventNames.begin(); eventIter != eventNames.end(); eventIter++) { + stream << " or event_" << eventNameEscape((*eventIter)->value) << "_sig" << std::endl; + } + } + stream << " )"; + + } + stream << ";" << std::endl; + } + +} + //TODO write event generator // wie die letzten beiden states erkennen // process bauen der bei fail 0 ausgibt und bei accept 1 @@ -476,16 +522,16 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { for (int i = 0; i < _states.size(); i++) { Element state(_states[i]); - // calculate event choises + // calculate event choices // _transitions is sorted in Postfix order // by stating with smalest index the most important // will be written first - std::vector< Element > choises; + std::vector< Element > choices; std::string spntaneous_trans_sig = ""; for (int j = 0; j < _transitions.size(); j++) { Element transition(_transitions[j]); if (ATTR_CAST(transition.getParentNode(), "id") == ATTR(state, "id")) { - choises.push_back(transition); + choices.push_back(transition); if (ATTR(transition, "event") == CONST_TRANS_SPONTANIOUS) { spntaneous_trans_sig = ATTR(transition, "id"); // FIXME hofully there are just single spntaneous transitions allowed @@ -503,13 +549,13 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { } } - if (choises.size() > 0) {// if no outgoing transitions (maybe final state :D) we don't write anything + if (choices.size() > 0) {// if no outgoing transitions (maybe final state :D) we don't write anything stream << " if ( " << ATTR(state, "id") << " = '1' ) then" << std::endl; stream << " if ( transition_spntaneous_en = '1' ) then" << std::endl; // enable spntaneous transition (if any) and disable all other - for (int j = 0; j < choises.size(); j++) { - Element transition(choises[j]); + for (int j = 0; j < choices.size(); j++) { + Element transition(choices[j]); if (ATTR(transition, "id") == spntaneous_trans_sig) { stream << " " << ATTR(transition, "id") << "_sig <= '1';" << std::endl; } else { @@ -524,8 +570,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { // FIXME hopefully there is just one transition per state and event at a time stream << " case next_event is" << std::endl; bool hasWildcardTransition = false; - for (int j = 0; j < choises.size(); j++) { - Element transition(choises[j]); + for (int j = 0; j < choices.size(); j++) { + Element transition(choices[j]); std::string eventName = ATTR(transition, "event"); if (eventName == CONST_EVENT_ANY) { eventName = "others"; @@ -533,8 +579,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { } stream << " when " << eventName << " =>" << std::endl; // activate transition and deactivete others - for (int k = 0; k < choises.size(); k++) { - Element tmp_t(choises[k]); + for (int k = 0; k < choices.size(); k++) { + Element tmp_t(choices[k]); if (ATTR(tmp_t, "event") == ATTR(transition, "event")) { stream << " " << ATTR(tmp_t, "id") << "_sig <= '1';" << std::endl; } else { @@ -545,8 +591,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { if (!hasWildcardTransition) { // if there is no others we create one for deactivating everything stream << " when others =>" << std::endl; - for (int j = 0; j < choises.size(); j++) { - Element tmp_t(choises[j]); + for (int j = 0; j < choices.size(); j++) { + Element tmp_t(choices[j]); stream << " " << ATTR(tmp_t, "id") << "_sig <= '0';" << std::endl; } } @@ -557,8 +603,8 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { stream << " else" << std::endl; // no enabled event ? disable all transitions (looks like we have to wait) - for (int j = 0; j < choises.size(); j++) { - Element transition(choises[j]); + for (int j = 0; j < choices.size(); j++) { + Element transition(choices[j]); stream << " " << ATTR(transition, "id") << "_sig <= '0';" << std::endl; } stream << " end if;" << std::endl; @@ -575,9 +621,9 @@ void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { nextStateBuffer << " ) or "; nextStateBuffer << "( ( not ( '0'"; seperator = " or "; - for (int j = 0; j < choises.size(); j++) { + for (int j = 0; j < choices.size(); j++) { nextStateBuffer << seperator - << ATTR(choises[j], "id") << "_sig"; + << ATTR(choices[j], "id") << "_sig"; } nextStateBuffer << " ) ) and " << ATTR(state, "id") << "_curr ));" << std::endl; diff --git a/src/uscxml/transform/ChartToVHDL.h b/src/uscxml/transform/ChartToVHDL.h index a2cbac7..64cf444 100644 --- a/src/uscxml/transform/ChartToVHDL.h +++ b/src/uscxml/transform/ChartToVHDL.h @@ -44,13 +44,14 @@ public: protected: ChartToVHDL(const Interpreter& other); - void checkDocument(); - void findEvents(); - + void checkDocument(); + void findEvents(); + void writeIncludes(std::ostream& stream); void writeTopDown(std::ostream& stream); void writeTypes(std::ostream& stream); + void writeOptimalTransitionSetSelection(std::ostream& stream); void writeNextStateLogic(std::ostream& stream); void writeOutputLogic(std::ostream& stream); void writeSignals(std::ostream& stream); @@ -59,11 +60,15 @@ protected: void writeErrorHandler(std::ostream& stream); void writeFSM(std::ostream& stream); - void writeTransitionSet(std::ostream & stream); - void writeExitSet(std::ostream & stream); - void writeEntrySet(std::ostream & stream); + void writeTransitionSet(std::ostream & stream); + void writeExitSet(std::ostream & stream); + void writeEntrySet(std::ostream & stream); + + Trie _eventTrie; + +private: + std::string eventNameEscape(const std::string& eventName); - Trie _eventTrie; }; diff --git a/src/uscxml/transform/Transformer.h b/src/uscxml/transform/Transformer.h index c88015b..3751c00 100644 --- a/src/uscxml/transform/Transformer.h +++ b/src/uscxml/transform/Transformer.h @@ -36,10 +36,10 @@ public: } protected: - std::multimap _extensions; - std::list _options; - - friend class Transformer; + std::multimap _extensions; + std::list _options; + + friend class Transformer; }; class USCXML_API Transformer : public boost::enable_shared_from_this { @@ -79,14 +79,14 @@ public: return _impl; } - void setExtensions(const std::multimap& extensions) { - _impl->_extensions = extensions; - } - - void setOptions(const std::list& options) { - _impl->_options = options; - } - + void setExtensions(const std::multimap& extensions) { + _impl->_extensions = extensions; + } + + void setOptions(const std::list& options) { + _impl->_options = options; + } + protected: boost::shared_ptr _impl; diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in index 6ba6eb1..c26b6b0 100644 --- a/test/ctest/CTestCustom.ctest.in +++ b/test/ctest/CTestCustom.ctest.in @@ -198,43 +198,43 @@ set(CTEST_CUSTOM_TESTS_IGNORE ### Ignore for generated C sources # we do not support invokers yet - "gen/c/ecma/test187.scxml" - "gen/c/ecma/test191.scxml" - "gen/c/ecma/test192.scxml" - "gen/c/ecma/test207.scxml" - "gen/c/ecma/test215.scxml" - "gen/c/ecma/test216.scxml" - "gen/c/ecma/test220.scxml" - "gen/c/ecma/test223.scxml" - "gen/c/ecma/test224.scxml" - "gen/c/ecma/test225.scxml" - "gen/c/ecma/test226.scxml" - "gen/c/ecma/test228.scxml" - "gen/c/ecma/test229.scxml" - "gen/c/ecma/test230.scxml" - "gen/c/ecma/test232.scxml" - "gen/c/ecma/test233.scxml" - "gen/c/ecma/test234.scxml" - "gen/c/ecma/test235.scxml" - "gen/c/ecma/test236.scxml" - "gen/c/ecma/test237.scxml" - "gen/c/ecma/test239.scxml" - "gen/c/ecma/test240.scxml" - "gen/c/ecma/test241.scxml" - "gen/c/ecma/test242.scxml" - "gen/c/ecma/test243.scxml" - "gen/c/ecma/test244.scxml" - "gen/c/ecma/test245.scxml" - "gen/c/ecma/test247.scxml" - "gen/c/ecma/test250.scxml" - "gen/c/ecma/test252.scxml" - "gen/c/ecma/test253.scxml" - "gen/c/ecma/test276.scxml" - "gen/c/ecma/test338.scxml" - "gen/c/ecma/test347.scxml" - "gen/c/ecma/test422.scxml" - "gen/c/ecma/test530.scxml" - "gen/c/ecma/test554.scxml" + # "gen/c/ecma/test187.scxml" + # "gen/c/ecma/test191.scxml" + # "gen/c/ecma/test192.scxml" + # "gen/c/ecma/test207.scxml" + # "gen/c/ecma/test215.scxml" + # "gen/c/ecma/test216.scxml" + # "gen/c/ecma/test220.scxml" + # "gen/c/ecma/test223.scxml" + # "gen/c/ecma/test224.scxml" + # "gen/c/ecma/test225.scxml" + # "gen/c/ecma/test226.scxml" + # "gen/c/ecma/test228.scxml" + # "gen/c/ecma/test229.scxml" + # "gen/c/ecma/test230.scxml" + # "gen/c/ecma/test232.scxml" + # "gen/c/ecma/test233.scxml" + # "gen/c/ecma/test234.scxml" + # "gen/c/ecma/test235.scxml" + # "gen/c/ecma/test236.scxml" + # "gen/c/ecma/test237.scxml" + # "gen/c/ecma/test239.scxml" + # "gen/c/ecma/test240.scxml" + # "gen/c/ecma/test241.scxml" + # "gen/c/ecma/test242.scxml" + # "gen/c/ecma/test243.scxml" + # "gen/c/ecma/test244.scxml" + # "gen/c/ecma/test245.scxml" + # "gen/c/ecma/test247.scxml" + # "gen/c/ecma/test250.scxml" + # "gen/c/ecma/test252.scxml" + # "gen/c/ecma/test253.scxml" + # "gen/c/ecma/test276.scxml" + # "gen/c/ecma/test338.scxml" + # "gen/c/ecma/test347.scxml" + # "gen/c/ecma/test422.scxml" + # "gen/c/ecma/test530.scxml" + # "gen/c/ecma/test554.scxml" # we do not support io processors yet "gen/c/ecma/test201.scxml" diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp index 11bb1c7..1dc95d4 100644 --- a/test/src/test-c-machine.cpp +++ b/test/src/test-c-machine.cpp @@ -24,7 +24,7 @@ #include "uscxml/concurrency/Timer.h" //#include "uscxml/DOMUtils.h" #include "uscxml/Factory.h" -#include "uscxml/InterpreterInfo.h" +//#include "uscxml/Interpreter.h" #include "uscxml/UUID.h" #include "uscxml/concurrency/DelayedEventQueue.h" @@ -34,18 +34,98 @@ # include "uscxml/plugins/DataModel.h" # endif -#define USER_DATA(ctx) ((GenCInterpreterInfo*)(((scxml_ctx*)ctx)->user_data)) +#define USER_DATA(ctx) ((StateMachine*)(((scxml_ctx*)ctx)->user_data)) using namespace uscxml; -typedef struct scxml_foreach_info scxml_foreach_info; -struct scxml_foreach_info { - size_t iterations; - size_t currIteration; -}; - -class GenCInterpreterInfo : public InterpreterInfo { +class StateMachine : public InterpreterInfo { public: + StateMachine(const scxml_machine* machine) : parentMachine(NULL), topMostMachine(NULL) { + init(machine); + allMachines[sessionId] = this; + topMostMachine = this; + currentMachine = allMachines.begin(); + } + + StateMachine(StateMachine* parent, const scxml_machine* machine) { + init(machine); + parentMachine = parent; + topMostMachine = parent->topMostMachine; + } + + void init(const scxml_machine* machine) { + sessionId = UUID::getUUID(); + + // clear and initialize machine context + memset(&ctx, 0, sizeof(scxml_ctx)); + ctx.machine = machine; + ctx.user_data = (void*)this; + + // register callbacks with scxml context + ctx.is_enabled = &isEnabled; + ctx.is_true = &isTrue; + ctx.raise_done_event = &raiseDoneEvent; + ctx.invoke = &invoke; + ctx.exec_content_send = &execContentSend; + ctx.exec_content_raise = &execContentRaise; + ctx.exec_content_cancel = &execContentCancel; + ctx.exec_content_log = &execContentLog; + ctx.exec_content_assign = &execContentAssign; + ctx.exec_content_foreach_init = &execContentForeachInit; + ctx.exec_content_foreach_next = &execContentForeachNext; + ctx.exec_content_foreach_done = &execContentForeachDone; + ctx.dequeue_external = &dequeueExternal; + ctx.dequeue_internal = &dequeueInternal; + ctx.exec_content_init = &execContentInit; + ctx.exec_content_script = &execContentScript; + + name = machine->name; + + delayQueue.start(); + dataModel = Factory::getInstance()->createDataModel(machine->datamodel, this); + } + + virtual ~StateMachine() { + delayQueue.stop(); + } + + bool hasPendingWork() { + return (iq.size() > 0 || + eq.size() > 0 || + ctx.flags & SCXML_CTX_SPONTANEOUS || + ctx.flags == SCXML_CTX_PRISTINE || + memcmp(ctx.config, ctx.invocations, sizeof(ctx.config)) != 0); + } + + bool isDone() { + return ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL; + } + + void reset() { + sessionId = UUID::getUUID(); + iq.clear(); + eq.clear(); + delayQueue.cancelAllEvents(); + + dataModel = Factory::getInstance()->createDataModel(ctx.machine->datamodel, this); + + } + + int step() { + // advance current machine if there are multiple + currentMachine++; + if (currentMachine == allMachines.end()) + currentMachine = allMachines.begin(); + + StateMachine* toRun = currentMachine->second; + if (!toRun->hasPendingWork()) { + return SCXML_ERR_IDLE; + } + + return scxml_step(&toRun->ctx); + } + + // InterpreterInfo NameSpaceInfo getNameSpaceInfo() const { return nsInfo; } @@ -58,524 +138,568 @@ public: const std::map& getIOProcessors() { return ioProcs; } - bool isInState(const std::string& stateId) { - for (int i = 0 ; i < SCXML_NUMBER_STATES; i++) { - if (scxml_states[i].name != NULL && BIT_HAS(i, ctx->config) && stateId == scxml_states[i].name) - return true; - } - return false; + const std::map& getInvokers() { + return invokers; } Arabica::DOM::Document getDocument() const { return document; } - const std::map& getInvokers() { - return invokers; - } - - NameSpaceInfo nsInfo; - std::string name; - std::string sessionId; - std::map ioProcs; - std::map invokers; - Arabica::DOM::Document document; - scxml_ctx* ctx; - DataModel datamodel; - - std::map foreachInfo; - std::deque iq; - std::deque eq; - - DelayedEventQueue delayQueue; - std::map sendIds; - tthread::condition_variable monitor; - tthread::mutex mutex; -}; + bool isInState(const std::string& stateId) { + for (int i = 0 ; i < ctx.machine->nr_states; i++) { + if (ctx.machine->states[i].name != NULL && BIT_HAS(i, ctx.config) && stateId == ctx.machine->states[i].name) + return true; + } + return false; + } -int matches(const char* desc, const char* event) { - const char* dPtr = desc; - const char* ePtr = event; - while(*dPtr != 0) { + // callbacks for scxml context - if (*dPtr == '*' && *ePtr != 0) // something following - return true; - - // descriptor differs from event name - if (*dPtr != *ePtr) { - // move to next descriptor - while(*dPtr != ' ' && *dPtr != 0) { - dPtr++; - } - if (*dPtr == 0) + static int isEnabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) { + Event* event = (Event*)e; + if (event == NULL) { + if (t->event == NULL) { + // spontaneous transition, null event + if (t->condition != NULL) + return isTrue(ctx, t->condition); + return true; + } else { + // spontaneous transition, but real event return false; - dPtr++; - ePtr = event; - } else { - // move both pointers one character - dPtr++; - ePtr++; - + } } - // descriptor is done, return match - if (((*dPtr == 0 || *dPtr == ' ') && (*ePtr == 0 || *ePtr == ' ')) || // exact match, end of string - (*dPtr == ' ' && *ePtr == '.') || (*dPtr == 0 && *ePtr == '.')) // prefix match + // real transition, real event + if (nameMatch(t->event, event->name.c_str())) { + if (t->condition != NULL) + return isTrue(ctx, t->condition); return true; + } + return false; } - return false; -} - -int exec_content_raise(const scxml_ctx* ctx, const char* event) { - Event* e = new Event(); - e->name = event; - if (boost::starts_with(e->name, "error.")) { - e->eventType = Event::PLATFORM; - } else { - e->eventType = Event::INTERNAL; + static int isTrue(const scxml_ctx* ctx, const char* expr) { + try { + return USER_DATA(ctx)->dataModel.evalAsBool(expr); + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + } + return false; } -#ifdef SCXML_VERBOSE - printf("Raising Internal Event: %s\n", e->name.c_str()); -#endif - USER_DATA(ctx)->iq.push_back(e); - return SCXML_ERR_OK; -} - -int is_true(const scxml_ctx* ctx, const char* expr) { - try { - return USER_DATA(ctx)->datamodel.evalAsBool(expr); - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - } - return false; -} + static int invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) { + if (invocation->machine != NULL) { + StateMachine* INSTANCE = USER_DATA(ctx); + // invoke a nested SCXML machine + StateMachine* invokedMachine = new StateMachine(INSTANCE, invocation->machine); + invokedMachine->invocation = invocation; + invokedMachine->invokeId = invocation->id; + assert(invocation->id != NULL); -int is_enabled(const scxml_ctx* ctx, const scxml_transition* t, const void* e) { - Event* event = (Event*)e; - if (event == NULL) { - if (t->event == NULL) { - // spontaneous transition, null event - if (t->condition != NULL) - return is_true(ctx, t->condition); - return true; - } else { - // spontaneous transition, but real event - return false; + INSTANCE->topMostMachine->allMachines[invokedMachine->invokeId] = invokedMachine; } + return SCXML_ERR_UNSUPPORTED; } - // real transition, real event - if (matches(t->event, event->name.c_str())) { - if (t->condition != NULL) - return is_true(ctx, t->condition); - return true; - } - return false; -} - -int raise_done_event(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) { - Event* e = new Event(); - e->name = std::string("done.state.") + state->name; + static int raiseDoneEvent(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata) { + Event* e = new Event(); + e->name = std::string("done.state.") + state->name; - if (donedata) { - if (donedata->content != NULL) { - e->data = Data(donedata->content, Data::VERBATIM); - } else if (donedata->contentexpr != NULL) { - try { - e->data = USER_DATA(ctx)->datamodel.getStringAsData(donedata->contentexpr); - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - } - } else { - try { - const scxml_elem_param* param = donedata->params; - while (param && ELEM_PARAM_IS_SET(param)) { - Data paramValue; - if (param->expr != NULL) { - paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->expr); - } else if(param->location) { - paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->location); + if (donedata) { + if (donedata->content != NULL) { + e->data = Data(donedata->content, Data::VERBATIM); + } else if (donedata->contentexpr != NULL) { + try { + e->data = USER_DATA(ctx)->dataModel.getStringAsData(donedata->contentexpr); + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + } + } else { + try { + const scxml_elem_param* param = donedata->params; + while (param && ELEM_PARAM_IS_SET(param)) { + Data paramValue; + if (param->expr != NULL) { + paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->expr); + } else if(param->location) { + paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->location); + } + e->params.insert(std::make_pair(param->name, paramValue)); + param++; } - e->params.insert(std::make_pair(param->name, paramValue)); - param++; + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); } - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); } } - } - -#ifdef SCXML_VERBOSE - printf("Raising Done Event: %s\n", e->name.c_str()); -#endif - USER_DATA(ctx)->iq.push_back(e); - return SCXML_ERR_OK; -} - -void delayedSend(void* ctx, std::string eventName) { - tthread::lock_guard lock(USER_DATA(ctx)->mutex); - - SendRequest* sr = USER_DATA(ctx)->sendIds[eventName]; - Event* e = new Event(*sr); - if (sr->target == "#_internal") { - e->eventType = Event::INTERNAL; #ifdef SCXML_VERBOSE - printf("Pushing Internal Event: %s\n", e->name.c_str()); + printf("Raising Done Event: %s\n", e->name.c_str()); #endif USER_DATA(ctx)->iq.push_back(e); - } else { - e->eventType = Event::EXTERNAL; -#ifdef SCXML_VERBOSE - printf("Pushing External Event: %s\n", e->name.c_str()); -#endif - USER_DATA(ctx)->eq.push_back(e); + return SCXML_ERR_OK; } - USER_DATA(ctx)->monitor.notify_all(); - delete sr; -} -int exec_content_cancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) { - std::string eventId; - if (sendid != NULL) { - eventId = sendid; - } else if (sendidexpr != NULL) { - eventId = USER_DATA(ctx)->datamodel.evalAsString(sendidexpr); - } + static int execContentSend(const scxml_ctx* ctx, const scxml_elem_send* send) { + SendRequest* e = new SendRequest(); - if (eventId.length() > 0) { - USER_DATA(ctx)->delayQueue.cancelEvent(eventId); - } else { - exec_content_raise(ctx, "error.execution"); - return SCXML_ERR_EXEC_CONTENT; - } - return SCXML_ERR_OK; -} - -std::string spaceNormalize(const std::string& text) { - std::stringstream content; - std::string seperator; - - size_t start = 0; - for (int i = 0; i < text.size(); i++) { - if (isspace(text[i])) { - if (i > 0 && start < i) { - content << seperator << text.substr(start, i - start); - seperator = " "; - } - while(isspace(text[++i])); // skip whitespaces - start = i; - } else if (i + 1 == text.size()) { - content << seperator << text.substr(start, i + 1 - start); + std::string target; + if (send->target != NULL) { + e->target = send->target; + } else if (send->targetexpr != NULL) { + e->target = USER_DATA(ctx)->dataModel.evalAsString(send->targetexpr); + } else { + e->target = "#_external"; } - } - return content.str(); -} + if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) { + delete e; + execContentRaise(ctx, "error.execution"); + return SCXML_ERR_INVALID_TARGET; + } -int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { - SendRequest* e = new SendRequest(); + e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + e->origin = e->target; - std::string target; - if (send->target != NULL) { - e->target = send->target; - } else if (send->targetexpr != NULL) { - e->target = USER_DATA(ctx)->datamodel.evalAsString(send->targetexpr); - } else { - e->target = "#_external"; - } + try { + if (send->type != NULL) { + e->type = send->type; + } else if (send->typeexpr != NULL) { + e->type = USER_DATA(ctx)->dataModel.evalAsString(send->typeexpr); + } else { + e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + } + } catch (Event exc) { + execContentRaise(ctx, exc.name.c_str()); + delete e; + return SCXML_ERR_EXEC_CONTENT; + } - if (e->target.size() > 0 && (e->target[0] != '#' || e->target[1] != '_')) { - delete e; - exec_content_raise(ctx, "error.execution"); - return SCXML_ERR_INVALID_TARGET; - } + // only one somewhat supported + if (e->type != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") { + delete e; + execContentRaise(ctx, "error.execution"); + return SCXML_ERR_INVALID_TARGET; + } - e->origintype = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; - e->origin = e->target; + e->origintype = e->type; - try { - if (send->type != NULL) { - e->type = send->type; - } else if (send->typeexpr != NULL) { - e->type = USER_DATA(ctx)->datamodel.evalAsString(send->typeexpr); + if (send->eventexpr != NULL) { + e->name = USER_DATA(ctx)->dataModel.evalAsString(send->eventexpr); } else { - e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; + e->name = send->event; } - } catch (Event exc) { - exec_content_raise(ctx, exc.name.c_str()); - delete e; - return SCXML_ERR_EXEC_CONTENT; - } - // only one somewhat supported - if (e->type != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") { - delete e; - exec_content_raise(ctx, "error.execution"); - return SCXML_ERR_INVALID_TARGET; - } + try { + const scxml_elem_param* param = send->params; + while (param && ELEM_PARAM_IS_SET(param)) { + Data paramValue; + if (param->expr != NULL) { + paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->expr); + } else if(param->location) { + paramValue = USER_DATA(ctx)->dataModel.getStringAsData(param->location); + } + e->params.insert(std::make_pair(param->name, paramValue)); + param++; + } + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; + } - e->origintype = e->type; + try { + if (send->namelist != NULL) { + const char* bPtr = &send->namelist[0]; + const char* ePtr = bPtr; + while(*ePtr != '\0') { + ePtr++; + if (*ePtr == ' ' || *ePtr == '\0') { + std::string key(bPtr, ePtr - bPtr); + e->params.insert(std::make_pair(key, USER_DATA(ctx)->dataModel.getStringAsData(key))); + if (*ePtr == '\0') + break; + bPtr = ++ePtr; + } + } + } + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; + } - if (send->eventexpr != NULL) { - e->name = USER_DATA(ctx)->datamodel.evalAsString(send->eventexpr); - } else { - e->name = send->event; - } + if (send->content != NULL) { + // will it parse as json? + Data d = Data::fromJSON(send->content); + if (!d.empty()) { + e->data = d; + } else { + e->data = Data(spaceNormalize(send->content), Data::VERBATIM); + } + } - try { - const scxml_elem_param* param = send->params; - while (param && ELEM_PARAM_IS_SET(param)) { - Data paramValue; - if (param->expr != NULL) { - paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->expr); - } else if(param->location) { - paramValue = USER_DATA(ctx)->datamodel.getStringAsData(param->location); + std::string sendid; + if (send->id != NULL) { + sendid = send->id; + e->sendid = sendid; + } else { + sendid = UUID::getUUID(); + if (send->idlocation != NULL) { + USER_DATA(ctx)->dataModel.assign(send->idlocation, Data(sendid, Data::VERBATIM)); + } else { + e->hideSendId = true; } - e->params.insert(std::make_pair(param->name, paramValue)); - param++; - } - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - return SCXML_ERR_EXEC_CONTENT; - } - - try { - if (send->namelist != NULL) { - const char* bPtr = &send->namelist[0]; - const char* ePtr = bPtr; - while(*ePtr != '\0') { - ePtr++; - if (*ePtr == ' ' || *ePtr == '\0') { - std::string key(bPtr, ePtr - bPtr); - e->params.insert(std::make_pair(key, USER_DATA(ctx)->datamodel.getStringAsData(key))); - if (*ePtr == '\0') - break; - bPtr = ++ePtr; - } + } + + size_t delayMs = 0; + std::string delay; + if (send->delayexpr != NULL) { + delay = USER_DATA(ctx)->dataModel.evalAsString(send->delayexpr); + } else if (send->delay != NULL) { + delay = send->delay; + } + if (delay.size() > 0) { + boost::trim(delay); + + NumAttr delayAttr(delay); + if (iequals(delayAttr.unit, "ms")) { + delayMs = strTo(delayAttr.value); + } else if (iequals(delayAttr.unit, "s")) { + delayMs = strTo(delayAttr.value) * 1000; + } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds + delayMs = strTo(delayAttr.value); + } else { + std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'"; } } - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - return SCXML_ERR_EXEC_CONTENT; - } - if (send->content != NULL) { - // will it parse as json? - Data d = Data::fromJSON(send->content); - if (!d.empty()) { - e->data = d; - } else { - e->data = Data(spaceNormalize(send->content), Data::VERBATIM); + if (USER_DATA(ctx)->invokeId.size() > 0) { + e->invokeid = USER_DATA(ctx)->invokeId; } - } - std::string sendid; - if (send->id != NULL) { - sendid = send->id; - e->sendid = sendid; - } else { - sendid = UUID::getUUID(); - if (send->idlocation != NULL) { - USER_DATA(ctx)->datamodel.assign(send->idlocation, Data(sendid, Data::VERBATIM)); + USER_DATA(ctx)->sendIds[sendid] = e; + if (delayMs > 0) { + USER_DATA(ctx)->delayQueue.addEvent(sendid, delayedSend, delayMs, (void*)ctx); } else { - e->hideSendId = true; + delayedSend((void*)ctx, sendid); } + + return SCXML_ERR_OK; } + static int execContentRaise(const scxml_ctx* ctx, const char* event) { + Event* e = new Event(); + e->name = event; - size_t delayMs = 0; - std::string delay; - if (send->delayexpr != NULL) { - delay = USER_DATA(ctx)->datamodel.evalAsString(send->delayexpr); - } else if (send->delay != NULL) { - delay = send->delay; + if (boost::starts_with(e->name, "error.")) { + e->eventType = Event::PLATFORM; + } else { + e->eventType = Event::INTERNAL; + } + USER_DATA(ctx)->iq.push_back(e); + return SCXML_ERR_OK; } - if (delay.size() > 0) { - boost::trim(delay); - NumAttr delayAttr(delay); - if (iequals(delayAttr.unit, "ms")) { - delayMs = strTo(delayAttr.value); - } else if (iequals(delayAttr.unit, "s")) { - delayMs = strTo(delayAttr.value) * 1000; - } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds - delayMs = strTo(delayAttr.value); + static int execContentCancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) { + std::string eventId; + if (sendid != NULL) { + eventId = sendid; + } else if (sendidexpr != NULL) { + eventId = USER_DATA(ctx)->dataModel.evalAsString(sendidexpr); + } + + if (eventId.length() > 0) { + USER_DATA(ctx)->delayQueue.cancelEvent(eventId); } else { - std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'"; + execContentRaise(ctx, "error.execution"); + return SCXML_ERR_EXEC_CONTENT; } + return SCXML_ERR_OK; } - USER_DATA(ctx)->sendIds[sendid] = e; - if (delayMs > 0) { - USER_DATA(ctx)->delayQueue.addEvent(sendid, delayedSend, delayMs, (void*)ctx); - } else { - delayedSend((void*)ctx, sendid); + static int execContentLog(const scxml_ctx* ctx, const char* label, const char* expr) { + try { + if (label != NULL) { + printf("%s%s", label, (expr != NULL ? ": " : "")); + } + if (expr != NULL) { + std::string msg = USER_DATA(ctx)->dataModel.evalAsString(expr); + printf("%s", msg.c_str()); + } + if (label != NULL || expr != NULL) { + printf("\n"); + } + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; + } + return SCXML_ERR_OK; } - return SCXML_ERR_OK; -} - -int exec_content_init(const scxml_ctx* ctx, const scxml_elem_data* data) { - while(ELEM_DATA_IS_SET(data)) { - Data d; - if (data->expr != NULL) { - d = Data(data->expr, Data::INTERPRETED); - } else if (data->content != NULL) { - d = Data(data->content, Data::INTERPRETED); - } else { - d = Data("undefined", Data::INTERPRETED); + static int execContentAssign(const scxml_ctx* ctx, const char* location, const char* expr) { + std::string key = location; + if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") { + execContentRaise(ctx, "error.execution"); + return SCXML_ERR_EXEC_CONTENT; } + try { - USER_DATA(ctx)->datamodel.init(data->id, d); + Data d(expr, Data::INTERPRETED); + USER_DATA(ctx)->dataModel.assign(key, d); } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); + execContentRaise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; } - data++; + return SCXML_ERR_OK; } - return SCXML_ERR_OK; -} -int exec_content_assign(const scxml_ctx* ctx, const char* location, const char* expr) { - std::string key = location; - if (key == "_sessionid" || key == "_name" || key == "_ioprocessors" || key == "_invokers" || key == "_event") { - exec_content_raise(ctx, "error.execution"); - return SCXML_ERR_EXEC_CONTENT; - } + static int execContentForeachInit(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) { + try { + scxml_foreach_info* feInfo = (scxml_foreach_info*)malloc(sizeof(scxml_foreach_info)); + USER_DATA(ctx)->foreachInfo[foreach] = feInfo; - try { - Data d(expr, Data::INTERPRETED); - USER_DATA(ctx)->datamodel.assign(key, d); - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - return SCXML_ERR_EXEC_CONTENT; + feInfo->iterations = USER_DATA(ctx)->dataModel.getLength(foreach->array); + feInfo->currIteration = 0; + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + return SCXML_ERR_EXEC_CONTENT; + } + return SCXML_ERR_OK; } - return SCXML_ERR_OK; -} -int exec_content_foreach_init(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) { - try { - scxml_foreach_info* feInfo = (scxml_foreach_info*)malloc(sizeof(scxml_foreach_info)); - USER_DATA(ctx)->foreachInfo[foreach] = feInfo; - - feInfo->iterations = USER_DATA(ctx)->datamodel.getLength(foreach->array); - feInfo->currIteration = 0; - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - return SCXML_ERR_EXEC_CONTENT; + static int execContentForeachNext(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) { + try { + scxml_foreach_info* feInfo = USER_DATA(ctx)->foreachInfo[foreach]; + if (feInfo->currIteration < feInfo->iterations) { + USER_DATA(ctx)->dataModel.setForeach((foreach->item != NULL ? foreach->item : ""), + (foreach->array != NULL ? foreach->array : ""), + (foreach->index != NULL ? foreach->index : ""), + feInfo->currIteration); + feInfo->currIteration++; + return SCXML_ERR_OK; + } + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + free(USER_DATA(ctx)->foreachInfo[foreach]); + USER_DATA(ctx)->foreachInfo.erase(foreach); + return SCXML_ERR_EXEC_CONTENT; + } + return SCXML_ERR_FOREACH_DONE; } - return SCXML_ERR_OK; -} -int exec_content_foreach_next(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) { - try { - scxml_foreach_info* feInfo = USER_DATA(ctx)->foreachInfo[foreach]; - if (feInfo->currIteration < feInfo->iterations) { - USER_DATA(ctx)->datamodel.setForeach((foreach->item != NULL ? foreach->item : ""), - (foreach->array != NULL ? foreach->array : ""), - (foreach->index != NULL ? foreach->index : ""), - feInfo->currIteration); - feInfo->currIteration++; - return SCXML_ERR_OK; - } - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); + static int execContentForeachDone(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) { free(USER_DATA(ctx)->foreachInfo[foreach]); USER_DATA(ctx)->foreachInfo.erase(foreach); - return SCXML_ERR_EXEC_CONTENT; + return SCXML_ERR_OK; + } + + static int execContentInit(const scxml_ctx* ctx, const scxml_elem_data* data) { + while(ELEM_DATA_IS_SET(data)) { + Data d; + if (data->expr != NULL) { + d = Data(data->expr, Data::INTERPRETED); + } else if (data->content != NULL) { + d = Data(data->content, Data::INTERPRETED); + } else { + d = Data("undefined", Data::INTERPRETED); + } + try { + USER_DATA(ctx)->dataModel.init(data->id, d); + } catch (Event e) { + execContentRaise(ctx, e.name.c_str()); + } + data++; + } + return SCXML_ERR_OK; } - return SCXML_ERR_FOREACH_DONE; -} -int exec_content_foreach_done(const scxml_ctx* ctx, const scxml_elem_foreach* foreach) { - free(USER_DATA(ctx)->foreachInfo[foreach]); - USER_DATA(ctx)->foreachInfo.erase(foreach); - return SCXML_ERR_OK; -} - -int exec_content_log(const scxml_ctx* ctx, const char* label, const char* expr) { - try { - if (label != NULL) { - printf("%s%s", label, (expr != NULL ? ": " : "")); - } - if (expr != NULL) { - std::string msg = USER_DATA(ctx)->datamodel.evalAsString(expr); - printf("%s", msg.c_str()); + static int execContentScript(const scxml_ctx* ctx, const char* src, const char* content) { + if (content != NULL) { + USER_DATA(ctx)->dataModel.eval(Arabica::DOM::Element(), content); + } else if (src != NULL) { + return SCXML_ERR_UNSUPPORTED; } - if (label != NULL || expr != NULL) { - printf("\n"); - } - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); - return SCXML_ERR_EXEC_CONTENT; + return SCXML_ERR_OK; } - return SCXML_ERR_OK; -} -int exec_content_script(const scxml_ctx* ctx, const char* src, const char* content) { - if (content != NULL) { - USER_DATA(ctx)->datamodel.eval(Arabica::DOM::Element(), content); - } else if (src != NULL) { - return SCXML_ERR_UNSUPPORTED; - } - return SCXML_ERR_OK; -} + static void* dequeueExternal(const scxml_ctx* ctx) { + tthread::lock_guard lock(USER_DATA(ctx)->mutex); + if (USER_DATA(ctx)->eq.size() == 0) + return NULL; + + Event* e = USER_DATA(ctx)->eq.front(); + USER_DATA(ctx)->eq.pop_front(); + USER_DATA(ctx)->dataModel.setEvent(*e); -void* dequeue_external(const scxml_ctx* ctx) { - tthread::lock_guard lock(USER_DATA(ctx)->mutex); - while (USER_DATA(ctx)->eq.size() == 0) { - USER_DATA(ctx)->monitor.wait(USER_DATA(ctx)->mutex); + if (e->invokeid.size() > 0) { + // we need to check for finalize content + StateMachine* invokedMachine = USER_DATA(ctx)->allMachines[e->invokeid]; + if (invokedMachine->invocation->finalize != NULL) + invokedMachine->invocation->finalize(ctx, + invokedMachine->invocation, + e); + } + +#ifdef SCXML_VERBOSE + printf("Popping External Event: %s\n", e->name.c_str()); +#endif + return e; } - Event* e = USER_DATA(ctx)->eq.front(); - USER_DATA(ctx)->eq.pop_front(); - USER_DATA(ctx)->datamodel.setEvent(*e); + + static void* dequeueInternal(const scxml_ctx* ctx) { + if (USER_DATA(ctx)->iq.size() == 0) + return NULL; + Event* e = USER_DATA(ctx)->iq.front(); + USER_DATA(ctx)->iq.pop_front(); + USER_DATA(ctx)->dataModel.setEvent(*e); #ifdef SCXML_VERBOSE - printf("Popping External Event: %s\n", e->name.c_str()); + printf("Popping Internal Event: %s\n", e->name.c_str()); #endif - return e; -} + return e; + } + + static void delayedSend(void* ctx, std::string eventName) { + tthread::lock_guard lock(USER_DATA(ctx)->mutex); + + SendRequest* sr = USER_DATA(ctx)->sendIds[eventName]; + Event* e = new Event(*sr); -void* dequeue_internal(const scxml_ctx* ctx) { - if (USER_DATA(ctx)->iq.size() == 0) - return NULL; - Event* e = USER_DATA(ctx)->iq.front(); - USER_DATA(ctx)->iq.pop_front(); - USER_DATA(ctx)->datamodel.setEvent(*e); + if (sr->target == "#_internal") { + e->eventType = Event::INTERNAL; #ifdef SCXML_VERBOSE - printf("Popping Internal Event: %s\n", e->name.c_str()); + printf("Pushing Internal Event: %s\n", e->name.c_str()); #endif - return e; -} + USER_DATA(ctx)->iq.push_back(e); + } else if (sr->target == "#_parent") { + e->eventType = Event::EXTERNAL; + if (USER_DATA(ctx)->parentMachine != NULL) { + USER_DATA(ctx)->parentMachine->eq.push_back(e); + } + // TODO: handle invalid parent + } else { + e->eventType = Event::EXTERNAL; +#ifdef SCXML_VERBOSE + printf("Pushing External Event: %s\n", e->name.c_str()); +#endif + USER_DATA(ctx)->eq.push_back(e); + } + USER_DATA(ctx)->monitor.notify_all(); + delete sr; + } -int main(int argc, char** argv) { + static std::string spaceNormalize(const std::string& text) { + std::stringstream content; + std::string seperator; - std::cout << "sizeof(scxml_state): " << sizeof(scxml_state) << std::endl; - std::cout << "sizeof(scxml_transition): " << sizeof(scxml_transition) << std::endl; - std::cout << "sizeof(scxml_ctx): " << sizeof(scxml_ctx) << std::endl; + size_t start = 0; + for (int i = 0; i < text.size(); i++) { + if (isspace(text[i])) { + if (i > 0 && start < i) { + content << seperator << text.substr(start, i - start); + seperator = " "; + } + while(isspace(text[++i])); // skip whitespaces + start = i; + } else if (i + 1 == text.size()) { + content << seperator << text.substr(start, i + 1 - start); + } + } + return content.str(); + } -#ifdef APPLE - mach_timebase_info_data_t timebase_info; - mach_timebase_info(&timebase_info); - - const uint64_t NANOS_PER_MSEC = 1000000ULL; - double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC; - - thread_time_constraint_policy_data_t policy; - policy.period = 0; - policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work - policy.constraint = (uint32_t)(10 * clock2abs); - policy.preemptible = FALSE; - - int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()), - THREAD_TIME_CONSTRAINT_POLICY, - (thread_policy_t)&policy, - THREAD_TIME_CONSTRAINT_POLICY_COUNT); - if (kr != KERN_SUCCESS) { - mach_error("thread_policy_set:", kr); - exit(1); + // TODO: isolate InterpreterImpl to reduce header deps on libxml/parser.h + static bool nameMatch(const std::string& eventDescs, const std::string& eventName) { + if(eventDescs.length() == 0 || eventName.length() == 0) + return false; + + // naive case of single descriptor and exact match + if (iequals(eventDescs, eventName)) + return true; + + size_t start = 0; + std::string eventDesc; + for (int i = 0; i < eventDescs.size(); i++) { + if (isspace(eventDescs[i])) { + if (i > 0 && start < i - 1) { + eventDesc = eventDescs.substr(start, i - start); + } + while(isspace(eventDescs[++i])); // skip whitespaces + start = i; + } else if (i + 1 == eventDescs.size()) { + eventDesc = eventDescs.substr(start, i + 1 - start); + } + + if (eventDesc.size() > 0) { + // remove optional trailing .* for CCXML compatibility + if (eventDesc.find("*", eventDesc.size() - 1) != std::string::npos) + eventDesc = eventDesc.substr(0, eventDesc.size() - 1); + if (eventDesc.find(".", eventDesc.size() - 1) != std::string::npos) + eventDesc = eventDesc.substr(0, eventDesc.size() - 1); + + // was eventDesc the * wildcard + if (eventDesc.size() == 0) + return true; + + // eventDesc has to be a real prefix of event now and therefore shorter + if (eventDesc.size() > eventName.size()) + goto NEXT_DESC; + + // are they already equal? + if (iequals(eventDesc, eventName)) + return true; + + if (eventName.find(eventDesc) == 0) { + if (eventName.find(".", eventDesc.size()) == eventDesc.size()) + return true; + } +NEXT_DESC: + eventDesc = ""; + } + } + return false; } -#endif + + std::map allMachines; + + StateMachine* parentMachine; + StateMachine* topMostMachine; + std::map::iterator currentMachine; // next machine to advance + + int state; + scxml_ctx ctx; + + std::string sessionId; + std::string name; + + // in case we were invoked + std::string invokeId; + const scxml_elem_invoke* invocation; + + std::deque iq; + std::deque eq; + + DataModel dataModel; + +protected: + struct scxml_foreach_info { + size_t iterations; + size_t currIteration; + }; + + NameSpaceInfo nsInfo; + std::map ioProcs; + std::map invokers; + Arabica::DOM::Document document; + + DelayedEventQueue delayQueue; + std::map sendIds; + std::map foreachInfo; + + tthread::condition_variable monitor; + tthread::mutex mutex; +}; + + +int main(int argc, char** argv) { int err; size_t benchmarkRuns = 1; @@ -584,90 +708,56 @@ int main(int argc, char** argv) { benchmarkRuns = strTo(envBenchmarkRuns); } - size_t remainingRuns = benchmarkRuns; - // setup info object required for datamodel - GenCInterpreterInfo interpreterInfo; - interpreterInfo.name = SCXML_MACHINE_NAME; - interpreterInfo.sessionId = "rfwef"; - interpreterInfo.delayQueue.start(); - - scxml_ctx ctx; - interpreterInfo.ctx = &ctx; - double avg = 0; size_t microSteps = 0; #ifdef BUILD_PROFILING double avgDm = 0; #endif + StateMachine rootMachine(&scxml_machines[0]); + Timer tTotal; tTotal.start(); while(remainingRuns-- > 0) { - memset(&ctx, 0, sizeof(scxml_ctx)); - - // fresh dm (expensive :( ) - interpreterInfo.datamodel = Factory::getInstance()->createDataModel("ecmascript", &interpreterInfo); - - // set info object as user data - ctx.user_data = (void*)&interpreterInfo; - - // register callbacks with scxml context - ctx.is_enabled = &is_enabled; - ctx.is_true = &is_true; - ctx.raise_done_event = &raise_done_event; - - ctx.exec_content_send = &exec_content_send; - ctx.exec_content_raise = &exec_content_raise; - ctx.exec_content_cancel = &exec_content_cancel; - ctx.exec_content_log = &exec_content_log; - ctx.exec_content_assign = &exec_content_assign; - ctx.exec_content_foreach_init = &exec_content_foreach_init; - ctx.exec_content_foreach_next = &exec_content_foreach_next; - ctx.exec_content_foreach_done = &exec_content_foreach_done; - ctx.dequeue_external = &dequeue_external; - ctx.dequeue_internal = &dequeue_internal; - ctx.exec_content_init = &exec_content_init; - ctx.exec_content_script = &exec_content_script; Timer t; t.start(); - microSteps = 0; - while((err = scxml_step(&ctx)) == SCXML_ERR_OK) { + + + for (;;) { + err = rootMachine.step(); + if (rootMachine.isDone()) + break; t.stop(); microSteps++; - if (ctx.event != NULL) { - delete ((Event*)(ctx.event)); - } + t.start(); } microSteps++; - assert(ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL); - + assert(rootMachine.ctx.flags & SCXML_CTX_TOP_LEVEL_FINAL); t.stop(); + avg += t.elapsed; #ifdef BUILD_PROFILING - avgDm += interpreterInfo.datamodel.timer.elapsed; - interpreterInfo.datamodel.timer.elapsed = 0; + avgDm += rootMachine.dataModel.timer.elapsed; + rootMachine.dataModel.timer.elapsed = 0; #endif size_t passIdx = 0; - for (int i = 0; i < SCXML_NUMBER_STATES; i++) { - if (scxml_states[i].name && strcmp(scxml_states[i].name, "pass") == 0) { + for (int i = 0; i < rootMachine.ctx.machine->nr_states; i++) { + if (rootMachine.ctx.machine->states[i].name && strcmp(rootMachine.ctx.machine->states[i].name, "pass") == 0) { passIdx = i; break; } } - if(!BIT_HAS(passIdx, ctx.config)) { + if(!BIT_HAS(passIdx, rootMachine.ctx.config)) { std::cerr << "Interpreter did not end in pass" << std::endl; exit(EXIT_FAILURE); } - interpreterInfo.delayQueue.cancelAllEvents(); - interpreterInfo.eq.clear(); - interpreterInfo.iq.clear(); } tTotal.stop(); std::cout << benchmarkRuns << " iterations" << std::endl; @@ -676,10 +766,9 @@ int main(int argc, char** argv) { std::cout << microSteps << " microsteps per iteration" << std::endl; std::cout << (avg * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep" << std::endl; #ifdef BUILD_PROFILING - std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in datamodel" << std::endl; - std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo datamodel" << std::endl; + std::cout << (avgDm * 1000.0) / (double)benchmarkRuns << " ms in dataModel" << std::endl; + std::cout << ((avg - avgDm) * 1000.0) / ((double)benchmarkRuns * (double)microSteps) << " ms per microstep \\wo dataModel" << std::endl; #endif - interpreterInfo.delayQueue.stop(); tthread::this_thread::sleep_for(tthread::chrono::milliseconds(100)); return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/test/src/test-c-machine.machine.c b/test/src/test-c-machine.machine.c index ebacc5f..a69b7c7 100644 --- a/test/src/test-c-machine.machine.c +++ b/test/src/test-c-machine.machine.c @@ -13,6 +13,22 @@ #define unlikely(x) (x) #endif +#ifndef SCXML_NR_STATES_TYPE +# define SCXML_NR_STATES_TYPE uint8_t +#endif + +#ifndef SCXML_NR_TRANS_TYPE +# define SCXML_NR_TRANS_TYPE uint8_t +#endif + +#ifndef SCXML_MAX_NR_STATES_BYTES +# define SCXML_MAX_NR_STATES_BYTES 1 +#endif + +#ifndef SCXML_MAX_NR_TRANS_BYTES +# define SCXML_MAX_NR_TRANS_BYTES 1 +#endif + // error return codes #define SCXML_ERR_OK 0 #define SCXML_ERR_IDLE 1 @@ -24,9 +40,8 @@ #define SCXML_ERR_INVALID_TYPE 7 #define SCXML_ERR_UNSUPPORTED 8 -#define SCXML_MACHINE_NAME "" -#define SCXML_NUMBER_STATES 9 -#define SCXML_NUMBER_TRANSITIONS 6 +#define SCXML_NUMBER_STATES (ctx->machine->nr_states) +#define SCXML_NUMBER_TRANS (ctx->machine->nr_transitions) #define SCXML_TRANS_SPONTANEOUS 0x01 #define SCXML_TRANS_TARGETLESS 0x02 @@ -53,12 +68,14 @@ #define ELEM_DATA_IS_SET(data) (data->id != NULL) #define ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL) #define ELEM_PARAM_IS_SET(param) (param->name != NULL) +#define SCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0) +typedef struct scxml_machine scxml_machine; typedef struct scxml_transition scxml_transition; typedef struct scxml_state scxml_state; typedef struct scxml_ctx scxml_ctx; -typedef struct scxml_invoke scxml_invoke; +typedef struct scxml_elem_invoke scxml_elem_invoke; typedef struct scxml_elem_send scxml_elem_send; typedef struct scxml_elem_param scxml_elem_param; @@ -72,7 +89,7 @@ typedef int (*is_enabled_t)(const scxml_ctx* ctx, const scxml_transition* transi typedef int (*is_true_t)(const scxml_ctx* ctx, const char* expr); typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event); typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata); -typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x); +typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke); typedef int (*exec_content_log_t)(const scxml_ctx* ctx, const char* label, const char* expr); typedef int (*exec_content_raise_t)(const scxml_ctx* ctx, const char* event); @@ -83,9 +100,26 @@ typedef int (*exec_content_foreach_done_t)(const scxml_ctx* ctx, const scxml_ele typedef int (*exec_content_assign_t)(const scxml_ctx* ctx, const char* location, const char* expr); typedef int (*exec_content_init_t)(const scxml_ctx* ctx, const scxml_elem_data* data); typedef int (*exec_content_cancel_t)(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr); -typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_invoke* invoker, const void* event); +typedef int (*exec_content_finalize_t)(const scxml_ctx* ctx, const scxml_elem_invoke* invoker, const void* event); typedef int (*exec_content_script_t)(const scxml_ctx* ctx, const char* src, const char* content); +struct scxml_machine { + uint8_t flags; + SCXML_NR_STATES_TYPE nr_states; + SCXML_NR_TRANS_TYPE nr_transitions; + const char* name; + const char* datamodel; + const char* uuid; + const scxml_state* states; + const scxml_transition* transitions; + const scxml_machine* parent; + const scxml_elem_donedata* donedata; + const exec_content_t script; +}; + +// forward declare machines to allow references +extern const scxml_machine scxml_machines[3]; + struct scxml_elem_data { const char* id; const char* src; @@ -99,22 +133,22 @@ struct scxml_state { const exec_content_t on_entry; // on entry handlers const exec_content_t on_exit; // on exit handlers const invoke_t invoke; // invocations - const char children[2]; // all children - const char completion[2]; // default completion - const char ancestors[2]; // all ancestors + const char children[SCXML_MAX_NR_STATES_BYTES]; // all children + const char completion[SCXML_MAX_NR_STATES_BYTES]; // default completion + const char ancestors[SCXML_MAX_NR_STATES_BYTES]; // all ancestors const scxml_elem_data* data; const uint8_t type; // atomic, parallel, compound, final, history }; struct scxml_transition { const uint8_t source; - const char target[2]; + const char target[SCXML_MAX_NR_STATES_BYTES]; const char* event; const char* condition; const exec_content_t on_transition; const uint8_t type; - const char conflicts[1]; - const char exit_set[2]; + const char conflicts[SCXML_MAX_NR_TRANS_BYTES]; + const char exit_set[SCXML_MAX_NR_STATES_BYTES]; }; struct scxml_elem_foreach { @@ -137,6 +171,7 @@ struct scxml_elem_donedata { }; struct scxml_elem_invoke { + const scxml_machine* machine; const char* type; const char* typeexpr; const char* src; @@ -146,7 +181,7 @@ struct scxml_elem_invoke { const char* namelist; const uint8_t autoforward; const scxml_elem_param* params; - const exec_content_finalize_t* finalize; + exec_content_finalize_t finalize; const char* content; const char* contentexpr; }; @@ -169,12 +204,13 @@ struct scxml_elem_send { }; struct scxml_ctx { - uint8_t flags; + uint8_t flags; + const scxml_machine* machine; - char config[2]; - char history[2]; - char pending_invokes[2]; - char initialized_data[2]; + char config[SCXML_MAX_NR_STATES_BYTES]; + char history[SCXML_MAX_NR_STATES_BYTES]; + char invocations[SCXML_MAX_NR_STATES_BYTES]; + char initialized_data[SCXML_MAX_NR_STATES_BYTES]; void* user_data; void* event; @@ -198,30 +234,107 @@ struct scxml_ctx { invoke_t invoke; }; -static const scxml_elem_data scxml_elem_datas[2] = { +static const scxml_elem_data _scxml_6A932FF1_elem_datas[2] = { /* id, src, expr, content */ - { "Var1", NULL, "0", NULL }, + { "Var1", NULL, "1", NULL }, { NULL, NULL, NULL, NULL } }; -static const scxml_elem_param scxml_elem_params[2] = { +static const scxml_elem_param _scxml_6A932FF1_elem_params[2] = { /* name, expr, location */ - { "Var1", "1", NULL }, + { "aParam", "2", NULL }, { NULL, NULL, NULL } }; -static const scxml_elem_donedata scxml_elem_donedatas[3] = { +static const scxml_elem_send _scxml_6A932FF1_elem_sends[2] = { + { + /* event */ "timeout", + /* eventexpr */ NULL, + /* target */ NULL, + /* targetexpr */ NULL, + /* type */ NULL, + /* typeexpr */ NULL, + /* id */ NULL, + /* idlocation */ NULL, + /* delay */ "300s", + /* delayexpr */ NULL, + /* namelist */ NULL, + /* content */ NULL, + /* contentexpr */ NULL, + /* params */ NULL + }, + { + /* event */ "childToParent", + /* eventexpr */ NULL, + /* target */ "#_parent", + /* targetexpr */ NULL, + /* type */ NULL, + /* typeexpr */ NULL, + /* id */ NULL, + /* idlocation */ NULL, + /* delay */ NULL, + /* delayexpr */ NULL, + /* namelist */ NULL, + /* content */ NULL, + /* contentexpr */ NULL, + /* params */ &_scxml_6A932FF1_elem_params[0] + } +}; + +static const scxml_elem_donedata _scxml_6A932FF1_elem_donedatas[1] = { /* source, content, contentexpr, params */ - { 3, NULL, NULL, &scxml_elem_params[0] }, - { 6, "foo", NULL, NULL }, { 0, NULL, NULL, NULL } }; -static int global_script(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_6A932FF1_s0_invoke0_finalize0(const scxml_ctx* ctx, const scxml_elem_invoke* invocation, const void* event) { + int err = SCXML_ERR_OK; + if likely(ctx->exec_content_assign != NULL) { + if ((ctx->exec_content_assign(ctx, "Var1", "_event.data.aParam")) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static const scxml_elem_invoke _scxml_6A932FF1_elem_invokes[1] = { + { + /* machine */ &scxml_machines[1], + /* type */ "http://www.w3.org/TR/scxml/", + /* typeexpr */ NULL, + /* src */ NULL, + /* srcexpr */ NULL, + /* id */ "d2170d67-da91-4aba-99a1-b1c021513e75", + /* idlocation */ NULL, + /* namelist */ NULL, + /* autoforward */ 0, + /* params */ NULL, + /* finalize */ _scxml_6A932FF1_s0_invoke0_finalize0, + /* content */ NULL, + /* contentexpr */ NULL, + } +}; + +static int _scxml_6A932FF1_s0_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + int err = SCXML_ERR_OK; + if likely(ctx->exec_content_send != NULL) { + if ((ctx->exec_content_send(ctx, &_scxml_6A932FF1_elem_sends[0])) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static int _scxml_6A932FF1_s0_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_6A932FF1_s0_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_6A932FF1_s0_invoke(const scxml_ctx* ctx, const scxml_state* s, const scxml_elem_invoke* invocation, uint8_t uninvoke) { + ctx->invoke(ctx, s, &_scxml_6A932FF1_elem_invokes[0], uninvoke); + + return SCXML_ERR_OK; +} +static int _scxml_6A932FF1_pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { int err = SCXML_ERR_OK; if likely(ctx->exec_content_log != NULL) { if unlikely((ctx->exec_content_log(ctx, "Outcome", "'pass'")) != SCXML_ERR_OK) return err; @@ -231,12 +344,12 @@ static int pass_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const return SCXML_ERR_OK; } -static int pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { - pass_on_entry_0(ctx, state, event); +static int _scxml_6A932FF1_pass_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_6A932FF1_pass_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { +static int _scxml_6A932FF1_fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { int err = SCXML_ERR_OK; if likely(ctx->exec_content_log != NULL) { if unlikely((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != SCXML_ERR_OK) return err; @@ -246,204 +359,201 @@ static int fail_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const return SCXML_ERR_OK; } -static int fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { - fail_on_entry_0(ctx, state, event); +static int _scxml_6A932FF1_fail_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_6A932FF1_fail_on_entry_0(ctx, state, event); return SCXML_ERR_OK; } -static const scxml_state scxml_states[9] = { +static const scxml_state _scxml_6A932FF1_states[4] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, /* onentry */ NULL, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x92, 0x01 /* 010010011, 1 4 7 8 */ }, - /* completion */ { 0x02, 0x00 /* 010000000, 1 */ }, - /* ancestors */ { 0x00, 0x00 /* 000000000, */ }, - /* data */ &scxml_elem_datas[0], + /* children */ { 0x0e /* 0111 */ }, + /* completion */ { 0x02 /* 0100 */ }, + /* ancestors */ { 0x00 /* 0000 */ }, + /* data */ &_scxml_6A932FF1_elem_datas[0], /* type */ SCXML_STATE_COMPOUND, }, { /* state number 1 */ /* name */ "s0", /* parent */ 0, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x0c, 0x00 /* 001100000, 2 3 */ }, - /* completion */ { 0x04, 0x00 /* 001000000, 2 */ }, - /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_COMPOUND, - }, - { /* state number 2 */ - /* name */ "s01", - /* parent */ 1, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x00, 0x00 /* 000000000, */ }, - /* completion */ { 0x00, 0x00 /* 000000000, */ }, - /* ancestors */ { 0x03, 0x00 /* 110000000, 0 1 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_ATOMIC, - }, - { /* state number 3 */ - /* name */ "s02", - /* parent */ 1, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x00, 0x00 /* 000000000, */ }, - /* completion */ { 0x00, 0x00 /* 000000000, */ }, - /* ancestors */ { 0x03, 0x00 /* 110000000, 0 1 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_FINAL, - }, - { /* state number 4 */ - /* name */ "s1", - /* parent */ 0, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x60, 0x00 /* 000001100, 5 6 */ }, - /* completion */ { 0x20, 0x00 /* 000001000, 5 */ }, - /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_COMPOUND, - }, - { /* state number 5 */ - /* name */ "s11", - /* parent */ 4, - /* onentry */ NULL, + /* onentry */ _scxml_6A932FF1_s0_on_entry, /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x00, 0x00 /* 000000000, */ }, - /* completion */ { 0x00, 0x00 /* 000000000, */ }, - /* ancestors */ { 0x11, 0x00 /* 100010000, 0 4 */ }, + /* invoke */ _scxml_6A932FF1_s0_invoke, + /* children */ { 0x00 /* 0000 */ }, + /* completion */ { 0x00 /* 0000 */ }, + /* ancestors */ { 0x01 /* 1000 */ }, /* data */ NULL, /* type */ SCXML_STATE_ATOMIC, }, - { /* state number 6 */ - /* name */ "s12", - /* parent */ 4, - /* onentry */ NULL, - /* onexit */ NULL, - /* invoke */ NULL, - /* children */ { 0x00, 0x00 /* 000000000, */ }, - /* completion */ { 0x00, 0x00 /* 000000000, */ }, - /* ancestors */ { 0x11, 0x00 /* 100010000, 0 4 */ }, - /* data */ NULL, - /* type */ SCXML_STATE_FINAL, - }, - { /* state number 7 */ + { /* state number 2 */ /* name */ "pass", /* parent */ 0, - /* onentry */ pass_on_entry, + /* onentry */ _scxml_6A932FF1_pass_on_entry, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00, 0x00 /* 000000000, */ }, - /* completion */ { 0x00, 0x00 /* 000000000, */ }, - /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ }, + /* children */ { 0x00 /* 0000 */ }, + /* completion */ { 0x00 /* 0000 */ }, + /* ancestors */ { 0x01 /* 1000 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, }, - { /* state number 8 */ + { /* state number 3 */ /* name */ "fail", /* parent */ 0, - /* onentry */ fail_on_entry, + /* onentry */ _scxml_6A932FF1_fail_on_entry, /* onexit */ NULL, /* invoke */ NULL, - /* children */ { 0x00, 0x00 /* 000000000, */ }, - /* completion */ { 0x00, 0x00 /* 000000000, */ }, - /* ancestors */ { 0x01, 0x00 /* 100000000, 0 */ }, + /* children */ { 0x00 /* 0000 */ }, + /* completion */ { 0x00 /* 0000 */ }, + /* ancestors */ { 0x01 /* 1000 */ }, /* data */ NULL, /* type */ SCXML_STATE_FINAL, } }; -static const scxml_transition scxml_transitions[6] = { +static const scxml_transition _scxml_6A932FF1_transitions[2] = { { /* transition number 0 with priority 0 - target: s02 - */ - /* source */ 2, - /* target */ { 0x08, 0x00 /* 000100000, 3 */ }, - /* event */ NULL, - /* condition */ NULL, - /* ontrans */ NULL, - /* type */ SCXML_TRANS_SPONTANEOUS, - /* conflicts */ { 0x37 /* 111011, 0 1 2 4 5 */ }, - /* exit set */ { 0x0c, 0x00 /* 001100000, 2 3 */ } - }, - { /* transition number 1 with priority 1 - target: s1 + target: pass */ /* source */ 1, - /* target */ { 0x10, 0x00 /* 000010000, 4 */ }, - /* event */ "done.state.s0", - /* condition */ "_event.data['Var1']==1", + /* target */ { 0x04 /* 0010 */ }, + /* event */ "childToParent", + /* condition */ "Var1==2", /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ }, - /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ } + /* conflicts */ { 0x03 /* 11 */ }, + /* exit set */ { 0x0e /* 0111 */ } }, - { /* transition number 2 with priority 2 + { /* transition number 1 with priority 1 target: fail */ /* source */ 1, - /* target */ { 0x00, 0x01 /* 000000001, 8 */ }, - /* event */ "done.state.s0", + /* target */ { 0x08 /* 0001 */ }, + /* event */ "*", /* condition */ NULL, /* ontrans */ NULL, /* type */ 0, - /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ }, - /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ } + /* conflicts */ { 0x03 /* 11 */ }, + /* exit set */ { 0x0e /* 0111 */ } + } +}; + +static const scxml_elem_param _scxml_74EC8913_elem_params[2] = { + /* name, expr, location */ + { "aParam", "2", NULL }, + { NULL, NULL, NULL } +}; + +static const scxml_elem_send _scxml_74EC8913_elem_sends[1] = { + { + /* event */ "childToParent", + /* eventexpr */ NULL, + /* target */ "#_parent", + /* targetexpr */ NULL, + /* type */ NULL, + /* typeexpr */ NULL, + /* id */ NULL, + /* idlocation */ NULL, + /* delay */ NULL, + /* delayexpr */ NULL, + /* namelist */ NULL, + /* content */ NULL, + /* contentexpr */ NULL, + /* params */ &_scxml_74EC8913_elem_params[0] + } +}; + +static const scxml_elem_donedata _scxml_74EC8913_elem_donedatas[1] = { + /* source, content, contentexpr, params */ + { 0, NULL, NULL, NULL } +}; + +static int _scxml_74EC8913_subFinal_on_entry_0(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + int err = SCXML_ERR_OK; + if likely(ctx->exec_content_send != NULL) { + if ((ctx->exec_content_send(ctx, &_scxml_74EC8913_elem_sends[0])) != SCXML_ERR_OK) return err; + } else { + return SCXML_ERR_MISSING_CALLBACK; + } + return SCXML_ERR_OK; +} + +static int _scxml_74EC8913_subFinal_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) { + _scxml_74EC8913_subFinal_on_entry_0(ctx, state, event); + return SCXML_ERR_OK; +} + +static const scxml_state _scxml_74EC8913_states[2] = { + { /* state number 0 */ + /* name */ NULL, + /* parent */ 0, + /* onentry */ NULL, + /* onexit */ NULL, + /* invoke */ NULL, + /* children */ { 0x02 /* 01 */ }, + /* completion */ { 0x02 /* 01 */ }, + /* ancestors */ { 0x00 /* 00 */ }, + /* data */ NULL, + /* type */ SCXML_STATE_COMPOUND, }, - { /* transition number 3 with priority 3 - target: s12 - */ - /* source */ 5, - /* target */ { 0x40, 0x00 /* 000000100, 6 */ }, - /* event */ NULL, - /* condition */ NULL, - /* ontrans */ NULL, - /* type */ SCXML_TRANS_SPONTANEOUS, - /* conflicts */ { 0x3e /* 011111, 1 2 3 4 5 */ }, - /* exit set */ { 0x60, 0x00 /* 000001100, 5 6 */ } + { /* state number 1 */ + /* name */ "subFinal", + /* parent */ 0, + /* onentry */ _scxml_74EC8913_subFinal_on_entry, + /* onexit */ NULL, + /* invoke */ NULL, + /* children */ { 0x00 /* 00 */ }, + /* completion */ { 0x00 /* 00 */ }, + /* ancestors */ { 0x01 /* 10 */ }, + /* data */ NULL, + /* type */ SCXML_STATE_FINAL, + } +}; + +static const scxml_transition _scxml_74EC8913_transitions[0] = { +}; + +const scxml_machine scxml_machines[3] = { + { + /* flags */ 0, + /* nr_states */ 4, + /* nr_transitions */ 2, + /* name */ "", + /* datamodel */ "ecmascript", + /* uuid */ "6A932FF17BFF1735E3F3C77F7B54C218", + /* states */ &_scxml_6A932FF1_states[0], + /* transitions */ &_scxml_6A932FF1_transitions[0], + /* parent */ NULL, + /* donedata */ &_scxml_6A932FF1_elem_donedatas[0], + /* script */ NULL }, - { /* transition number 4 with priority 4 - target: pass - */ - /* source */ 4, - /* target */ { 0x80, 0x00 /* 000000010, 7 */ }, - /* event */ "done.state.s1", - /* condition */ "_event.data == 'foo'", - /* ontrans */ NULL, - /* type */ 0, - /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ }, - /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ } + { + /* flags */ 0, + /* nr_states */ 2, + /* nr_transitions */ 0, + /* name */ "", + /* datamodel */ "ecmascript", + /* uuid */ "74EC8913A9386F1A7EC5EF2A0426752B", + /* states */ &_scxml_74EC8913_states[0], + /* transitions */ &_scxml_74EC8913_transitions[0], + /* parent */ &scxml_machines[0], + /* donedata */ &_scxml_74EC8913_elem_donedatas[0], + /* script */ NULL }, - { /* transition number 5 with priority 5 - target: fail - */ - /* source */ 4, - /* target */ { 0x00, 0x01 /* 000000001, 8 */ }, - /* event */ "done.state.s1", - /* condition */ NULL, - /* ontrans */ NULL, - /* type */ 0, - /* conflicts */ { 0x3f /* 111111, 0 1 2 3 4 5 */ }, - /* exit set */ { 0xfe, 0x01 /* 011111111, 1 2 3 4 5 6 7 8 */ } - } + {0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; #ifdef SCXML_VERBOSE -static void printStateNames(const char* a) { +static void printStateNames(const scxml_ctx* ctx, const char* a, size_t length) { size_t i; const char* seperator = ""; - for (i = 0; i < SCXML_NUMBER_STATES; i++) { + for (i = 0; i < length; i++) { if (BIT_HAS(i, a)) { - printf("%s%s", seperator, (scxml_states[i].name != NULL ? scxml_states[i].name : "UNK")); + printf("%s%s", seperator, (ctx->machine->states[i].name != NULL ? ctx->machine->states[i].name : "UNK")); seperator = ", "; } } @@ -464,69 +574,78 @@ static void printBitsetIndices(const char* a, size_t length) { #endif static int bit_has_and(const char* a, const char* b, size_t i) { - do { - if (a[i - 1] & b[i - 1]) + while(i--) { + if (a[i] & b[i]) return 1; - } while(--i); + } return 0; } +static void bit_clear_all(char* a, size_t i) { + while(i--) { + a[i] = 0; + } +} + static int bit_has_any(const char* a, size_t i) { - do { - if (a[i - 1] > 0) + while(i--) { + if (a[i] > 0) return 1; - } while(--i); + } return 0; } static void bit_or(char* dest, const char* mask, size_t i) { - do { - dest[i - 1] |= mask[i - 1]; - } while(--i); + while(i--) { + dest[i] |= mask[i]; + } } static void bit_copy(char* dest, const char* source, size_t i) { - do { - dest[i - 1] = source[i - 1]; - } while(--i); + while(i--) { + dest[i] = source[i]; + } } static void bit_and_not(char* dest, const char* mask, size_t i) { - do { - dest[i - 1] &= ~mask[i - 1]; - } while(--i); + while(i--) { + dest[i] &= ~mask[i]; + } } static void bit_and(char* dest, const char* mask, size_t i) { - do { - dest[i - 1] &= mask[i - 1]; - } while(--i); + while(i--) { + dest[i] &= mask[i]; + }; } int scxml_step(scxml_ctx* ctx) { #ifdef SCXML_VERBOSE printf("Config: "); - printStateNames(ctx->config); + printStateNames(ctx, ctx->config, SCXML_NUMBER_STATES); #endif -// MACRO_STEP: - if (ctx->flags & SCXML_CTX_TOP_LEVEL_FINAL) return SCXML_ERR_DONE; - size_t i, j, k; + SCXML_NR_STATES_TYPE i, j, k; + SCXML_NR_STATES_TYPE nr_states_bytes = ((SCXML_NUMBER_STATES + 7) & ~7) >> 3; + SCXML_NR_TRANS_TYPE nr_trans_bytes = ((SCXML_NUMBER_TRANS + 7) & ~7) >> 3; int err = SCXML_ERR_OK; - char conflicts[1] = {0}; - char target_set[2] = {0, 0}; - char exit_set[2] = {0, 0}; - char trans_set[1] = {0}; - char entry_set[2] = {0, 0}; - char tmp_states[2] = {0, 0}; - + char conflicts [SCXML_MAX_NR_TRANS_BYTES]; + char trans_set [SCXML_MAX_NR_TRANS_BYTES]; + char target_set [SCXML_MAX_NR_STATES_BYTES]; + char exit_set [SCXML_MAX_NR_STATES_BYTES]; + char entry_set [SCXML_MAX_NR_STATES_BYTES]; + char tmp_states [SCXML_MAX_NR_STATES_BYTES]; + + bit_clear_all(target_set, nr_states_bytes); + bit_clear_all(trans_set, nr_trans_bytes); if unlikely(ctx->flags == SCXML_CTX_PRISTINE) { - global_script(ctx, &scxml_states[0], NULL); - bit_or(target_set, scxml_states[0].completion, 2); + if (ctx->machine->script != NULL) + ctx->machine->script(ctx, &ctx->machine->states[0], NULL); + bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes); ctx->flags |= SCXML_CTX_SPONTANEOUS | SCXML_CTX_INITIALIZED; goto ESTABLISH_ENTRY_SET; } @@ -538,40 +657,59 @@ int scxml_step(scxml_ctx* ctx) { if ((ctx->event = ctx->dequeue_internal(ctx)) != NULL) { goto SELECT_TRANSITIONS; } + + // manage invocations + for (i = 0; i < SCXML_NUMBER_STATES; i++) { + // uninvoke + if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) { + if (ctx->machine->states[i].invoke != NULL) + ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 1); + BIT_CLEAR(i, ctx->invocations) + } + // invoke + if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) { + if (ctx->machine->states[i].invoke != NULL) + ctx->machine->states[i].invoke(ctx, &ctx->machine->states[i], NULL, 0); + BIT_SET_AT(i, ctx->invocations) + } + } + if ((ctx->event = ctx->dequeue_external(ctx)) != NULL) { goto SELECT_TRANSITIONS; } SELECT_TRANSITIONS: - for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) { + bit_clear_all(conflicts, nr_trans_bytes); + bit_clear_all(exit_set, nr_states_bytes); + for (i = 0; i < SCXML_NUMBER_TRANS; i++) { // never select history or initial transitions automatically - if unlikely(scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) + if unlikely(ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) continue; // is the transition active? - if (BIT_HAS(scxml_transitions[i].source, ctx->config)) { + if (BIT_HAS(ctx->machine->transitions[i].source, ctx->config)) { // is it non-conflicting? if (!BIT_HAS(i, conflicts)) { // is it enabled? - if (ctx->is_enabled(ctx, &scxml_transitions[i], ctx->event) > 0) { + if (ctx->is_enabled(ctx, &ctx->machine->transitions[i], ctx->event) > 0) { // remember that we found a transition ctx->flags |= SCXML_CTX_TRANSITION_FOUND; // transitions that are pre-empted - bit_or(conflicts, scxml_transitions[i].conflicts, 1); + bit_or(conflicts, ctx->machine->transitions[i].conflicts, nr_trans_bytes); // states that are directly targeted (resolve as entry-set later) - bit_or(target_set, scxml_transitions[i].target, 2); + bit_or(target_set, ctx->machine->transitions[i].target, nr_states_bytes); // states that will be left - bit_or(exit_set, scxml_transitions[i].exit_set, 2); + bit_or(exit_set, ctx->machine->transitions[i].exit_set, nr_states_bytes); BIT_SET_AT(i, trans_set); } } } } - bit_and(exit_set, ctx->config, 2); + bit_and(exit_set, ctx->config, nr_states_bytes); if (ctx->flags & SCXML_CTX_TRANSITION_FOUND) { ctx->flags |= SCXML_CTX_SPONTANEOUS; @@ -582,71 +720,71 @@ SELECT_TRANSITIONS: #ifdef SCXML_VERBOSE printf("Targets: "); - printStateNames(target_set); + printStateNames(ctx, target_set, SCXML_NUMBER_STATES); #endif #ifdef SCXML_VERBOSE printf("Exiting: "); - printStateNames(exit_set); + printStateNames(ctx, exit_set, SCXML_NUMBER_STATES); #endif #ifdef SCXML_VERBOSE printf("History: "); - printStateNames(ctx->history); + printStateNames(ctx, ctx->history, SCXML_NUMBER_STATES); #endif // REMEMBER_HISTORY: for (i = 0; i < SCXML_NUMBER_STATES; i++) { - if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW || - SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP) { + if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW || + SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP) { // a history state whose parent is about to be exited - if unlikely(BIT_HAS(scxml_states[i].parent, exit_set)) { - bit_copy(tmp_states, scxml_states[i].completion, 2); + if unlikely(BIT_HAS(ctx->machine->states[i].parent, exit_set)) { + bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes); // set those states who were enabled - bit_and(tmp_states, ctx->config, 2); + bit_and(tmp_states, ctx->config, nr_states_bytes); // clear current history with completion mask - bit_and_not(ctx->history, scxml_states[i].completion, 2); + bit_and_not(ctx->history, ctx->machine->states[i].completion, nr_states_bytes); // set history - bit_or(ctx->history, tmp_states, 2); + bit_or(ctx->history, tmp_states, nr_states_bytes); } } } ESTABLISH_ENTRY_SET: // calculate new entry set - bit_copy(entry_set, target_set, 2); + bit_copy(entry_set, target_set, nr_states_bytes); // iterate for ancestors for (i = 0; i < SCXML_NUMBER_STATES; i++) { if (BIT_HAS(i, entry_set)) { - bit_or(entry_set, scxml_states[i].ancestors, 2); + bit_or(entry_set, ctx->machine->states[i].ancestors, nr_states_bytes); } } // iterate for descendants for (i = 0; i < SCXML_NUMBER_STATES; i++) { if (BIT_HAS(i, entry_set)) { - switch (SCXML_STATE_MASK(scxml_states[i].type)) { + switch (SCXML_STATE_MASK(ctx->machine->states[i].type)) { case SCXML_STATE_PARALLEL: { - bit_or(entry_set, scxml_states[i].completion, 2); + bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes); break; } case SCXML_STATE_HISTORY_SHALLOW: case SCXML_STATE_HISTORY_DEEP: { - if (!bit_has_and(scxml_states[i].completion, ctx->history, 2) && - !BIT_HAS(scxml_states[i].parent, ctx->config)) { + if (!bit_has_and(ctx->machine->states[i].completion, ctx->history, nr_states_bytes) && + !BIT_HAS(ctx->machine->states[i].parent, ctx->config)) { // nothing set for history, look for a default transition - for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) { - if unlikely(scxml_transitions[j].source == i) { - bit_or(entry_set, scxml_transitions[j].target, 2); - if(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP && - !bit_has_and(scxml_transitions[j].target, scxml_states[i].children, 2)) { + for (j = 0; j < SCXML_NUMBER_TRANS; j++) { + if unlikely(ctx->machine->transitions[j].source == i) { + bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes); + if(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP && + !bit_has_and(ctx->machine->transitions[j].target, ctx->machine->states[i].children, nr_states_bytes)) { for (k = i + 1; k < SCXML_NUMBER_STATES; k++) { - if (BIT_HAS(k, scxml_transitions[j].target)) { - bit_or(entry_set, scxml_states[k].ancestors, 2); + if (BIT_HAS(k, ctx->machine->transitions[j].target)) { + bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes); break; } } @@ -657,20 +795,20 @@ ESTABLISH_ENTRY_SET: // Note: SCXML mandates every history to have a transition! } } else { - bit_copy(tmp_states, scxml_states[i].completion, 2); - bit_and(tmp_states, ctx->history, 2); - bit_or(entry_set, tmp_states, 2); - if (scxml_states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) { + bit_copy(tmp_states, ctx->machine->states[i].completion, nr_states_bytes); + bit_and(tmp_states, ctx->history, nr_states_bytes); + bit_or(entry_set, tmp_states, nr_states_bytes); + if (ctx->machine->states[i].type == (SCXML_STATE_HAS_HISTORY | SCXML_STATE_HISTORY_DEEP)) { // a deep history state with nested histories -> more completion for (j = i + 1; j < SCXML_NUMBER_STATES; j++) { - if (BIT_HAS(j, scxml_states[i].completion) && + if (BIT_HAS(j, ctx->machine->states[i].completion) && BIT_HAS(j, entry_set) && - (scxml_states[j].type & SCXML_STATE_HAS_HISTORY)) { + (ctx->machine->states[j].type & SCXML_STATE_HAS_HISTORY)) { for (k = j + 1; k < SCXML_NUMBER_STATES; k++) { // add nested history to entry_set - if ((SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_DEEP || - SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_HISTORY_SHALLOW) && - BIT_HAS(k, scxml_states[j].children)) { + if ((SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_DEEP || + SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_HISTORY_SHALLOW) && + BIT_HAS(k, ctx->machine->states[j].children)) { // a nested history state BIT_SET_AT(k, entry_set); } @@ -682,14 +820,14 @@ ESTABLISH_ENTRY_SET: break; } case SCXML_STATE_INITIAL: { - for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) { - if (scxml_transitions[j].source == i) { + for (j = 0; j < SCXML_NUMBER_TRANS; j++) { + if (ctx->machine->transitions[j].source == i) { BIT_SET_AT(j, trans_set); BIT_CLEAR(i, entry_set); - bit_or(entry_set, scxml_transitions[j].target, 2); + bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes); for (k = i + 1; k < SCXML_NUMBER_STATES; k++) { - if (BIT_HAS(k, scxml_transitions[j].target)) { - bit_or(entry_set, scxml_states[k].ancestors, 2); + if (BIT_HAS(k, ctx->machine->transitions[j].target)) { + bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes); } } } @@ -697,16 +835,16 @@ ESTABLISH_ENTRY_SET: break; } case SCXML_STATE_COMPOUND: { // we need to check whether one child is already in entry_set - if (!bit_has_and(entry_set, scxml_states[i].children, 2) && - (!bit_has_and(ctx->config, scxml_states[i].children, 2) || - bit_has_and(exit_set, scxml_states[i].children, 2))) + if (!bit_has_and(entry_set, ctx->machine->states[i].children, nr_states_bytes) && + (!bit_has_and(ctx->config, ctx->machine->states[i].children, nr_states_bytes) || + bit_has_and(exit_set, ctx->machine->states[i].children, nr_states_bytes))) { - bit_or(entry_set, scxml_states[i].completion, 2); - if (!bit_has_and(scxml_states[i].completion, scxml_states[i].children, 2)) { + bit_or(entry_set, ctx->machine->states[i].completion, nr_states_bytes); + if (!bit_has_and(ctx->machine->states[i].completion, ctx->machine->states[i].children, nr_states_bytes)) { // deep completion for (j = i + 1; j < SCXML_NUMBER_STATES; j++) { - if (BIT_HAS(j, scxml_states[i].completion)) { - bit_or(entry_set, scxml_states[j].ancestors, 2); + if (BIT_HAS(j, ctx->machine->states[i].completion)) { + bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes); break; // completion of compound is single state } } @@ -720,7 +858,7 @@ ESTABLISH_ENTRY_SET: #ifdef SCXML_VERBOSE printf("Transitions: "); - printBitsetIndices(trans_set, sizeof(char) * 8 * 1); + printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes); #endif // EXIT_STATES: @@ -728,8 +866,8 @@ ESTABLISH_ENTRY_SET: while(i-- > 0) { if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) { // call all on exit handlers - if (scxml_states[i].on_exit != NULL) { - if unlikely((err = scxml_states[i].on_exit(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK) + if (ctx->machine->states[i].on_exit != NULL) { + if unlikely((err = ctx->machine->states[i].on_exit(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK) return err; } BIT_CLEAR(i, ctx->config); @@ -737,13 +875,13 @@ ESTABLISH_ENTRY_SET: } // TAKE_TRANSITIONS: - for (i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) { - if (BIT_HAS(i, trans_set) && (scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) { + for (i = 0; i < SCXML_NUMBER_TRANS; i++) { + if (BIT_HAS(i, trans_set) && (ctx->machine->transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) { // call executable content in transition - if (scxml_transitions[i].on_transition != NULL) { - if unlikely((err = scxml_transitions[i].on_transition(ctx, - &scxml_states[scxml_transitions[i].source], - ctx->event)) != SCXML_ERR_OK) + if (ctx->machine->transitions[i].on_transition != NULL) { + if unlikely((err = ctx->machine->transitions[i].on_transition(ctx, + &ctx->machine->states[ctx->machine->transitions[i].source], + ctx->event)) != SCXML_ERR_OK) return err; } } @@ -751,61 +889,61 @@ ESTABLISH_ENTRY_SET: #ifdef SCXML_VERBOSE printf("Entering: "); - printStateNames(entry_set); + printStateNames(ctx, entry_set, SCXML_NUMBER_STATES); #endif // ENTER_STATES: for (i = 0; i < SCXML_NUMBER_STATES; i++) { if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) { // these are no proper states - if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_DEEP || - SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_HISTORY_SHALLOW || - SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_INITIAL) + if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_DEEP || + SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_HISTORY_SHALLOW || + SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_INITIAL) continue; BIT_SET_AT(i, ctx->config); // initialize data if (!BIT_HAS(i, ctx->initialized_data)) { - if unlikely(scxml_states[i].data != NULL && ctx->exec_content_init != NULL) { - ctx->exec_content_init(ctx, scxml_states[i].data); + if unlikely(ctx->machine->states[i].data != NULL && ctx->exec_content_init != NULL) { + ctx->exec_content_init(ctx, ctx->machine->states[i].data); } BIT_SET_AT(i, ctx->initialized_data); } - if (scxml_states[i].on_entry != NULL) { - if unlikely((err = scxml_states[i].on_entry(ctx, &scxml_states[i], ctx->event)) != SCXML_ERR_OK) + if (ctx->machine->states[i].on_entry != NULL) { + if unlikely((err = ctx->machine->states[i].on_entry(ctx, &ctx->machine->states[i], ctx->event)) != SCXML_ERR_OK) return err; } // take history and initial transitions - for (j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) { + for (j = 0; j < SCXML_NUMBER_TRANS; j++) { if unlikely(BIT_HAS(j, trans_set) && - (scxml_transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) && - scxml_states[scxml_transitions[j].source].parent == i) { + (ctx->machine->transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) && + ctx->machine->states[ctx->machine->transitions[j].source].parent == i) { // call executable content in transition - if (scxml_transitions[j].on_transition != NULL) { - if unlikely((err = scxml_transitions[j].on_transition(ctx, - &scxml_states[i], - ctx->event)) != SCXML_ERR_OK) + if (ctx->machine->transitions[j].on_transition != NULL) { + if unlikely((err = ctx->machine->transitions[j].on_transition(ctx, + &ctx->machine->states[i], + ctx->event)) != SCXML_ERR_OK) return err; } } } // handle final states - if unlikely(SCXML_STATE_MASK(scxml_states[i].type) == SCXML_STATE_FINAL) { - if unlikely(scxml_states[i].ancestors[0] == 0x01) { + if unlikely(SCXML_STATE_MASK(ctx->machine->states[i].type) == SCXML_STATE_FINAL) { + if unlikely(ctx->machine->states[i].ancestors[0] == 0x01) { ctx->flags |= SCXML_CTX_TOP_LEVEL_FINAL; } else { // raise done event - const scxml_elem_donedata* donedata = &scxml_elem_donedatas[0]; + const scxml_elem_donedata* donedata = &ctx->machine->donedata[0]; while(ELEM_DONEDATA_IS_SET(donedata)) { if unlikely(donedata->source == i) break; donedata++; } - ctx->raise_done_event(ctx, &scxml_states[scxml_states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL)); + ctx->raise_done_event(ctx, &ctx->machine->states[ctx->machine->states[i].parent], (ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL)); } /** @@ -816,20 +954,20 @@ ESTABLISH_ENTRY_SET: * 4. If a state remains, not all children of a parallel are final */ for (j = 0; j < SCXML_NUMBER_STATES; j++) { - if unlikely(SCXML_STATE_MASK(scxml_states[j].type) == SCXML_STATE_PARALLEL && - BIT_HAS(j, scxml_states[i].ancestors)) { - bit_and_not(tmp_states, tmp_states, 2); + if unlikely(SCXML_STATE_MASK(ctx->machine->states[j].type) == SCXML_STATE_PARALLEL && + BIT_HAS(j, ctx->machine->states[i].ancestors)) { + bit_clear_all(tmp_states, nr_states_bytes); for (k = 0; k < SCXML_NUMBER_STATES; k++) { - if unlikely(BIT_HAS(j, scxml_states[k].ancestors) && BIT_HAS(k, ctx->config)) { - if (SCXML_STATE_MASK(scxml_states[k].type) == SCXML_STATE_FINAL) { - bit_and_not(tmp_states, scxml_states[k].ancestors, 2); + if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) { + if (SCXML_STATE_MASK(ctx->machine->states[k].type) == SCXML_STATE_FINAL) { + bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes); } else { BIT_SET_AT(k, tmp_states); } } } - if unlikely(!bit_has_any(tmp_states, 2)) { - ctx->raise_done_event(ctx, &scxml_states[j], NULL); + if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) { + ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL); } } } -- cgit v0.12