From 3ec460015db867b6163f14e5d7effc7a01b29295 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Wed, 16 Nov 2016 11:36:07 +0100 Subject: Impreoved PROMELA transformation --- apps/uscxml-transform.cpp | 63 +- src/uscxml/transform/ChartToPromela.cpp | 3120 +++++++++++--------- src/uscxml/transform/ChartToPromela.h | 72 +- src/uscxml/transform/Transformer.h | 6 + .../transform/promela/PromelaCodeAnalyzer.cpp | 59 +- src/uscxml/transform/promela/PromelaCodeAnalyzer.h | 10 +- test/CMakeLists.txt | 2 +- test/ctest/CTestCustom.ctest.in | 110 +- test/ctest/scripts/run_promela_test.cmake | 4 +- test/w3c/analyze_tests.pl | 101 + 10 files changed, 1997 insertions(+), 1550 deletions(-) diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp index e1c44c3..b5f42c4 100644 --- a/apps/uscxml-transform.cpp +++ b/apps/uscxml-transform.cpp @@ -41,20 +41,7 @@ void printUsageAndExit(const char* progName) { printf("\t-t pml : convert to spin/promela program\n"); printf("\t-t vhdl : convert to VHDL hardware description\n"); printf("\t-t flat : flatten to SCXML state-machine\n"); - printf("\t-t min : minimize SCXML state-chart\n"); - printf("\t-a {OPTIONS} : annotate SCXML elements with comma seperated options\n"); - printf("\t priority - transitions with their priority for transition selection\n"); - printf("\t exitset - annotate all transitions with their exit sets\n"); - printf("\t entryset - annotate all transitions with their entry sets\n"); - printf("\t conflicts - annotate all transitions with their conflicts\n"); - printf("\t domain - annotate all transitions with their domain\n"); - printf("\t step - global states with their step identifier (-tflat only)\n"); - printf("\t members - global transitions with their member transitions per index (-tflat only)\n"); - printf("\t sends - transititve number of sends to external queue for global transitions (-tflat only)\n"); - printf("\t raises - transititve number of raises to internal queue for global transitions (-tflat only)\n"); - 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-a FILE : write annotated SCXML document for transformation\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"); @@ -71,7 +58,8 @@ int main(int argc, char** argv) { bool verbose = false; std::string outType; std::string pluginPath; - std::string inputFile; + std::string inputFile; + std::string annotatedFile; std::string outputFile; std::list options; std::multimap extensions; @@ -122,7 +110,7 @@ int main(int argc, char** argv) { inputFile = optarg; break; case 'a': - options = tokenize(optarg, ','); + annotatedFile = optarg; break; case 'X': { std::list extension = tokenize(optarg, '='); @@ -275,10 +263,12 @@ int main(int argc, char** argv) { } } + Transformer transformer; if (outType == "c") { - Transformer transformer = ChartToC::transform(interpreter); + transformer = ChartToC::transform(interpreter); transformer.setExtensions(extensions); transformer.setOptions(options); + if (outputFile.size() == 0 || outputFile == "-") { transformer.writeTo(std::cout); } else { @@ -287,31 +277,36 @@ int main(int argc, char** argv) { transformer.writeTo(outStream); outStream.close(); } - exit(EXIT_SUCCESS); } if (outType == "vhdl") { + transformer = ChartToVHDL::transform(interpreter); + transformer.setExtensions(extensions); + transformer.setOptions(options); + if (outputFile.size() == 0 || outputFile == "-") { - ChartToVHDL::transform(interpreter).writeTo(std::cout); + transformer.writeTo(std::cout); } else { std::ofstream outStream; outStream.open(outputFile.c_str()); - ChartToVHDL::transform(interpreter).writeTo(outStream); + transformer.writeTo(outStream); outStream.close(); } - exit(EXIT_SUCCESS); } if (outType == "pml") { - if (outputFile.size() == 0 || outputFile == "-") { - ChartToPromela::transform(interpreter).writeTo(std::cout); - } else { - std::ofstream outStream; - outStream.open(outputFile.c_str()); - ChartToPromela::transform(interpreter).writeTo(outStream); - outStream.close(); - } - exit(EXIT_SUCCESS); + transformer = ChartToPromela::transform(interpreter); + transformer.setExtensions(extensions); + transformer.setOptions(options); + + if (outputFile.size() == 0 || outputFile == "-") { + transformer.writeTo(std::cout); + } else { + std::ofstream outStream; + outStream.open(outputFile.c_str()); + transformer.writeTo(outStream); + outStream.close(); + } } // if (outType == "tex") { @@ -350,7 +345,13 @@ int main(int argc, char** argv) { // exit(EXIT_SUCCESS); // } + if (annotatedFile.size() > 0) { + std::ofstream outStream; + outStream.open(annotatedFile.c_str()); + outStream << (*transformer.getImpl()->getDocument()); + outStream.close(); + } #if 0 if (options.size() > 0) { ChartToFSM annotater(interpreter); @@ -385,4 +386,4 @@ int main(int argc, char** argv) { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp index a697d99..9a8b999 100644 --- a/src/uscxml/transform/ChartToPromela.cpp +++ b/src/uscxml/transform/ChartToPromela.cpp @@ -28,9 +28,42 @@ #include -#define ADAPT_SRC(code) _analyzer.adaptCode(code, _prefix) +#define ADAPT_SRC(code) _analyzer->adaptCode(code, _prefix) #define BIT_WIDTH(number) (number > 1 ? (int)ceil(log((double)number) / log((double)2.0)) : 1) -#define EVENT_NAME (_analyzer.usesComplexEventStruct() ? "_event.name" : "_event") +#define EVENT_NAME (_analyzer->usesComplexEventStruct() ? "_event.name" : "_event") +#define TMP_EVENT_NAME (_analyzer->usesComplexEventStruct() ? "_tmpE.name" : "_tmpE") +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) + +#undef TRACE_EXECUTION + +#ifdef TRACE_EXECUTION +#define TRACE_EXECUTION_V(fmt, ...) \ +stream << std::endl; \ +stream << "#if TRACE_EXECUTION" << std::endl; \ +if (_machinesAll->size() > 1) {\ + stream << "printf(\"%d: " fmt "\\n\", _pid, " __VA_ARGS__ ");" << std::endl; \ +} else { \ + stream << "printf(\"" fmt "\\n\", " __VA_ARGS__ ");" << std::endl; \ +} \ +stream << "#endif" << std::endl; \ +stream << std::endl; + +#define TRACE_EXECUTION(fmt) \ +stream << std::endl; \ +stream << "#if TRACE_EXECUTION" << std::endl; \ +if (_machinesAll->size() > 1) {\ +stream << "printf(\"%d: " fmt "\\n\", _pid);" << std::endl; \ +} else { \ +stream << "printf(\"" fmt "\\n\");" << std::endl; \ +} \ +stream << "#endif" << std::endl; \ +stream << std::endl; + +#else + +#define TRACE_EXECUTION_V(fmt, ...) +#define TRACE_EXECUTION(fmt) +#endif namespace uscxml { @@ -44,148 +77,78 @@ Transformer ChartToPromela::transform(const Interpreter& other) { ChartToPromela::~ChartToPromela() { } -/** - The following tests FAILED: - 1740 - w3c/spin/promela/test150.scxml (Failed) - 1741 - w3c/spin/promela/test151.scxml (Failed) - 1742 - w3c/spin/promela/test152.scxml (Failed) - 1743 - w3c/spin/promela/test153.scxml (Failed) - 1744 - w3c/spin/promela/test155.scxml (Failed) - 1745 - w3c/spin/promela/test156.scxml (Failed) - 1749 - w3c/spin/promela/test173.scxml (Failed) - 1750 - w3c/spin/promela/test174.scxml (Failed) - 1752 - w3c/spin/promela/test176.scxml (Failed) - 1753 - w3c/spin/promela/test178.scxml (Failed) - 1754 - w3c/spin/promela/test179.scxml (Failed) - 1757 - w3c/spin/promela/test186.scxml (Failed) - 1762 - w3c/spin/promela/test192.scxml (Failed) - 1763 - w3c/spin/promela/test193.scxml (Failed) - 1765 - w3c/spin/promela/test198.scxml (Failed) - 1769 - w3c/spin/promela/test205.scxml (Failed) - 1770 - w3c/spin/promela/test207.scxml (Failed) - 1771 - w3c/spin/promela/test208.scxml (Failed) - 1772 - w3c/spin/promela/test210.scxml (Failed) - 1773 - w3c/spin/promela/test215.scxml (Failed) - 1774 - w3c/spin/promela/test216.scxml (Failed) - 1776 - w3c/spin/promela/test223.scxml (Failed) - 1777 - w3c/spin/promela/test224.scxml (Failed) - 1778 - w3c/spin/promela/test225.scxml (Failed) - 1780 - w3c/spin/promela/test228.scxml (Failed) - 1782 - w3c/spin/promela/test230.scxml (Failed) - 1783 - w3c/spin/promela/test232.scxml (Failed) - 1785 - w3c/spin/promela/test234.scxml (Failed) - 1787 - w3c/spin/promela/test236.scxml (Failed) - 1788 - w3c/spin/promela/test237.scxml (Failed) - 1789 - w3c/spin/promela/test239.scxml (Failed) - 1790 - w3c/spin/promela/test240.scxml (Failed) - 1791 - w3c/spin/promela/test241.scxml (Failed) - 1792 - w3c/spin/promela/test242.scxml (Failed) - 1797 - w3c/spin/promela/test250.scxml (Failed) - 1798 - w3c/spin/promela/test252.scxml (Failed) - 1799 - w3c/spin/promela/test253.scxml (Failed) - 1802 - w3c/spin/promela/test278.scxml (Failed) - 1803 - w3c/spin/promela/test279.scxml (Failed) - 1805 - w3c/spin/promela/test286.scxml (Failed) - 1808 - w3c/spin/promela/test294.scxml (Failed) - 1809 - w3c/spin/promela/test298.scxml (Failed) - 1811 - w3c/spin/promela/test302.scxml (Failed) - 1813 - w3c/spin/promela/test304.scxml (Failed) - 1814 - w3c/spin/promela/test309.scxml (Failed) - 1815 - w3c/spin/promela/test310.scxml (Failed) - 1816 - w3c/spin/promela/test311.scxml (Failed) - 1817 - w3c/spin/promela/test312.scxml (Failed) - 1818 - w3c/spin/promela/test313.scxml (Failed) - 1819 - w3c/spin/promela/test314.scxml (Failed) - 1820 - w3c/spin/promela/test318.scxml (Failed) - 1823 - w3c/spin/promela/test322.scxml (Failed) - 1825 - w3c/spin/promela/test324.scxml (Failed) - 1827 - w3c/spin/promela/test326.scxml (Failed) - 1828 - w3c/spin/promela/test329.scxml (Failed) - 1829 - w3c/spin/promela/test330.scxml (Failed) - 1830 - w3c/spin/promela/test331.scxml (Failed) - 1831 - w3c/spin/promela/test332.scxml (Failed) - 1832 - w3c/spin/promela/test333.scxml (Failed) - 1833 - w3c/spin/promela/test335.scxml (Failed) - 1835 - w3c/spin/promela/test337.scxml (Failed) - 1837 - w3c/spin/promela/test339.scxml (Failed) - 1838 - w3c/spin/promela/test342.scxml (Failed) - 1839 - w3c/spin/promela/test343.scxml (Failed) - 1840 - w3c/spin/promela/test344.scxml (Failed) - 1841 - w3c/spin/promela/test346.scxml (Failed) - 1842 - w3c/spin/promela/test347.scxml (Failed) - 1846 - w3c/spin/promela/test351.scxml (Failed) - 1847 - w3c/spin/promela/test352.scxml (Failed) - 1848 - w3c/spin/promela/test354.scxml (Failed) - 1849 - w3c/spin/promela/test355.scxml (Failed) - 1850 - w3c/spin/promela/test364.scxml (Failed) - 1851 - w3c/spin/promela/test372.scxml (Failed) - 1854 - w3c/spin/promela/test377.scxml (Failed) - 1855 - w3c/spin/promela/test378.scxml (Failed) - 1856 - w3c/spin/promela/test387.scxml (Failed) - 1857 - w3c/spin/promela/test388.scxml (Failed) - 1858 - w3c/spin/promela/test396.scxml (Failed) - 1859 - w3c/spin/promela/test399.scxml (Failed) - 1860 - w3c/spin/promela/test401.scxml (Failed) - 1861 - w3c/spin/promela/test402.scxml (Failed) - 1862 - w3c/spin/promela/test403a.scxml (Failed) - 1863 - w3c/spin/promela/test403b.scxml (Failed) - 1864 - w3c/spin/promela/test403c.scxml (Failed) - 1865 - w3c/spin/promela/test404.scxml (Failed) - 1866 - w3c/spin/promela/test405.scxml (Failed) - 1867 - w3c/spin/promela/test406.scxml (Failed) - 1868 - w3c/spin/promela/test407.scxml (Failed) - 1869 - w3c/spin/promela/test409.scxml (Failed) - 1870 - w3c/spin/promela/test411.scxml (Failed) - 1871 - w3c/spin/promela/test412.scxml (Failed) - 1872 - w3c/spin/promela/test413.scxml (Failed) - 1873 - w3c/spin/promela/test415.scxml (Failed) - 1874 - w3c/spin/promela/test416.scxml (Failed) - 1875 - w3c/spin/promela/test417.scxml (Failed) - 1877 - w3c/spin/promela/test421.scxml (Failed) - 1878 - w3c/spin/promela/test422.scxml (Failed) - 1880 - w3c/spin/promela/test487.scxml (Failed) - 1881 - w3c/spin/promela/test488.scxml (Failed) - 1882 - w3c/spin/promela/test495.scxml (Failed) - 1886 - w3c/spin/promela/test503.scxml (Failed) - 1887 - w3c/spin/promela/test504.scxml (Failed) - 1888 - w3c/spin/promela/test505.scxml (Failed) - 1890 - w3c/spin/promela/test509.scxml (Failed) - 1892 - w3c/spin/promela/test518.scxml (Failed) - 1893 - w3c/spin/promela/test519.scxml (Failed) - 1894 - w3c/spin/promela/test520.scxml (Failed) - 1897 - w3c/spin/promela/test525.scxml (Failed) - 1898 - w3c/spin/promela/test527.scxml (Failed) - 1899 - w3c/spin/promela/test528.scxml (Failed) - 1900 - w3c/spin/promela/test529.scxml (Failed) - 1901 - w3c/spin/promela/test530.scxml (Failed) - 1902 - w3c/spin/promela/test531.scxml (Failed) - 1903 - w3c/spin/promela/test532.scxml (Failed) - 1904 - w3c/spin/promela/test533.scxml (Failed) - 1905 - w3c/spin/promela/test534.scxml (Failed) - 1906 - w3c/spin/promela/test550.scxml (Failed) - 1907 - w3c/spin/promela/test551.scxml (Failed) - 1911 - w3c/spin/promela/test567.scxml (Failed) - 1912 - w3c/spin/promela/test570.scxml (Failed) - 1913 - w3c/spin/promela/test576.scxml (Failed) - 1915 - w3c/spin/promela/test579.scxml (Failed) - 1916 - w3c/spin/promela/test580.scxml (Failed) -*/ - void ChartToPromela::prepare() { if (_machinesAll == NULL) { - _machinesAll = new std::map(); + _machinesAll = new std::map(); (*_machinesAll)[_scxml] = this; } if (_machinesAllPerId == NULL) - _machinesAllPerId = new std::map(); + _machinesAllPerId = new std::map(); - if (_parentTopMost == NULL) + if (_parentTopMost == NULL) { _parentTopMost = this; + } + + // are there nested SCXML invokers? + std::list invokes = DOMUtils::inDocumentOrder({ XML_PREFIX(_scxml).str() + "invoke" }, _scxml); + for (auto invoke : invokes) { + + if (!HAS_ATTR(invoke, "id")) { + invoke->setAttribute(X("id"), X("INV_" + UUID::getUUID().substr(0,5))); + } else if (HAS_ATTR(invoke, "id") && UUID::isUUID(ATTR(invoke, "id"))) { + // shorten UUIDs + invoke->setAttribute(X("id"), X("INV_" + ATTR(invoke, "id").substr(0,5))); + } + + if (HAS_ATTR(invoke, "type") && + ATTR(invoke, "type") != "scxml" && + ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/" && + ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") + continue; + + assert(HAS_ATTR(invoke, "id")); + invoke->setAttribute(X("name"), invoke->getAttribute(X("id"))); + + Interpreter nested; + if (HAS_ATTR(invoke, "src")) { + nested = Interpreter::fromURL(URL::resolve(ATTR(invoke, "src"), _baseURL)); + } else { + std::list contents = DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "content", invoke); + std::list scxmls = DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "scxml", contents.front()); + + assert (scxmls.size() > 0); + nested = Interpreter::fromElement(scxmls.front(), _baseURL); + } + + _machinesNested[invoke] = new ChartToPromela(nested); + _machinesNested[invoke]->_analyzer = _analyzer; + _machinesNested[invoke]->_analyzer->analyze(_machinesNested[invoke]); + _machinesNested[invoke]->prepare(); + _machinesNested[invoke]->_parent = this; + _machinesNested[invoke]->_parentTopMost = _parentTopMost; + _machinesNested[invoke]->_machinesAll = _machinesAll; + (*_machinesAll)[invoke] = _machinesNested[invoke]; + + _machinesNested[invoke]->_invokerid = ATTR(invoke, "id"); + _analyzer->createMacroName(_machinesNested[invoke]->_invokerid); + _analyzer->addEvent("done.invoke." + _machinesNested[invoke]->_invokerid); + + _machinesNested[invoke]->_prefix = _analyzer->macroForLiteral(ATTR(invoke, "id")) + "_"; + + + _machinesPerId[ATTR_CAST(invoke, "id")] = invoke; + (*_machinesAllPerId)[ATTR(invoke, "id")] = invoke; + + } + + if (_machinesAll->size() > 1) { +// _analyzer->addCode("_event.origin", this); + _analyzer->addCode("_event.invokeid", this); + } // transform data / assign json into PROMELA statements std::list values; - values.splice(values.end(), DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "assign"}, _scxml)); values.splice(values.end(), DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "data"}, _scxml)); @@ -219,7 +182,7 @@ void ChartToPromela::prepare() { if (value.size() == 0) continue; - // remove all children, we will replae by suitable promela statements + // remove all children, we will replace by suitable promela statements while(element->hasChildNodes()) element->removeChild(element->getFirstChild()); @@ -237,57 +200,111 @@ void ChartToPromela::prepare() { DOMText* newText = _document->createTextNode(X(newValue)); element->insertBefore(newText, NULL); - _analyzer.addCode(newValue, this); + _analyzer->addCode(newValue, this); } } void ChartToPromela::writeTo(std::ostream& stream) { - - _analyzer.analyze(this); - // same preparations as the C transformation + _prefix = "ROOT_"; + _invokerid = "ROOT"; + _analyzer = new PromelaCodeAnalyzer(); + _analyzer->analyze(this); + _analyzer->createMacroName(_invokerid); prepare(); stream << "/** generated from " << std::endl; stream << " " << std::string(_baseURL) << std::endl; - stream << " Use as:" << std::endl; + stream << " Verify as:" << std::endl; stream << " $ spin -a this.pml" << std::endl; - stream << " $ gcc pan.c -o pan" << std::endl; - stream << " $ ./pan -a -n -N w3c" << std::endl; + stream << " $ gcc -DMEMLIM=1024 -DVECTORSZ=8192 -O2 -DXUSAFE pan.c -o pan" << std::endl; + stream << " $ ./pan -a -m10000 -n -N w3c" << std::endl; stream << " */" << std::endl; stream << std::endl; writeMacros(stream); - stream << std::endl; - writeTypeDefs(stream); - stream << std::endl; - writeTypes(stream); stream << std::endl; writeStrings(stream); stream << std::endl; + + for (auto machine : *_machinesAll) { + machine.second->writeBitHasAndMacro(stream); + stream << std::endl; + machine.second->writeBitHasAnyMacro(stream); + stream << std::endl; + machine.second->writeBitOrMacro(stream); + stream << std::endl; + machine.second->writeBitClearMacro(stream); + stream << std::endl; + machine.second->writeBitCopyMacro(stream); + stream << std::endl; + machine.second->writeBitAndMacro(stream); + stream << std::endl; + machine.second->writeBitAndNotMacro(stream); + stream << std::endl; + writeTypeDefs(stream); + stream << std::endl; + + } + + writeCommonTypeDefs(stream); + stream << std::endl; + + for (auto machine : *_machinesAll) { + machine.second->writeVariables(stream); + stream << std::endl; + } + writeCommonVariables(stream); + stream << std::endl; + + if (_analyzer->usesComplexEventStruct()) { + if (_analyzer->usesEventField("delay")) { + writeInsertWithDelay(stream); + stream << std::endl; + } + writeAdvanceTime(stream); + stream << std::endl; + writeScheduleMachines(stream); + stream << std::endl; + writeRescheduleProcess(stream); + stream << std::endl; + writeDetermineShortestDelay(stream); + stream << std::endl; + } + + if (_machinesAll->size() > 1) { + writeRemovePendingEventsFromInvoker(stream); + stream << std::endl; + } + writeCancelEvents(stream); stream << std::endl; - writeFSM(stream); - stream << std::endl; + + for (auto machine : *_machinesAll) { + machine.second->writeFSM(stream); + stream << std::endl; + } stream << "init {" << std::endl; stream << "/* initialize state and transition information */" << std::endl; - writeTransitions(stream); - stream << std::endl; - writeStates(stream); - stream << std::endl; + for (auto machine : *_machinesAll) { + machine.second->writeTransitions(stream); + stream << std::endl; + machine.second->writeStates(stream); + stream << std::endl; - stream << "/* initialize data model variables */" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_PRISTINE] = true;" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + stream << "/* initialize data model variables */" << std::endl; + stream << " " << machine.second->_prefix << "flags[USCXML_CTX_PRISTINE] = true;" << std::endl; + stream << " " << machine.second->_prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; - for (auto initializer : _varInitializers) { - stream << ADAPT_SRC(beautifyIndentation(initializer, 1)) << std::endl; + for (auto initializer : machine.second->_varInitializers) { + stream << _analyzer->adaptCode(beautifyIndentation(initializer, 1), machine.second->_prefix) << std::endl; + } } - + stream << std::endl; stream << " run " << _prefix << "step() priority 10;" << std::endl; @@ -297,94 +314,129 @@ void ChartToPromela::writeTo(std::ostream& stream) { } -void ChartToPromela::bit_clear_all(std::ostream& stream, - const std::string& identifier, - size_t length, - size_t indent) { - std::string padding; - while (indent--) - padding += " "; - stream << std::endl; - stream << padding << "/** clearing all bits of " << identifier << " */" << std::endl; - for (size_t i = 0; i < length; i++) { - stream << padding << identifier << "[" << i << "] = false;" << std::endl; - } +void ChartToPromela::writeBitAndMacro(std::ostream& stream) { + stream << "/** and'ing bits in a with mask */" << std::endl; + stream << "#define " << _prefix << "TRANS_AND(a, mask) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_AND(a, mask) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + } -void ChartToPromela::bit_copy(std::ostream& stream, - const std::string& from, - const std::string& to, - size_t length, - size_t indent) { - std::string padding; - while (indent--) - padding += " "; - stream << std::endl; - stream << padding << "/** copy bits from " << from << " to " << to << " */" << std::endl; - for (size_t i = 0; i < length; i++) { - stream << padding << to << "[" << i << "] = "<< from << "[" << i << "];" << std::endl; - } +void ChartToPromela::writeBitAndNotMacro(std::ostream& stream) { + stream << "/** not and'ing bits in a with mask */" << std::endl; + stream << "#define " << _prefix << "TRANS_AND_NOT(a, mask) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & !mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_AND_NOT(a, mask) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & !mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + } -void ChartToPromela::bit_or(std::ostream& stream, - const std::string& to, - const std::string& mask, - size_t length, - size_t indent) { - std::string padding; - while (indent--) - padding += " "; - stream << std::endl; - stream << padding << "/** or'ing bits in " << to << " with mask " << mask << " */" << std::endl; - for (size_t i = 0; i < length; i++) { - stream << padding << to << "[" << i << "] = "<< to << "[" << i << "] | " << mask << "[" << i << "];" << std::endl; +void ChartToPromela::writeBitCopyMacro(std::ostream& stream) { + stream << "/** copy bits from a to b */" << std::endl; + stream << "#define " << _prefix << "TRANS_COPY(a, b) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = b[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_COPY(a, b) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = b[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + +} + +void ChartToPromela::writeBitHasAndMacro(std::ostream& stream) { + stream << "/** is there a common bit in t1 and t2 */" << std::endl; + stream << "#define " << _prefix << "TRANS_HAS_AND(a, b) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << " || a[" << i << "] & b[" << i << "] \\" << std::endl; } + stream << ")" << std::endl; + stream << std::endl; + + stream << "#define " << _prefix << "STATES_HAS_AND(a, b) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << " || a[" << i << "] & b[" << i << "] \\" << std::endl; + } + stream << ")" << std::endl; + stream << std::endl; + } -void ChartToPromela::bit_and(std::ostream& stream, - const std::string& to, - const std::string& mask, - size_t length, - size_t indent) { - std::string padding; - while (indent--) - padding += " "; - stream << std::endl; - stream << padding << "/** and'ing bits in " << to << " with mask " << mask << " */" << std::endl; - for (size_t i = 0; i < length; i++) { - stream << padding << to << "[" << i << "] = "<< to << "[" << i << "] & " << mask << "[" << i << "];" << std::endl; - } +void ChartToPromela::writeBitHasAnyMacro(std::ostream& stream) { + stream << "/** is there bit set in a */" << std::endl; + stream << "#define " << _prefix << "TRANS_HAS_ANY(a) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << " || a[" << i << "] \\" << std::endl; + } + stream << ")" << std::endl; + stream << std::endl; + + stream << "#define " << _prefix << "STATES_HAS_ANY(a) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << " || a[" << i << "] \\" << std::endl; + } + stream << ")" << std::endl; + stream << std::endl; + } -void ChartToPromela::bit_and_not(std::ostream& stream, - const std::string& to, - const std::string& mask, - size_t length, - size_t indent) { - std::string padding; - while (indent--) - padding += " "; - stream << std::endl; - stream << padding << "/** not and'ing bits in " << to << " with mask " << mask << " */" << std::endl; - for (size_t i = 0; i < length; i++) { - stream << padding << to << "[" << i << "] = "<< to << "[" << i << "] & !" << mask << "[" << i << "];" << std::endl; - } +void ChartToPromela::writeBitOrMacro(std::ostream& stream) { + stream << "/** or'ing bits in a with mask */" << std::endl; + stream << "#define " << _prefix << "TRANS_OR(a, mask) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] | mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_OR(a, mask) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] | mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + } -void ChartToPromela::bit_has_and(std::ostream& stream, - const std::string& a, - const std::string& b, - size_t length, - size_t indent) { - std::string padding; - while (indent--) - padding += " "; - stream << "(false /** is there a common bit in " << a << " and " << b << " */" << std::endl; - for (size_t i = 0; i < length; i++) { - stream << padding << " || " << a << "[" << i << "] & "<< b << "[" << i << "]" << std::endl; - } - stream << padding << ")"; +void ChartToPromela::writeBitClearMacro(std::ostream& stream) { + stream << "/** clearing all bits of a */" << std::endl; + stream << "#define " << _prefix << "TRANS_CLEAR(a) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = false; \\" << std::endl; + } + stream << std::endl; + stream << "#define " << _prefix << "STATES_CLEAR(a) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = false; \\" << std::endl; + } + stream << std::endl; + } void ChartToPromela::printBitArray(std::ostream& stream, @@ -411,46 +463,45 @@ void ChartToPromela::printBitArray(std::ostream& stream, void ChartToPromela::writeMacros(std::ostream& stream) { stream << "/* machine state flags */" << std::endl; - stream << "#define USCXML_CTX_PRISTINE 0" << std::endl; - stream << "#define USCXML_CTX_SPONTANEOUS 1" << std::endl; - stream << "#define USCXML_CTX_INITIALIZED 2" << std::endl; - stream << "#define USCXML_CTX_TOP_LEVEL_FINAL 3" << std::endl; - stream << "#define USCXML_CTX_TRANSITION_FOUND 4" << std::endl; - stream << "#define USCXML_CTX_FINISHED 5" << std::endl; + stream << "#define USCXML_CTX_PRISTINE 0 /* can be out-factored */" << std::endl; + stream << "#define USCXML_CTX_SPONTANEOUS 1" << std::endl; + stream << "#define USCXML_CTX_TOP_LEVEL_FINAL 2" << std::endl; + stream << "#define USCXML_CTX_TRANSITION_FOUND 3" << std::endl; + stream << "#define USCXML_CTX_FINISHED 4" << std::endl; + stream << "#define USCXML_CTX_DEQUEUE_EXTERNAL 5" << std::endl; stream << std::endl; - stream << "#define USCXML_TRANS_SPONTANEOUS 0" << std::endl; - stream << "#define USCXML_TRANS_TARGETLESS 1" << std::endl; - stream << "#define USCXML_TRANS_INTERNAL 2" << std::endl; - stream << "#define USCXML_TRANS_HISTORY 3" << std::endl; - stream << "#define USCXML_TRANS_INITIAL 4" << std::endl; + stream << "#define USCXML_TRANS_SPONTANEOUS 0" << std::endl; + stream << "#define USCXML_TRANS_TARGETLESS 1" << std::endl; + stream << "#define USCXML_TRANS_INTERNAL 2" << std::endl; + stream << "#define USCXML_TRANS_HISTORY 3" << std::endl; + stream << "#define USCXML_TRANS_INITIAL 4" << std::endl; stream << std::endl; - stream << "#define USCXML_STATE_ATOMIC 0" << std::endl; - stream << "#define USCXML_STATE_PARALLEL 1" << std::endl; - stream << "#define USCXML_STATE_COMPOUND 2" << std::endl; - stream << "#define USCXML_STATE_FINAL 3" << std::endl; - stream << "#define USCXML_STATE_HISTORY_DEEP 4" << std::endl; - stream << "#define USCXML_STATE_HISTORY_SHALLOW 5" << std::endl; - stream << "#define USCXML_STATE_INITIAL 6" << std::endl; - stream << "#define USCXML_STATE_HAS_HISTORY 7" << std::endl; + stream << "#define USCXML_STATE_ATOMIC 0" << std::endl; + stream << "#define USCXML_STATE_PARALLEL 1" << std::endl; + stream << "#define USCXML_STATE_COMPOUND 2" << std::endl; + stream << "#define USCXML_STATE_FINAL 3" << std::endl; + stream << "#define USCXML_STATE_HISTORY_DEEP 4" << std::endl; + stream << "#define USCXML_STATE_HISTORY_SHALLOW 5" << std::endl; + stream << "#define USCXML_STATE_INITIAL 6" << std::endl; + stream << "#define USCXML_STATE_HAS_HISTORY 7" << std::endl; stream << std::endl; - stream << "#define USCXML_ERR_OK 0" << std::endl; - stream << "#define USCXML_ERR_DONE 1" << std::endl; + stream << "#define USCXML_ERR_OK 0" << std::endl; + stream << "#define USCXML_ERR_DONE 1" << std::endl; stream << std::endl; - stream << "#define USCXML_EVENT_SPONTANEOUS 0" << std::endl; + stream << "#define USCXML_EVENT_SPONTANEOUS 0" << std::endl; stream << std::endl; - stream << "#define TRACE_EXECUTION 1" << std::endl; + stream << "#define TRACE_EXECUTION 1" << std::endl; stream << std::endl; - } -void ChartToPromela::writeTypeDefs(std::ostream& stream) { - stream << "/* type definitions */" << std::endl; - PromelaCodeAnalyzer::PromelaTypedef typeDefs = _analyzer.getTypes(); +void ChartToPromela::writeCommonTypeDefs(std::ostream& stream) { + stream << "/* common type definitions */" << std::endl; + PromelaCodeAnalyzer::PromelaTypedef typeDefs = _analyzer->getTypes(); if (typeDefs.types.size() == 0) return; @@ -477,23 +528,27 @@ void ChartToPromela::writeTypeDefs(std::ostream& stream) { stream << "typedef " << currDef.name << " {" << std::endl; if (currDef.name.compare("_event_t") ==0) { - if (_analyzer.usesEventField("delay")) { + if (_analyzer->usesEventField("delay")) { // make sure delay is the first member for sorted enqueuing to work - stream << " int delay;" << std::endl; + stream << " " << declForRange("delay", 0, _analyzer->largestDelay, true) << ";" << std::endl; #if NEW_DELAY_RESHUFFLE #else - stream << " int seqNr;" << std::endl; + stream << " short seqNr;" << std::endl; #endif } - stream << " int name;" << std::endl; - if (_analyzer.usesEventField("invokeid")) { - stream << " int invokeid;" << std::endl; + stream << " " << declForRange("name", 0, _analyzer->getTrie().lastIndex, true) << ";" << std::endl; + if (_analyzer->usesEventField("invokeid")) { + stream << " " << declForRange("invokeid", 0, _machinesAll->size() + 1, true) << ";" << std::endl; + } + if (_analyzer->usesEventField("origin")) { + stream << " " << declForRange("origin", 0, _machinesAll->size() + 1, true) << ";" << std::endl; } } for (std::map::iterator tIter = currDef.types.begin(); tIter != currDef.types.end(); tIter++) { if (currDef.name.compare("_event_t") == 0 && (tIter->first.compare("name") == 0 || tIter->first.compare("seqNr") == 0 || tIter->first.compare("invokeid") == 0 || + tIter->first.compare("origin") == 0 || tIter->first.compare("delay") == 0)) { // special treatment for _event continue; } @@ -522,80 +577,103 @@ void ChartToPromela::writeTypeDefs(std::ostream& stream) { } +void ChartToPromela::writeTypeDefs(std::ostream& stream) { + stream << "/* custom type definitions for " << _prefix << " */" << std::endl; + +} + +void ChartToPromela::writeCommonVariables(std::ostream& stream) { + stream << "hidden int tmpIndex;" << std::endl; + if (_analyzer->usesComplexEventStruct()) { + stream << "hidden _event_t tmpE;" << std::endl; + } else { + stream << "hidden int tmpE;" << std::endl; + } + + if (_analyzer->hasIndexLessLoops()) + stream << "hidden int _index; /* helper for indexless foreach loops */" << std::endl; + + if (_analyzer->usesEventField("sendid")) + stream << "hidden int _lastSendId = 0; /* sequential counter for send ids */" << std::endl; + + if (_analyzer->usesEventField("delay")) + stream << "hidden short _lastSeqId = 0; /* sequential counter for delayed events */" << std::endl; + stream << std::endl; + +} -void ChartToPromela::writeTypes(std::ostream& stream) { - stream << "/* type definitions and global variables */" << std::endl; +void ChartToPromela::writeVariables(std::ostream& stream) { + stream << "/* custom definitions and global variables */" << std::endl; stream << "bool " << _prefix << "flags[6];" << std::endl; stream << "bool " << _prefix << "config[" << _states.size() << "];" << std::endl; stream << "bool " << _prefix << "history[" << _states.size() << "];" << std::endl; stream << "bool " << _prefix << "invocations[" << _states.size() << "];" << std::endl; - stream << "bool " << _prefix << "initialized_data[" << _states.size() << "];" << std::endl; +// stream << "bool " << _prefix << "initialized_data[" << _states.size() << "];" << std::endl; size_t tolerance = 6; - if (_analyzer.usesComplexEventStruct()) { + if (_analyzer->usesComplexEventStruct()) { // event is defined with the typedefs - stream << "_event_t " << _prefix << "_event; /* current event */" << std::endl; + stream << "hidden _event_t " << _prefix << "_event; /* current event */" << std::endl; + stream << "hidden _event_t " << _prefix << "_tmpE; /* temporary event for send */" << std::endl; stream << "chan " << _prefix << "iQ = [" << (std::max)(_internalQueueLength, (size_t)1) << "] of {_event_t} /* internal queue */" << std::endl; stream << "chan " << _prefix << "eQ = [" << _externalQueueLength + tolerance << "] of {_event_t} /* external queue */" << std::endl; if (_allowEventInterleaving) stream << "chan " << _prefix << "tmpQ = [" << (std::max)(_externalQueueLength + tolerance, (size_t)1) << "] of {_event_t} /* temporary queue for external events in transitions */" << std::endl; } else { - stream << "unsigned " << _prefix << "_event : " << BIT_WIDTH(_analyzer.getLiterals().size() + 1) << "; /* current event */" << std::endl; + stream << "unsigned " << _prefix << "_event : " << BIT_WIDTH(_analyzer->getLiterals().size() + 1) << "; /* current event */" << std::endl; + stream << "hidden unsigned " << _prefix << "_tmpE : " << BIT_WIDTH(_analyzer->getLiterals().size() + 1) << "; /* temporary event for send */" << std::endl; stream << "chan " << _prefix << "iQ = [" << (std::max)(_internalQueueLength, (size_t)1) << "] of {int} /* internal queue */" << std::endl; stream << "chan " << _prefix << "eQ = [" << _externalQueueLength + tolerance << "] of {int} /* external queue */" << std::endl; if (_allowEventInterleaving) stream << "chan " << _prefix << "tmpQ = [" << (std::max)(_externalQueueLength + tolerance, (size_t)1) << "] of {int} /* temporary queue for external events in transitions */" << std::endl; } - stream << std::endl; - stream << "typedef transition {" << std::endl; - stream << " unsigned source : " << BIT_WIDTH(_states.size()) << ";" << std::endl; - stream << " bool target[" << _states.size() << "];" << std::endl; - stream << " bool type[5];" << std::endl; - stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; - stream << " bool exit_set[" << _states.size() << "];" << std::endl; - stream << "}" << std::endl; - if (_transitions.size() > 0) { - stream << "hidden transition " << _prefix << "transitions[" << toStr(_transitions.size()) << "];" << std::endl; + if (_transitions.size() > 0) { + stream << std::endl; + stream << "typedef " << _prefix << "transition_t {" << std::endl; + stream << " unsigned source : " << BIT_WIDTH(_states.size()) << ";" << std::endl; + stream << " bool target[" << _states.size() << "];" << std::endl; + stream << " bool type[5];" << std::endl; + stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; + stream << " bool exit_set[" << _states.size() << "];" << std::endl; + stream << "}" << std::endl; + stream << "hidden " << _prefix << "transition_t " << _prefix << "transitions[" << toStr(_transitions.size()) << "];" << std::endl; + stream << std::endl; } - stream << std::endl; - stream << "typedef state {" << std::endl; - stream << " unsigned parent : " << BIT_WIDTH(_states.size()) << ";" << std::endl; - stream << " bool children[" << _states.size() << "];" << std::endl; - stream << " bool completion[" << _states.size() << "];" << std::endl; - stream << " bool ancestors[" << _states.size() << "];" << std::endl; - stream << " bool type[8];" << std::endl; - stream << "}" << std::endl; - if (_states.size() > 0) { - stream << "hidden state " << _prefix << "states[" << toStr(_states.size()) << "];" << std::endl; + if (_states.size() > 0) { + stream << "typedef " << _prefix << "state_t {" << std::endl; + stream << " unsigned parent : " << BIT_WIDTH(_states.size()) << ";" << std::endl; + stream << " bool children[" << _states.size() << "];" << std::endl; + stream << " bool completion[" << _states.size() << "];" << std::endl; + stream << " bool ancestors[" << _states.size() << "];" << std::endl; + stream << " bool type[8];" << std::endl; + stream << "}" << std::endl; + stream << "hidden " << _prefix << "state_t " << _prefix << "states[" << toStr(_states.size()) << "];" << std::endl; + stream << std::endl; } - stream << std::endl; - stream << "hidden int tmpIndex;" << std::endl; - if (_analyzer.usesComplexEventStruct()) { - stream << "hidden _event_t tmpE;" << std::endl; - } else { - stream << "hidden int tmpE;" << std::endl; + stream << "typedef " << _prefix << "ctx_t {" << std::endl; + if (_transitions.size() > 0) { + stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; + stream << " bool trans_set[" << _transitions.size() << "];" << std::endl; } - - if (_analyzer.hasIndexLessLoops()) - stream << "hidden int " << _prefix << "_index; /* helper for indexless foreach loops */" << std::endl; - - if (_analyzer.usesEventField("sendid")) - stream << "hidden int _lastSendId = 0; /* sequential counter for send ids */" << std::endl; - if (_analyzer.usesEventField("delay")) - stream << "hidden int _lastSeqId = 0; /* sequential counter for delayed events */" << std::endl; - + stream << " bool target_set[" << _states.size() << "];" << std::endl; + stream << " bool exit_set[" << _states.size() << "];" << std::endl; + stream << " bool entry_set[" << _states.size() << "];" << std::endl; + stream << " bool tmp_states[" << _states.size() << "];" << std::endl; + stream << "}" << std::endl; + stream << "hidden " << _prefix << "ctx_t " << _prefix << "ctx;" << std::endl; + stream << std::endl; stream << std::endl; std::set processedIdentifiers; // automatic types std::list datas = DOMUtils::inDocumentOrder({ XML_PREFIX(_scxml).str() + "data" }, _scxml, false); - PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer.getTypes(); + PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes(); for (auto data : datas) { std::string identifier = (HAS_ATTR_CAST(data, "id") ? ATTR_CAST(data, "id") : ""); @@ -665,24 +743,40 @@ void ChartToPromela::writeTypes(std::ostream& stream) { typeIter++; } + if (_analyzer->getTypes().types.find("_ioprocessors") != _analyzer->getTypes().types.end()) { + stream << "hidden _ioprocessors_t " << _prefix << "_ioprocessors;" << std::endl; + _varInitializers.push_front("_ioprocessors.scxml.location = " + (_invokerid.size() > 0 ? _analyzer->macroForLiteral(_invokerid) : "1") + ";"); + } + + stream << "hidden int " << _prefix << "procid; /* the process id running this machine */" << std::endl; + } + void ChartToPromela::writeStrings(std::ostream& stream) { stream << "/* states, events and string literals */" << std::endl; - std::set literals = _analyzer.getLiterals(); + std::set literals = _analyzer->getLiterals(); { for (size_t i = 0; i < _states.size(); i++) { if (HAS_ATTR(_states[i], "id")) { - stream << "#define " << _prefix << _analyzer.macroForLiteral(ATTR(_states[i], "id")) << " " << toStr(i); + stream << "#define " << _prefix << _analyzer->macroForLiteral(ATTR(_states[i], "id")) << " " << toStr(i); stream << " /* index for state " << ATTR(_states[i], "id") << " */" << std::endl; } } } + { + size_t i = 0; + for (auto machine : *_machinesAll) { + i++; + stream << "#define " << _analyzer->macroForLiteral(machine.second->_invokerid) << " " << toStr(i); + stream << " /* index for invoker " << machine.second->_invokerid << " */" << std::endl; + } + } for (auto literal : literals) { - stream << "#define " << _analyzer.macroForLiteral(literal) << " " << _analyzer.indexForLiteral(literal) << " /* " << literal << " */" << std::endl; + stream << "#define " << _analyzer->macroForLiteral(literal) << " " << _analyzer->indexForLiteral(literal) << " /* " << literal << " */" << std::endl; } } @@ -703,19 +797,6 @@ void ChartToPromela::writeTransitions(std::ostream& stream) { stream << " " << _prefix << "transitions[" << toStr(i) << "].target[" << toStr(j) << "] = 1;" << std::endl; } } - -#if 0 - /** events */ - if (HAS_ATTR(transition, "event")) { - std::list events = tokenize(ATTR(transition, "event"), ' ', true); - for(auto& event : events) { - auto trieNodes = _analyzer.getTrie().getWordsWithPrefix(event); - for(auto trieNode : trieNodes) { - stream << " " << _prefix << "transitions[" << toStr(i) << "].event[" << _analyzer.macroForLiteral(trieNode->value) << "] = 1;" << std::endl; - } - } - } -#endif if (!HAS_ATTR(transition, "event")) stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_SPONTANEOUS] = 1;" << std::endl; @@ -816,10 +897,65 @@ void ChartToPromela::writeStates(std::ostream& stream) { } } +void ChartToPromela::writeRaiseDoneDate(std::ostream& stream, const DOMElement* donedata, size_t indent) { + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } -void ChartToPromela::writeHelpers(std::ostream& stream) { - + std::list contents = DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "content", donedata); + if (contents.size() > 0) { + auto& content = contents.front(); + + // an expression + if (HAS_ATTR(content, "expr")) { + stream << dataToAssignments(_prefix + "_tmpE.data", Data(ADAPT_SRC(ATTR(content, "expr")), Data::INTERPRETED)); + return; + } + + std::list textChilds = DOMUtils::filterChildType(DOMNode::TEXT_NODE, content); + std::stringstream ss; + for (auto text : textChilds) { + ss << X(text->getNodeValue()).str(); + } + + // text childs + std::string value = boost::trim_copy(ss.str()); + if (value.size() > 0) { + Data d = Data::fromJSON(value); + if (!d.empty()) { + stream << dataToAssignments(_prefix + "_tmpE.data", d); + } else { + if (!isNumeric(value.c_str(), 10)) { + stream << dataToAssignments(_prefix + "_tmpE.data", Data(value, Data::VERBATIM)); + } else { + stream << dataToAssignments(_prefix + "_tmpE.data", Data(value, Data::INTERPRETED)); + } + } + return; + } + } + + std::list params = DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "param", donedata); + if (params.size() > 0) { + Data d; + for (auto& param : params) { + if (!HAS_ATTR(param, "name")) + continue; + std::string name = ATTR(param, "name"); + std::string expr; + if (HAS_ATTR(param, "expr")) { + expr = ATTR(param, "expr"); + } else if (HAS_ATTR(param, "location")) { + expr = ATTR(param, "location"); + } + + d[name] = Data(expr, Data::INTERPRETED); + } + stream << dataToAssignments(_prefix + "_tmpE.data", d); + } + } void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent) { @@ -890,9 +1026,9 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO } } else if(TAGNAME(element) == "foreach") { - stream << padding << "for (" << _prefix << (HAS_ATTR(element, "index") ? ATTR(element, "index") : "_index") << " in " << _prefix << ATTR(element, "array") << ") {" << std::endl; + stream << padding << "for (" << (HAS_ATTR(element, "index") ? _prefix + ATTR(element, "index") : "_index") << " in " << _prefix << ATTR(element, "array") << ") {" << std::endl; if (HAS_ATTR(element, "item")) { - stream << padding << " " << _prefix << ATTR(element, "item") << " = " << _prefix << ATTR(element, "array") << "[" << _prefix << (HAS_ATTR(element, "index") ? ATTR(element, "index") : "_index") << "];" << std::endl; + stream << padding << " " << _prefix << ATTR(element, "item") << " = " << _prefix << ATTR(element, "array") << "[" << (HAS_ATTR(element, "index") ? _prefix + ATTR(element, "index") : "_index") << "];" << std::endl; } const XERCESC_NS::DOMNode* child = element->getFirstChild(); while(child) { @@ -916,10 +1052,15 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO std::list assignTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, element, true); assert(assignTexts.size() > 0); - stream << beautifyIndentation(ADAPT_SRC(boost::trim_copy(X(assignTexts.front()->getNodeValue()).str())), indent) << std::endl; + stream << beautifyIndentation(ADAPT_SRC(boost::trim_copy(X(assignTexts.front()->getNodeValue()).str())), indent + 1) << std::endl; } else if(TAGNAME(element) == "send" || TAGNAME(element) == "raise") { std::string targetQueue; + + stream << padding << "if" << std::endl; + stream << padding << ":: !" << _prefix << "flags[USCXML_CTX_FINISHED] || " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + + padding += " "; std::string insertOp = "!"; if (TAGNAME(element) == "raise") { targetQueue = _prefix + "iQ"; @@ -933,67 +1074,71 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO targetQueue = _prefix + "iQ"; } else if (ATTR(element, "target").compare("#_parent") == 0) { targetQueue = _parent->_prefix + "eQ"; - } else if (boost::starts_with(ATTR(element, "target"), "#_") && _machinesPerId.find(ATTR(element, "target").substr(2)) != _machinesPerId.end()) { - targetQueue = _machines[_machinesPerId[ATTR(element, "target").substr(2)]]->_prefix + "eQ"; + } else if (boost::starts_with(ATTR(element, "target"), "#_") && _machinesAllPerId->find(ATTR(element, "target").substr(2)) != _machinesAllPerId->end()) { + targetQueue = (*_machinesAll)[(*_machinesAllPerId)[ATTR(element, "target").substr(2)]]->_prefix + "eQ"; } if (targetQueue.length() > 0) { // this is for our external queue std::string event; if (HAS_ATTR(element, "event")) { - event = _analyzer.macroForLiteral(ATTR(element, "event")); + event = _analyzer->macroForLiteral(ATTR(element, "event")); } else if (HAS_ATTR(element, "eventexpr")) { event = ADAPT_SRC(ATTR(element, "eventexpr")); } - if (_analyzer.usesComplexEventStruct()) { + if (_analyzer->usesComplexEventStruct()) { stream << padding << "{" << std::endl; - std::string typeReset = _analyzer.getTypeReset(_prefix + "_event", _analyzer.getType("_event"), padding + " "); + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), indent + 2); std::stringstream typeAssignSS; - typeAssignSS << padding << " " << _prefix << EVENT_NAME << " = " << event << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.name = " << event << ";" << std::endl; if (HAS_ATTR(element, "idlocation")) { typeAssignSS << padding << " /* idlocation */" << std::endl; typeAssignSS << padding << " _lastSendId = _lastSendId + 1;" << std::endl; typeAssignSS << padding << " " << _prefix << ATTR(element, "idlocation") << " = _lastSendId;" << std::endl; - typeAssignSS << padding << " " << _prefix << "_event.sendid = _lastSendId;" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.sendid = _lastSendId;" << std::endl; typeAssignSS << padding << " if" << std::endl; typeAssignSS << padding << " :: _lastSendId == 2147483647 -> _lastSendId = 0;" << std::endl; typeAssignSS << padding << " :: else -> skip;" << std::endl; typeAssignSS << padding << " fi;" << std::endl; } else if (HAS_ATTR(element, "id")) { - typeAssignSS << padding << " " << _prefix << "_event.sendid = " << _analyzer.macroForLiteral(ATTR(element, "id")) << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.sendid = " << _analyzer->macroForLiteral(ATTR(element, "id")) << ";" << std::endl; } - if (_invokerid.length() > 0) { // do not send invokeid if we send / raise to ourself - typeAssignSS << padding << " " << _prefix << "_event.invokeid = " << _analyzer.macroForLiteral(_invokerid) << ";" << std::endl; + if (_analyzer->usesEventField("invokeid") && _parent != NULL) { // do not send invokeid if we send / raise to ourself + typeAssignSS << padding << " " << _prefix << "_tmpE.invokeid = " << _analyzer->macroForLiteral(_invokerid) << ";" << std::endl; } - if (_analyzer.usesEventField("origintype") && !boost::ends_with(targetQueue, "iQ")) { - typeAssignSS << padding << " " << _prefix << "_event.origintype = " << _analyzer.macroForLiteral("http://www.w3.org/TR/scxml/#SCXMLEventProcessor") << ";" << std::endl; + if (_analyzer->usesEventField("origintype") && !boost::ends_with(targetQueue, "iQ")) { + typeAssignSS << padding << " " << _prefix << "_tmpE.origintype = " << _analyzer->macroForLiteral("http://www.w3.org/TR/scxml/#SCXMLEventProcessor") << ";" << std::endl; } + + if (_analyzer->usesEventField("origin") && !boost::ends_with(targetQueue, "iQ")) { + typeAssignSS << padding << " " << _prefix << "_tmpE.origin = " << _analyzer->macroForLiteral(_invokerid) << ";" << std::endl; + } - if (_analyzer.usesEventField("delay")) { + if (_analyzer->usesEventField("delay")) { #if NEW_DELAY_RESHUFFLE #else - insertOp += "!"; +// insertOp += "!"; typeAssignSS << padding << " _lastSeqId = _lastSeqId + 1;" << std::endl; #endif if (HAS_ATTR_CAST(element, "delay")) { - typeAssignSS << padding << " " << _prefix << "_event.delay = " << ATTR_CAST(element, "delay") << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.delay = " << ATTR_CAST(element, "delay") << ";" << std::endl; } else if (HAS_ATTR_CAST(element, "delayexpr")) { - typeAssignSS << padding << " " << _prefix << "_event.delay = " << ADAPT_SRC(ATTR_CAST(element, "delayexpr")) << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.delay = " << ADAPT_SRC(ATTR_CAST(element, "delayexpr")) << ";" << std::endl; } else { - typeAssignSS << padding << " " << _prefix << "_event.delay = 0;" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.delay = 0;" << std::endl; } #if NEW_DELAY_RESHUFFLE #else - typeAssignSS << padding << " " << _prefix << "_event.seqNr = _lastSeqId;" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.seqNr = _lastSeqId;" << std::endl; #endif } - if (_analyzer.usesEventField("type")) { - std::string eventType = (targetQueue.compare("iQ!") == 0 ? _analyzer.macroForLiteral("internal") : _analyzer.macroForLiteral("external")); - typeAssignSS << padding << " " << _prefix << "_event.type = " << eventType << ";" << std::endl; + if (_analyzer->usesEventField("type")) { + std::string eventType = (targetQueue.compare("iQ!") == 0 ? _analyzer->macroForLiteral("internal") : _analyzer->macroForLiteral("external")); + typeAssignSS << padding << " " << _prefix << "_tmpE.type = " << eventType << ";" << std::endl; } std::list sendParams = DOMUtils::filterChildElements(XML_PREFIX(element).str() + "param", element); @@ -1001,14 +1146,14 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO std::string sendNameList = ATTR(element, "namelist"); if (sendParams.size() > 0) { for (auto sendParam : sendParams) { - typeAssignSS << padding << " " << _prefix << "_event.data." << ATTR(sendParam, "name") << " = " << ADAPT_SRC(ATTR(sendParam, "expr")) << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.data." << ATTR(sendParam, "name") << " = " << ADAPT_SRC(ATTR(sendParam, "expr")) << ";" << std::endl; } } if (sendNameList.size() > 0) { std::list nameListIds = tokenize(sendNameList); std::list::iterator nameIter = nameListIds.begin(); while(nameIter != nameListIds.end()) { - typeAssignSS << padding << " " << _prefix << "_event.data." << *nameIter << " = " << ADAPT_SRC(*nameIter) << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.data." << *nameIter << " = " << ADAPT_SRC(*nameIter) << ";" << std::endl; nameIter++; } } @@ -1018,12 +1163,12 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO if (contentElem->hasChildNodes() && contentElem->getFirstChild()->getNodeType() == DOMNode::TEXT_NODE) { std::string content = spaceNormalize(X(contentElem->getFirstChild()->getNodeValue()).str()); if (!isNumeric(content.c_str(), 10)) { - typeAssignSS << padding << " " << _prefix << "_event.data = " << _analyzer.macroForLiteral(content) << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.data = " << _analyzer->macroForLiteral(content) << ";" << std::endl; } else { - typeAssignSS << padding << " " << _prefix << "_event.data = " << content << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.data = " << content << ";" << std::endl; } } else if (HAS_ATTR(contentElem, "expr")) { - typeAssignSS << padding << " " << _prefix << "_event.data = " << ADAPT_SRC(ATTR(contentElem, "expr")) << ";" << std::endl; + typeAssignSS << padding << " " << _prefix << "_tmpE.data = " << ADAPT_SRC(ATTR(contentElem, "expr")) << ";" << std::endl; } } @@ -1053,563 +1198,584 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO } stream << typeAssignSS.str(); + stream << "#if TRACE_EXECUTION" << std::endl; + if (_analyzer->usesComplexEventStruct()) { + stream << "printf(\"%d: Sending " << event << " (%d) to " << targetQueue << "\\n\", _pid, " << _prefix << TMP_EVENT_NAME << " );" << std::endl; + } else { + stream << "printf(\"Sending " << event << " (%d) to " << targetQueue << "\\n\", " << _prefix << TMP_EVENT_NAME << " );" << std::endl; + } + stream << "#endif" << std::endl; + stream << std::endl; - stream << padding << " " << targetQueue << insertOp << _prefix <<"_event;" << std::endl; + stream << padding << " " << targetQueue << insertOp << _prefix <<"_tmpE;" << std::endl; -#if NEW_DELAY_RESHUFFLE if (_analyzer->usesEventField("delay") && !boost::ends_with(targetQueue, "iQ")) { stream << padding << " insertWithDelay(" << targetQueue << ");" << std::endl; } -#endif stream << padding << "}" << std::endl; } else { stream << padding << targetQueue << insertOp << event << ";" << std::endl; } } + stream << padding << "skip;" << std::endl; + + padding = padding.substr(0, padding.size() - 2); + stream << padding << "}" << std::endl; + stream << padding << ":: else -> skip;" << std::endl; + stream << padding << "fi" << std::endl; + } else if(TAGNAME(element) == "cancel") { if (HAS_ATTR(element, "sendid")) { - stream << padding << "cancelSendId(" << _analyzer.macroForLiteral(ATTR(element, "sendid")) << ", " << (_invokerid.size() > 0 ? _analyzer.macroForLiteral(_invokerid) : "0") << ");" << std::endl; + stream << " " << padding << "cancelSendId(" << _analyzer->macroForLiteral(ATTR(element, "sendid")) << "," << _analyzer->macroForLiteral(_invokerid) << ");" << std::endl; } else if (HAS_ATTR(element, "sendidexpr")) { - stream << padding << "cancelSendId(" << ADAPT_SRC(ATTR(element, "sendidexpr")) << ", " << (_invokerid.size() > 0 ? _analyzer.macroForLiteral(_invokerid) : "0") << ");" << std::endl; + stream << " " << padding << "cancelSendId(" << ADAPT_SRC(ATTR(element, "sendidexpr")) << "," << _analyzer->macroForLiteral(_invokerid) << ");" << std::endl; } } else { std::cerr << "'" << TAGNAME(element) << "' not supported" << std::endl << element << std::endl; assert(false); } - - } void ChartToPromela::writeFSM(std::ostream& stream) { stream << "/* machine microstep function */" << std::endl; - stream << "#define USCXML_NUMBER_STATES " << _states.size() << std::endl; - stream << "#define USCXML_NUMBER_TRANS " << _transitions.size() << std::endl; + stream << "#define " << _prefix << "USCXML_NUMBER_STATES " << _states.size() << std::endl; + stream << "#define " << _prefix << "USCXML_NUMBER_TRANS " << _transitions.size() << std::endl; + stream << std::endl; stream << "proctype " << _prefix << "step() { atomic {" << std::endl; - stream << std::endl; + stream << std::endl; + stream << _prefix << "procid = _pid;" << std::endl; + + size_t largestBitWidth = (_states.size() > _transitions.size() ? + BIT_WIDTH(_states.size() + 1) : + BIT_WIDTH(_transitions.size() + 1)); + + stream << "unsigned"; + stream << " i : " << largestBitWidth << ", "; + stream << " j : " << largestBitWidth << ", "; + stream << " k : " << largestBitWidth << ";" << std::endl; + stream << std::endl; + + std::list globalScripts = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "script", _scxml, false); + if (globalScripts.size() > 0) { + stream << "/* run global scripts */" << std::endl; + for (auto globalScript : globalScripts) { + TRACE_EXECUTION("Processing executable content for global script"); + + writeExecContent(stream, globalScript, 2); + } + stream << std::endl; + } + + stream << std::endl; stream << "/* ---------------------------- */" << std::endl; - stream << "MICROSTEP:" << std::endl; + stream << _prefix << "MICROSTEP:" << std::endl; stream << "do" << std::endl; stream << ":: !" << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; - stream << std::endl; + stream << " /* Run until machine is finished */" << std::endl; + stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Taking a step\\n\");" << std::endl; - stream << "#endif" << std::endl; + TRACE_EXECUTION("Taking a step"); + + stream << " /* Dequeue an event */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] = false;" << std::endl; + stream << " if" << std::endl; + stream << " ::" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; + stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; + TRACE_EXECUTION("Trying with a spontaneous event"); - size_t largestBitWidth = (_states.size() > _transitions.size() ? - BIT_WIDTH(_states.size() + 1) : - BIT_WIDTH(_transitions.size() + 1)); + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: len(" << _prefix << "iQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; + + TRACE_EXECUTION("Deqeued an internal event"); - stream << " unsigned"; - stream << " i : " << largestBitWidth << ", "; - stream << " j : " << largestBitWidth << ", "; - stream << " k : " << largestBitWidth << ";" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] = true;" << std::endl; + stream << " }" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; - stream << " int err = USCXML_ERR_OK;" << std::endl; + stream << std::endl; - stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; - stream << " bool trans_set[" << _transitions.size() << "];" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] -> {" << std::endl; + stream << " /* manage invocations */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " /* uninvoke */" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << std::endl; - stream << " bool target_set[" << _states.size() << "];" << std::endl; - stream << " bool exit_set[" << _states.size() << "];" << std::endl; - stream << " bool entry_set[" << _states.size() << "];" << std::endl; - stream << " bool tmp_states[" << _states.size() << "];" << std::endl; - stream << std::endl; + TRACE_EXECUTION_V("Uninvoking in state %d", "i"); -#if 0 - stream << " if" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED]" << std::endl; - stream << " ACCEPT: {" << std::endl; - stream << " false;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; + stream << " if" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Machine not finished\\n\");" << std::endl; - stream << "#endif" << std::endl; -#endif + for (size_t i = 0; i < _states.size(); i++) { + std::list invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); + if (invokers.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + for (auto invokeElem : invokers) { + if (_machinesNested.find(invokeElem) == _machinesNested.end()) + continue; + ChartToPromela* invoker = _machinesNested[invokeElem]; + stream << " " << invoker->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + } + stream << " }" << std::endl; + } + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; -#if 0 - stream << " if (ctx->flags & USCXML_CTX_TOP_LEVEL_FINAL) -> {" << std::endl; - stream << " /* exit all remaining states */" << std::endl; - stream << " i = USCXML_NUMBER_STATES;" << std::endl; - stream << " while(i-- > 0) {" << std::endl; - stream << " if (BIT_HAS(i, ctx->config)) {" << std::endl; - stream << " /* call all on exit handlers */" << std::endl; - stream << " if (USCXML_GET_STATE(i).on_exit != NULL) {" << std::endl; - stream << " if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)" << std::endl; - stream << " return err;" << std::endl; - stream << " }" << std::endl; - // stream << " BIT_CLEAR(i, ctx->config);" << std::endl; - stream << " }" << std::endl; - stream << " if (BIT_HAS(i, ctx->invocations)) {" << std::endl; - stream << " if (USCXML_GET_STATE(i).invoke != NULL)" << std::endl; - stream << " USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1);" << std::endl; - stream << " BIT_CLEAR(i, ctx->invocations);" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " ctx->flags |= USCXML_CTX_FINISHED;" << std::endl; - stream << " return USCXML_ERR_DONE;" << std::endl; - stream << " }" << std::endl; - stream << std::endl; - -#endif - - stream << " if" << std::endl; - stream << " ::" << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Top level final state reached\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " /* exit all remaining states */" << std::endl; - stream << " i = USCXML_NUMBER_STATES;" << std::endl; - stream << " do" << std::endl; - stream << " :: i > 0 -> {" << std::endl; - stream << " i = i - 1;" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "config[i] -> {" << std::endl; - stream << " /* TODO: call all on exit handlers */" << std::endl; - stream << " skip;" << std::endl; - stream << " " << std::endl; + stream << " " << _prefix << "invocations[i] = false;" << std::endl; + + stream << " skip;" << std::endl; stream << " }" << std::endl; stream << " :: else -> skip;" << std::endl; stream << " fi;" << std::endl; stream << std::endl; + + + stream << " /* invoke */" << std::endl; stream << " if" << std::endl; - stream << " :: " << _prefix << "invocations[i] -> {" << std::endl; - stream << " /* TODO: cancel invocations */" << std::endl; - stream << " skip;" << std::endl; - stream << " " << std::endl; + stream << " :: " << _prefix << "config[i] && !" << _prefix << "invocations[i] -> {" << std::endl; + stream << " if" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + std::list invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); + if (invokers.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + for (auto invokeElem : invokers) { + if (_machinesNested.find(invokeElem) == _machinesNested.end()) + continue; + ChartToPromela* invoker = _machinesNested[invokeElem]; + + // pass variables via namelist + if (HAS_ATTR(invokeElem, "namelist")) { + std::list namelist = tokenize(ATTR_CAST(invokeElem, "namelist")); + for (auto name : namelist) { + if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { + stream << " " << invoker->_prefix << name << " = " << _prefix << name << ";" << std::endl; + } + } + } + + // pass variables via params + std::list invokeParams = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + + "param", invokeElem); + for (auto param : invokeParams) { + std::string name = ATTR(param, "name"); + std::string expression = ATTR(param, "expr"); + if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { + stream << " " << invoker->_prefix << name << " = " << ADAPT_SRC(expression) << ";" << std::endl; + } + } + + TRACE_EXECUTION_V("Invoking in state %d", "i"); + + stream << " run " << invoker->_prefix << "step() priority 20;" << std::endl; + if (HAS_ATTR(invokeElem, "idlocation")) { + stream << " " << ADAPT_SRC(ATTR(invokeElem, "idlocation")) << " = "; + stream << _analyzer->macroForLiteral(invoker->_invokerid) << ";" << std::endl; + } + + } + stream << " " << _prefix << "invocations[i] = true;" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; stream << " }" << std::endl; stream << " :: else -> skip;" << std::endl; stream << " fi;" << std::endl; + stream << " i = i + 1;" << std::endl; stream << " }" << std::endl; stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Ending machine!\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; - stream << " goto MICROSTEP;" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; + stream << " od;" << std::endl; stream << std::endl; -#if 0 - 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 == USCXML_CTX_PRISTINE) {" << 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 |= USCXML_CTX_SPONTANEOUS | USCXML_CTX_INITIALIZED;" << std::endl; - stream << " goto ESTABLISH_ENTRY_SET;" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif - - stream << " if" << std::endl; - stream << " ::" << _prefix << "flags[USCXML_CTX_PRISTINE] -> {" << std::endl; - stream << " /* run global scripts */" << std::endl; - - std::list globalScripts = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "script", _scxml, false); - for (auto globalScript : globalScripts) { - writeExecContent(stream, globalScript); + if (_analyzer->usesEventField("delay") && _machinesAll->size() > 1) { + stream << " /* Determine machines with smallest delay and set their process priority */" << std::endl; + stream << " scheduleMachines();" << std::endl << std::endl; } - stream << std::endl; - - stream << " /* Enter initial configuration */" << std::endl; - bit_copy(stream, _prefix + "states[0].completion", "target_set", _states.size(), 2); - stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_PRISTINE] = false;" << std::endl; - - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Entering initial default completion\\n\");" << std::endl; - stream << "#endif" << std::endl; - - stream << " goto ESTABLISH_ENTRY_SET;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; - - -#if 0 - stream << "DEQUEUE_EVENT:" << std::endl; - stream << " if (ctx->flags & USCXML_CTX_SPONTANEOUS) {" << std::endl; - stream << " ctx->event = NULL;" << std::endl; - stream << " goto SELECT_TRANSITIONS;" << std::endl; - stream << " }" << std::endl; - stream << " if (ctx->dequeue_internal != NULL && (ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl; - stream << " goto SELECT_TRANSITIONS;" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif - - - stream << "/* ---------------------------- */" << std::endl; - stream << "DEQUEUE_EVENT:" << std::endl; - stream << " if" << std::endl; - stream << " ::" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; - stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Trying with a spontaneuous event\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " goto SELECT_TRANSITIONS;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; + + stream << " /* we may return to find ourselves terminated */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; + stream << " goto " << _prefix << "TERMINATE_MACHINE;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; - stream << " if" << std::endl; - stream << " :: len(" << _prefix << "iQ) != 0 -> {" << std::endl; - stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Deqeued an internal event\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " goto SELECT_TRANSITIONS;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; + + stream << " /* Not sure if this should be before the invocation due to auto-forwarding */" << std::endl; + stream << " if" << std::endl; + stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; + + if (_machinesNested.size() > 0) { + stream << std::endl; + stream << " /* auto-forward event */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + + std::string insertOp = "!"; + if (_analyzer->usesEventField("delay")) { +// insertOp += "!"; + } + + for (auto state : _states) { + std::list invokers = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "invoke", state, false); + if (invokers.size() > 0) { + stream << " :: i == " << ATTR(state, "documentOrder") << " && " << _prefix << "invocations[i] -> { " << std::endl; + for (auto invoker : invokers) { + assert(_machinesNested.find(invoker) != _machinesNested.end()); + if (HAS_ATTR(invoker, "autoforward") && stringIsTrue(ATTR(invoker, "autoforward"))) { + stream << " " << _machinesNested[invoker]->_prefix << "eQ " << insertOp << " " << _prefix << "_event;" << std::endl; + if (_analyzer->usesEventField("delay")) { + stream << " insertWithDelay(" << _machinesNested[invoker]->_prefix << "eQ);" << std::endl; + } + TRACE_EXECUTION("Auto forwarded event"); + } + } + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; -#if 0 - stream << " /* manage invocations */" << std::endl; - stream << " for (i = 0; i < USCXML_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 (USCXML_GET_STATE(i).invoke != NULL)" << std::endl; - stream << " USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(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 (USCXML_GET_STATE(i).invoke != NULL)" << std::endl; - stream << " USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 0);" << std::endl; - stream << " BIT_SET_AT(i, ctx->invocations)" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif + stream << std::endl; + stream << " /* finalize event */" << std::endl; + stream << " if" << std::endl; + + for (auto machine : _machinesNested) { + + stream << " :: " << _prefix << "_event.invokeid == " << _analyzer->macroForLiteral(machine.second->_invokerid) << " -> {" << std::endl; + std::list finalizers = DOMUtils::filterChildElements(XML_PREFIX(machine.first).str() + "finalize", machine.first, false); + + TRACE_EXECUTION("Finalizing event") + + for (auto finalize : finalizers) { + writeExecContent(stream, finalize, 4); + } + stream << " skip" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else -> skip;" << std::endl; + + stream << " fi" << std::endl; - stream << " /* manage invocations */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; - stream << " /* uninvoke */" << std::endl; - stream << " if" << std::endl; - stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; + } + + TRACE_EXECUTION("Deqeued an external event"); - stream << " /* invoke */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "config[i] && !" << _prefix << "invocations[i] -> {" << std::endl; - stream << " skip;" << std::endl; stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - -#if 0 - stream << " if (ctx->dequeue_external != NULL && (ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl; - stream << " goto SELECT_TRANSITIONS;" << std::endl; - stream << " }" << std::endl; - stream << std::endl; - stream << " if (ctx->dequeue_external == NULL) {" << std::endl; - stream << " return USCXML_ERR_DONE;" << std::endl; - stream << " }" << std::endl; - stream << " return USCXML_ERR_IDLE;" << std::endl; - stream << std::endl; -#endif - - stream << " if" << std::endl; - stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; - stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Deqeued an external event\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " goto SELECT_TRANSITIONS;" << std::endl; - stream << " }" << std::endl; // stream << " :: else -> quit;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; - -#if 0 - stream << "SELECT_TRANSITIONS:" << 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 < USCXML_NUMBER_TRANS; i++) {" << std::endl; - stream << " /* never select history or initial transitions automatically */" << std::endl; - stream << " if unlikely(USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL))" << std::endl; - stream << " continue;" << std::endl; - stream << std::endl; - stream << " /* is the transition active? */" << std::endl; - stream << " if (BIT_HAS(USCXML_GET_TRANS(i).source, ctx->config)) {" << std::endl; - stream << " /* is it non-conflicting? */" << std::endl; - stream << " if (!BIT_HAS(i, conflicts)) {" << std::endl; - stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; - stream << " if ((USCXML_GET_TRANS(i).event == NULL && ctx->event == NULL) || " << std::endl; - stream << " (USCXML_GET_TRANS(i).event != NULL && ctx->event != NULL)) {" << std::endl; - stream << " /* is it enabled? */" << std::endl; - stream << " if ((ctx->event == NULL || ctx->is_matched(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) &&" << std::endl; - stream << " (USCXML_GET_TRANS(i).condition == NULL || " << std::endl; - stream << " USCXML_GET_TRANS(i).is_enabled(ctx, &USCXML_GET_TRANS(i)) > 0)) {" << std::endl; - stream << " /* remember that we found a transition */" << std::endl; - stream << " ctx->flags |= USCXML_CTX_TRANSITION_FOUND;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; stream << std::endl; - stream << " /* transitions that are pre-empted */" << std::endl; - stream << " bit_or(conflicts, USCXML_GET_TRANS(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, USCXML_GET_TRANS(i).target, nr_states_bytes);" << std::endl; - stream << std::endl; - stream << " /* states that will be left */" << std::endl; - stream << " bit_or(exit_set, USCXML_GET_TRANS(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 << " }" << std::endl; - stream << " bit_and(exit_set, ctx->config, nr_states_bytes);" << std::endl; - stream << std::endl; -#endif + stream << " d_step { skip;" << std::endl; stream << "/* ---------------------------- */" << std::endl; - stream << "SELECT_TRANSITIONS:" << std::endl; - bit_clear_all(stream, "conflicts", _transitions.size(), 1); - bit_clear_all(stream, "trans_set", _transitions.size(), 1); - bit_clear_all(stream, "target_set", _states.size(), 1); - bit_clear_all(stream, "exit_set", _states.size(), 1); - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Establishing optimal transition set for event %d\\n\", " << _prefix << EVENT_NAME << ");" << std::endl; - stream << "#endif" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_TRANS -> {" << std::endl; - - stream << " /* only select non-history, non-initial transitions */" << std::endl; - stream << " if" << std::endl; - stream << " :: !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] &&" << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; - - stream << " if" << std::endl; - stream << " :: /* is the transition active? */" << std::endl; - stream << " " << _prefix << "config[" << _prefix << "transitions[i].source] && " << std::endl; - stream << std::endl; - stream << " /* is it non-conflicting? */" << std::endl; - stream << " !conflicts[i] && " << std::endl; - stream << std::endl; - stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; - stream << " ((" << _prefix << EVENT_NAME << " == USCXML_EVENT_SPONTANEOUS && " << std::endl; - stream << " " << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS]) || " << std::endl; - stream << " (" << _prefix << EVENT_NAME << " != USCXML_EVENT_SPONTANEOUS && " << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS])) &&" << std::endl; - stream << std::endl; - stream << " /* is it matching and enabled? */" << std::endl; - stream << " (false " << std::endl; - - - for (auto i = 0; i < _transitions.size(); i++) { - stream << " || (i == " << toStr(i); - if (HAS_ATTR(_transitions[i], "event") && ATTR(_transitions[i], "event") != "*") { - stream << " && (false"; - std::list events =_analyzer.getTrie().getWordsWithPrefix(ATTR(_transitions[i], "event")); - for (auto event : events) { - stream << " || " << _prefix << EVENT_NAME << " == " << _analyzer.macroForLiteral(event->value); - } - stream << ")"; - } - if (HAS_ATTR(_transitions[i], "cond")) { - stream << " && " << ADAPT_SRC(ATTR(_transitions[i], "cond")); - } - stream << ")" << std::endl; - } - - stream << " ) -> {" << std::endl; + stream << _prefix << "SELECT_TRANSITIONS:" << std::endl; + stream << _prefix << "STATES_CLEAR(" << _prefix << "ctx.target_set)" << std::endl; + stream << _prefix << "STATES_CLEAR(" << _prefix << "ctx.exit_set)" << std::endl; - stream << " /* remember that we found a transition */" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; - stream << std::endl; + if (_transitions.size() > 0) { + stream << _prefix << "TRANS_CLEAR(" << _prefix << "ctx.conflicts)" << std::endl; + stream << _prefix << "TRANS_CLEAR(" << _prefix << "ctx.trans_set)" << std::endl; - stream << " /* transitions that are pre-empted */" << std::endl; - bit_or(stream, "conflicts", _prefix + "transitions[i].conflicts", _transitions.size(), 4); - stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + if (_machinesAll->size() > 1) { + stream << "printf(\"%d: Establishing optimal transition set for event %d\\n\", _pid, " << _prefix << EVENT_NAME << " );" << std::endl; + } else { + stream << "printf(\"Establishing optimal transition set for event %d\\n\", " << _prefix << EVENT_NAME << " );" << std::endl; + } + stream << "#endif" << std::endl; + stream << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Configuration: \");" << std::endl; + printBitArray(stream, _prefix + "config", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + + stream << " /* only select non-history, non-initial transitions */" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] &&" << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: /* is the transition active? */" << std::endl; + stream << " " << _prefix << "config[" << _prefix << "transitions[i].source] && " << std::endl; + stream << std::endl; + stream << " /* is it non-conflicting? */" << std::endl; + stream << " !" << _prefix << "ctx.conflicts[i] && " << std::endl; + stream << std::endl; + stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; + stream << " ((" << _prefix << EVENT_NAME << " == USCXML_EVENT_SPONTANEOUS && " << std::endl; + stream << " " << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS]) || " << std::endl; + stream << " (" << _prefix << EVENT_NAME << " != USCXML_EVENT_SPONTANEOUS && " << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS])) &&" << std::endl; + stream << std::endl; + stream << " /* is it matching and enabled? */" << std::endl; + stream << " (false " << std::endl; + + + for (auto i = 0; i < _transitions.size(); i++) { + stream << " || (i == " << toStr(i); + if (HAS_ATTR(_transitions[i], "event") && ATTR(_transitions[i], "event") != "*") { + stream << " && (false"; + std::list eventLiterals = tokenize(ATTR(_transitions[i], "event")); + for (auto eventLiteral : eventLiterals) { + if (boost::ends_with(eventLiteral, ".*")) { + eventLiteral = eventLiteral.substr(0, eventLiteral.size() - 2); + } + if (boost::ends_with(eventLiteral, ".")) { + eventLiteral = eventLiteral.substr(0, eventLiteral.size() - 1); + } + std::list events =_analyzer->getTrie().getWordsWithPrefix(eventLiteral); + for (auto event : events) { + stream << " || " << _prefix << EVENT_NAME << " == " << _analyzer->macroForLiteral(event->value); + } + } + stream << ")"; + } + if (HAS_ATTR(_transitions[i], "cond")) { + stream << " && " << ADAPT_SRC(ATTR(_transitions[i], "cond")); + } + stream << ")" << std::endl; + } - stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; - bit_or(stream, "target_set", _prefix + "transitions[i].target", _states.size(), 4); - stream << std::endl; + stream << " ) -> {" << std::endl; - stream << " /* states that will be left */" << std::endl; - bit_or(stream, "exit_set", _prefix + "transitions[i].exit_set", _states.size(), 4); - stream << std::endl; + stream << " /* remember that we found a transition */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; + stream << std::endl; - stream << " trans_set[i] = true;" << std::endl; + stream << " /* transitions that are pre-empted */" << std::endl; + stream << " " << _prefix << "TRANS_OR(" << _prefix << "ctx.conflicts, " << _prefix << "transitions[i].conflicts)" << std::endl; + stream << std::endl; + stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.target_set, " << _prefix << "transitions[i].target)" << std::endl; + stream << std::endl; - stream << " }" << std::endl; - stream << " :: else {" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " fi" << std::endl; + stream << " /* states that will be left */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.exit_set, " << _prefix << "transitions[i].exit_set)" << std::endl; + stream << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; + stream << " " << _prefix << "ctx.trans_set[i] = true;" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Selected Transitions: \");" << std::endl; - printBitArray(stream, "trans_set", _transitions.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; + stream << " }" << std::endl; + stream << " :: else {" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + + stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.exit_set, " << _prefix << "config)" << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Selected Transitions: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.trans_set", _transitions.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + } + stream << std::endl; stream << "#if TRACE_EXECUTION" << std::endl; stream << "printf(\"Target Set: \");" << std::endl; - printBitArray(stream, "target_set", _states.size()); + printBitArray(stream, _prefix + "ctx.target_set", _states.size()); stream << "printf(\"\\n\");" << std::endl; stream << "#endif" << std::endl; + stream << std::endl; -#if 0 - stream << " if (ctx->flags & USCXML_CTX_TRANSITION_FOUND) {" << std::endl; - stream << " ctx->flags |= USCXML_CTX_SPONTANEOUS;" << std::endl; - stream << " ctx->flags &= ~USCXML_CTX_TRANSITION_FOUND;" << std::endl; - stream << " } else {" << std::endl; - stream << " ctx->flags &= ~USCXML_CTX_SPONTANEOUS;" << std::endl; - stream << " goto DEQUEUE_EVENT;" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Exit Set: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.exit_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "STATES_HAS_ANY(" << _prefix << "config) -> {" << std::endl; + stream << " /* Enter initial configuration */" << std::endl; + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.target_set, " << _prefix << "states[0].completion)" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; + + TRACE_EXECUTION("Entering initial default completion"); + +// stream << " goto " << _prefix << "ESTABLISH_ENTRY_SET;" << std::endl; + stream << std::endl; + + stream << " }" << std::endl; stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Found transitions\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; + + TRACE_EXECUTION("Found transitions"); + + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; stream << " }" << std::endl; stream << " :: else {" << std::endl; stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = false;" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Found NO transitions\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " goto DEQUEUE_EVENT;" << std::endl; + + TRACE_EXECUTION("Found NO transitions"); + +// stream << " goto " << _prefix << "MICROSTEP;" << std::endl; stream << " }" << std::endl; stream << " fi" << std::endl; stream << std::endl; -#if 0 - stream << "/* REMEMBER_HISTORY: */" << std::endl; - stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; - stream << " if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW ||" << std::endl; - stream << " USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP) {" << std::endl; - stream << " /* a history state whose parent is about to be exited */" << std::endl; - stream << " if unlikely(BIT_HAS(USCXML_GET_STATE(i).parent, exit_set)) {" << std::endl; - stream << " bit_copy(tmp_states, USCXML_GET_STATE(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, nr_states_bytes);" << std::endl; - stream << std::endl; - stream << " /* clear current history with completion mask */" << std::endl; - stream << " bit_and_not(ctx->history, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; - stream << std::endl; - stream << " /* set history */" << std::endl; - stream << " bit_or(ctx->history, tmp_states, nr_states_bytes);" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; + stream << " /* only process anything if we found transitions or are on initial entry */" << std::endl; + stream << "/* ---------------------------- */" << std::endl; stream << "/* REMEMBER_HISTORY: */" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Save history configurations\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + TRACE_EXECUTION("Save history configurations"); - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; - stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: exit_set[" << _prefix << "states[i].parent] -> {" << std::endl; - stream << " /* a history state whose parent is about to be exited */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "STATES_HAS_ANY(" << _prefix << "config) -> {" << std::endl; + stream << " /* only remember history on non-initial entry */" << std::endl; - bit_copy(stream, _prefix + "states[i].completion", "tmp_states", _states.size(), 3); - bit_and(stream, "tmp_states", _prefix + "config", _states.size(), 3); - bit_and_not(stream, "tmp_states", _prefix + "states[i].completion", _states.size(), 3); - bit_or(stream, _prefix + "history", "tmp_states", _states.size(), 3); - stream << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; + stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.exit_set[" << _prefix << "states[i].parent] -> {" << std::endl; + + stream << " /* a history state whose parent is about to be exited */" << std::endl; + TRACE_EXECUTION_V("history state %d is about to be exited", "i"); + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"COMPLET: \");" << std::endl; + printBitArray(stream, _prefix + "states[i].completion", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.tmp_states, " << _prefix << "states[i].completion)" << std::endl; -#if 0 - stream << "ESTABLISH_ENTRY_SET:" << std::endl; - stream << " /* calculate new entry set */" << 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 < USCXML_NUMBER_STATES; i++) {" << std::endl; - stream << " if (BIT_HAS(i, entry_set)) {" << std::endl; - stream << " bit_or(entry_set, USCXML_GET_STATE(i).ancestors, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " /* set those states who were enabled */" << std::endl; + stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.tmp_states, " << _prefix << "config)" << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"CONFIG : \");" << std::endl; + printBitArray(stream, _prefix + "config", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"TMP_STS: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.tmp_states", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << " /* clear current history with completion mask */" << std::endl; + stream << " " << _prefix << "STATES_AND_NOT(" << _prefix << "history, " << _prefix << "states[i].completion)" << std::endl; + stream << std::endl; + + stream << " /* set history */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "history, " << _prefix << "ctx.tmp_states)" << std::endl; + + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + + stream << " i = i + 1;" << std::endl; stream << " }" << std::endl; - stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; stream << std::endl; -#endif + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"History: \");" << std::endl; + printBitArray(stream, _prefix + "history", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + + stream << std::endl; stream << "/* ---------------------------- */" << std::endl; - stream << "ESTABLISH_ENTRY_SET:" << std::endl; + stream << _prefix << "ESTABLISH_ENTRY_SET:" << std::endl; stream << " /* calculate new entry set */" << std::endl; - bit_copy(stream, "target_set", "entry_set", _states.size(), 1); + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.entry_set, " << _prefix << "ctx.target_set)" << std::endl; stream << std::endl; stream << " i = 0;" << std::endl; stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; stream << " if" << std::endl; - stream << " :: entry_set[i] -> {" << std::endl; + stream << " :: " << _prefix << "ctx.entry_set[i] -> {" << std::endl; stream << " /* ancestor completion */" << std::endl; - bit_or(stream, "entry_set", _prefix + "states[i].ancestors", _states.size(), 3); + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].ancestors)" << std::endl; stream << " }" << std::endl; stream << " :: else -> skip;" << std::endl; @@ -1621,168 +1787,106 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " od;" << std::endl; stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Entry Set (after ancestor completion)\");" << std::endl; - printBitArray(stream, "entry_set", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - -#if 0 - stream << " /* iterate for descendants */" << std::endl; - stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; - stream << " if (BIT_HAS(i, entry_set)) {" << std::endl; - stream << " switch (USCXML_STATE_MASK(USCXML_GET_STATE(i).type)) {" << std::endl; -#endif - stream << " /* iterate for descendants */" << std::endl; stream << " i = 0;" << std::endl; stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; stream << " if" << std::endl; - stream << " :: entry_set[i] -> {" << std::endl; + stream << " :: " << _prefix << "ctx.entry_set[i] -> {" << std::endl; stream << " if" << std::endl; -#if 0 - stream << " case USCXML_STATE_PARALLEL: {" << std::endl; - stream << " bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; -#endif - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_PARALLEL] -> {" << std::endl; - bit_or(stream, "entry_set", _prefix + "states[i].completion", _states.size(), 4); + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].completion)" << std::endl; stream << " }" << std::endl; -#if 0 - stream << " case USCXML_STATE_HISTORY_SHALLOW:" << std::endl; - stream << " case USCXML_STATE_HISTORY_DEEP: {" << std::endl; - stream << " if (!bit_has_and(USCXML_GET_STATE(i).completion, ctx->history, nr_states_bytes) &&" << std::endl; - stream << " !BIT_HAS(USCXML_GET_STATE(i).parent, ctx->config)) {" << std::endl; - stream << " /* nothing set for history, look for a default transition */" << std::endl; - stream << " for (j = 0; j < USCXML_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(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP &&" << std::endl; - stream << " !bit_has_and(ctx->machine->transitions[j].target, USCXML_GET_STATE(i).children, nr_states_bytes)) {" << std::endl; - stream << " for (k = i + 1; k < USCXML_NUMBER_STATES; k++) {" << 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; - stream << " }" << std::endl; - stream << " BIT_SET_AT(j, trans_set);" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; - stream << " /* Note: SCXML mandates every history to have a transition! */" << std::endl; - stream << " }" << std::endl; - stream << " } else {" << std::endl; - stream << " bit_copy(tmp_states, USCXML_GET_STATE(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 (USCXML_GET_STATE(i).type == (USCXML_STATE_HAS_HISTORY | USCXML_STATE_HISTORY_DEEP)) {" << std::endl; - stream << " /* a deep history state with nested histories -> more completion */" << std::endl; - stream << " for (j = i + 1; j < USCXML_NUMBER_STATES; j++) {" << std::endl; - stream << " if (BIT_HAS(j, USCXML_GET_STATE(i).completion) &&" << std::endl; - stream << " BIT_HAS(j, entry_set) &&" << std::endl; - stream << " (ctx->machine->states[j].type & USCXML_STATE_HAS_HISTORY)) {" << std::endl; - stream << " for (k = j + 1; k < USCXML_NUMBER_STATES; k++) {" << std::endl; - stream << " /* add nested history to entry_set */" << std::endl; - stream << " if ((USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_DEEP ||" << std::endl; - stream << " USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_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; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; -#endif - - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: !"; - bit_has_and(stream, _prefix + "states[i].completion", _prefix + "history", _states.size(), 5); + + TRACE_EXECUTION_V("Descendant completion for history state %d", "i") + + stream << " if" << std::endl; + stream << " :: !" << _prefix << "STATES_HAS_AND(" << _prefix << "states[i].completion, " << _prefix << "history)"; +// bit_has_and(stream, _prefix + "states[i].completion", _prefix + "history", _states.size(), 5); stream << " && !" << _prefix << "config[" << _prefix << "states[i].parent]" << " -> {" << std::endl; stream << " /* nothing set for history, look for a default transition */" << std::endl; - stream << " j = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; - - bit_or(stream, "entry_set", _prefix + "transitions[j].target", _states.size(), 8); - stream << std::endl; - stream << " if" << std::endl; - stream << " :: (" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] &&" << std::endl; - stream << " !"; - bit_has_and(stream, _prefix + "transitions[j].target", _prefix + "states[i].children", _states.size(), 10); - stream << " ) -> {" << std::endl; - stream << " k = i + 1" << std::endl; - stream << " do" << std::endl; - stream << " :: k < USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; - bit_or(stream, "entry_set", _prefix + "states[k].ancestors", _states.size(), 11); - stream << " break;" << std::endl; - stream << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << " trans_set[j] = true;" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break" << std::endl; - stream << " od" << std::endl; + TRACE_EXECUTION("Fresh history in target set") + if (_transitions.size() > 0) { + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; + stream << " " << _prefix << "ctx.trans_set[j] = true;" << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "transitions[j].target)" << std::endl; + stream << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] &&" << std::endl; + stream << " !" << _prefix << "STATES_HAS_AND(" << _prefix << "transitions[j].target, " << _prefix << "states[i].children)"; + // bit_has_and(stream, _prefix + "transitions[j].target", _prefix + "states[i].children", _states.size(), 10); + stream << " ) -> {" << std::endl; + stream << " k = i + 1" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[k].ancestors)" << std::endl; + stream << " break;" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break" << std::endl; + stream << " od" << std::endl; + } stream << " skip;" << std::endl; stream << " }" << std::endl; stream << " :: else -> {" << std::endl; - bit_copy(stream, "tmp_states", _prefix + "states[i].completion", _states.size(), 5); - bit_and(stream, "tmp_states", _prefix + "history", _states.size(), 5); - bit_or(stream, "entry_set", "tmp_states", _states.size(), 5); + + TRACE_EXECUTION("Established history in target set") + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.tmp_states, " << _prefix << "states[i].completion)" << std::endl; + stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.tmp_states, " << _prefix << "history)" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "ctx.tmp_states)" << std::endl; stream << " if" << std::endl; stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HAS_HISTORY] ||" << std::endl; stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> { " << std::endl; stream << " /* a deep history state with nested histories -> more completion */" << std::endl; + TRACE_EXECUTION("DEEP HISTORY") stream << " j = i + 1;" << std::endl; stream << " do" << std::endl; - stream << " :: j < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; stream << " if" << std::endl; stream << " :: (" << _prefix << "states[i].completion[j] &&" << std::endl; - stream << " entry_set[j] && " << std::endl; + stream << " " << _prefix << "ctx.entry_set[j] && " << std::endl; stream << " " << _prefix << "states[j].type[USCXML_STATE_HAS_HISTORY]) -> {" << std::endl; stream << " k = j + 1;" << std::endl; stream << " do" << std::endl; - stream << " :: k < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; stream << " /* add nested history to entry_set */" << std::endl; - stream << " k = k + 1;" << std::endl; stream << " if" << std::endl; stream << " :: (" << _prefix << "states[k].type[USCXML_STATE_HISTORY_DEEP] ||" << std::endl; stream << " " << _prefix << "states[k].type[USCXML_STATE_HISTORY_SHALLOW]) &&" << std::endl; stream << " " << _prefix << "states[j].children[k] -> {" << std::endl; stream << " /* a nested history state */" << std::endl; - stream << " entry_set[k] = true;" << std::endl; + stream << " " << _prefix << "ctx.entry_set[k] = true;" << std::endl; stream << " }" << std::endl; stream << " :: else -> skip;" << std::endl; stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; stream << " }" << std::endl; stream << " :: else -> break;" << std::endl; stream << " od" << std::endl; @@ -1790,6 +1894,7 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " :: else -> skip;" << std::endl; stream << " fi" << std::endl; stream << " }" << std::endl; + stream << " j = j + 1;" << std::endl; stream << " :: else -> break;" << std::endl; stream << " od" << std::endl; stream << " }" << std::endl; @@ -1801,137 +1906,100 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " }" << std::endl; -#if 0 - stream << " case USCXML_STATE_INITIAL: {" << std::endl; - stream << " for (j = 0; j < USCXML_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, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl; - stream << " for (k = i + 1; k < USCXML_NUMBER_STATES; k++) {" << 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; - stream << " }" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; -#endif + if (_transitions.size() > 0) { + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_INITIAL] -> {" << std::endl; - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_INITIAL] -> {" << std::endl; - stream << " j = 0" << std::endl; - stream << " do" << std::endl; - stream << " :: j < USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; - stream << " trans_set[j] = true;" << std::endl; - stream << " entry_set[i] = false;" << std::endl; + TRACE_EXECUTION_V("Descendant completion for initial state %d", "i") - bit_or(stream, "entry_set", _prefix + "transitions[j].target", _states.size(), 6); - stream << std::endl; + stream << " j = 0" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; + stream << " " << _prefix << "ctx.trans_set[j] = true;" << std::endl; + stream << " " << _prefix << "ctx.entry_set[i] = false;" << std::endl; - stream << " k = i + 1;" << std::endl; - stream << " do" << std::endl; - stream << " :: k < USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; + TRACE_EXECUTION_V("Adding transition %d!", "j"); - bit_or(stream, "entry_set", _prefix + "states[k].ancestors", _states.size(), 8); - stream << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "transitions[j].target)" << std::endl; + stream << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " fi" << std::endl; - stream << " k = k + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break" << std::endl; - stream << " od" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break" << std::endl; - stream << " od;" << std::endl; + stream << " k = i + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; - stream << " }" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[k].ancestors)" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break" << std::endl; + stream << " od" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break" << std::endl; + stream << " od;" << std::endl; -#if 0 - stream << " case USCXML_STATE_COMPOUND: { /* we need to check whether one child is already in entry_set */" << std::endl; - stream << " if (!bit_has_and(entry_set, USCXML_GET_STATE(i).children, nr_states_bytes) &&" << std::endl; - stream << " (!bit_has_and(ctx->config, USCXML_GET_STATE(i).children, nr_states_bytes) ||" << std::endl; - stream << " bit_has_and(exit_set, USCXML_GET_STATE(i).children, nr_states_bytes)))" << std::endl; - stream << " {" << std::endl; - stream << " bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; - stream << " if (!bit_has_and(USCXML_GET_STATE(i).completion, USCXML_GET_STATE(i).children, nr_states_bytes)) {" << std::endl; - stream << " /* deep completion */" << std::endl; - stream << " for (j = i + 1; j < USCXML_NUMBER_STATES; j++) {" << std::endl; - stream << " if (BIT_HAS(j, USCXML_GET_STATE(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; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif + stream << " }" << std::endl; + } stream << " :: " << _prefix << "states[i].type[USCXML_STATE_COMPOUND] -> {" << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Descendant completion for compound state %d\\n\", i);" << std::endl; - stream << "#endif" << std::endl; +// TRACE_EXECUTION_V("Descendant completion for compound state %d", "i") stream << " /* we need to check whether one child is already in entry_set */" << std::endl; stream << " if" << std::endl; stream << " :: (" << std::endl; - stream << " !"; - bit_has_and(stream, "entry_set", _prefix + "states[i].children", _states.size(), 5); + stream << " !" << _prefix << "STATES_HAS_AND(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].children)"; stream << " && " << std::endl; - stream << " (!"; - bit_has_and(stream, _prefix + "config", _prefix + "states[i].children", _states.size(), 5); - stream << " || " << std::endl; - bit_has_and(stream, "exit_set", _prefix + "states[i].children", _states.size(), 5); - stream << ")) "<< std::endl; + stream << " (!" << _prefix << "STATES_HAS_AND(" << _prefix << "config, " << _prefix << "states[i].children)"; +// bit_has_and(stream, _prefix + "config", _prefix + "states[i].children", _states.size(), 5); + stream << " || " << _prefix << "STATES_HAS_AND(" << _prefix << "ctx.exit_set, " << _prefix << "states[i].children)" << std::endl; + stream << ")) " << std::endl; stream << " -> {" << std::endl; - bit_or(stream, "entry_set", _prefix + "states[i].completion", _states.size(), 5); + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].completion)" << std::endl; - stream << " if" << std::endl; - stream << " :: ("; - bit_has_and(stream, _prefix + "states[i].completion", _prefix + "states[i].children", _states.size(), 5); - stream << std::endl; - stream << " ) -> {" << std::endl; - stream << " /* deep completion */" << std::endl; - stream << " j = i + 1;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < USCXML_NUMBER_STATES - 1 -> {" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].completion[j] -> {" << std::endl; - - bit_or(stream, "entry_set", _prefix + "states[j].ancestors", _states.size(), 9); + stream << " if" << std::endl; + stream << " :: (" << _prefix << "STATES_HAS_AND(" << _prefix << "states[i].completion, " << _prefix << "states[i].children)"; +// bit_has_and(stream, _prefix + "states[i].completion", _prefix + "states[i].children", _states.size(), 6); + stream << std::endl; + stream << " ) -> {" << std::endl; + stream << " /* deep completion */" << std::endl; + stream << " j = i + 1;" << std::endl; + +// TRACE_EXECUTION_V("Deep completion for compound state %d", "i") + + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES - 1 -> {" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].completion[j] -> {" << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[j].ancestors)" << std::endl; stream << std::endl; - stream << " /* completion of compound is single state */" << std::endl; - stream << " break;" << std::endl; - stream << " } " << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; + stream << " /* completion of compound is single state */" << std::endl; + stream << " break;" << std::endl; + stream << " } " << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; stream << " }" << std::endl; stream << " :: else -> skip;" << std::endl; @@ -1949,53 +2017,41 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " od;" << std::endl; stream << std::endl; -#if 0 - stream << "/* EXIT_STATES: */" << std::endl; - stream << " i = USCXML_NUMBER_STATES;" << std::endl; - 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 (USCXML_GET_STATE(i).on_exit != NULL) {" << std::endl; - stream << " if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)" << std::endl; - stream << " return err;" << std::endl; - stream << " }" << std::endl; - stream << " BIT_CLEAR(i, ctx->config);" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif - + stream << std::endl; stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Entry Set (after descendant completion)\");" << std::endl; - printBitArray(stream, "entry_set", _states.size()); + stream << "printf(\"Entry Set\");" << std::endl; + printBitArray(stream, _prefix + "ctx.entry_set", _states.size()); stream << "printf(\"\\n\");" << std::endl; stream << "#endif" << std::endl; + stream << std::endl; stream << "/* ---------------------------- */" << std::endl; stream << "/* EXIT_STATES: */" << std::endl; - stream << " i = USCXML_NUMBER_STATES;" << std::endl; + stream << " i = " << _prefix << "USCXML_NUMBER_STATES;" << std::endl; stream << " do" << std::endl; stream << " :: i > 0 -> {" << std::endl; stream << " i = i - 1;" << std::endl; stream << " if" << std::endl; - stream << " :: exit_set[i] && " << _prefix << "config[i] -> {" << std::endl; + stream << " :: " << _prefix << "ctx.exit_set[i] && " << _prefix << "config[i] -> {" << std::endl; stream << " /* call all on-exit handlers */" << std::endl; - + + TRACE_EXECUTION_V("Exiting state %d", "i"); + stream << " if" << std::endl; for (auto i = 0; i < _states.size(); i++) { - std::list onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); - if (onentries.size() > 0) { + std::list onexits = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); + if (onexits.size() > 0) { stream << " :: i == " << toStr(i) << " -> {" << std::endl; - for (auto onentry : onentries) - writeExecContent(stream, onentry, 3); + TRACE_EXECUTION_V("Processing executable content for exiting state %d", "i"); + for (auto onexit : onexits) + writeExecContent(stream, onexit, 3); stream << " }" << std::endl; } } - stream << " :: else ->skip;" << std::endl; + stream << " :: else -> skip;" << std::endl; stream << " fi" << std::endl; stream << std::endl; - stream << " " << _prefix << "config[i] = false;" << std::endl; stream << " skip;" << std::endl; stream << " }" << std::endl; @@ -2006,110 +2062,63 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " od;" << std::endl; stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Exited States\\n\");" << std::endl; - stream << "#endif" << std::endl; - -#if 0 - stream << "/* TAKE_TRANSITIONS: */" << std::endl; - stream << " for (i = 0; i < USCXML_NUMBER_TRANS; i++) {" << std::endl; - stream << " if (BIT_HAS(i, trans_set) && (USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) == 0) {" << std::endl; - stream << " /* call executable content in transition */" << std::endl; - stream << " if (USCXML_GET_TRANS(i).on_transition != NULL) {" << std::endl; - stream << " if unlikely((err = USCXML_GET_TRANS(i).on_transition(ctx," << std::endl; - stream << " &ctx->machine->states[USCXML_GET_TRANS(i).source]," << std::endl; - stream << " ctx->event)) != USCXML_ERR_OK)" << std::endl; - stream << " return err;" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; -#endif +// TRACE_EXECUTION("Exited States") stream << "/* ---------------------------- */" << std::endl; stream << "/* TAKE_TRANSITIONS: */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: trans_set[i] && " << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] && " << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; - stream << " /* Call executable content in normal transition */" << std::endl; - stream << " if" << std::endl; - for (auto i = 0; i < _transitions.size(); i++) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - writeExecContent(stream, _transitions[i], 4); - stream << " skip;" << std::endl; - stream << " }" << std::endl; + if (_transitions.size() > 0) { + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.trans_set[i] && " << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] && " << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; + stream << " /* Call executable content in normal transition */" << std::endl; + + TRACE_EXECUTION_V("Taking transition %d", "i"); + + stream << " if" << std::endl; + for (auto i = 0; i < _transitions.size(); i++) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for transition %d", "i"); + writeExecContent(stream, _transitions[i], 4); + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else ->skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; } - stream << " :: else ->skip;" << std::endl; - stream << " fi" << std::endl; stream << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Took Transitions\\n\");" << std::endl; - stream << "#endif" << std::endl; - -#if 0 - stream << "/* ENTER_STATES: */" << std::endl; - stream << " for (i = 0; i < USCXML_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(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP ||" << std::endl; - stream << " USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW ||" << std::endl; - stream << " USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_INITIAL)" << std::endl; - stream << " continue;" << std::endl; - stream << std::endl; -#endif stream << "/* ---------------------------- */" << std::endl; stream << "/* ENTER_STATES: */" << std::endl; stream << " i = 0;" << std::endl; stream << " do" << std::endl; - stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; stream << " if" << std::endl; - stream << " :: (entry_set[i] &&" << std::endl; - stream << " !" << _prefix << "config[i] && " << std::endl; - stream << " /* these are no proper states */" << std::endl; - stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] && " << std::endl; - stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] && " << std::endl; - stream << " !" << _prefix << "states[i].type[USCXML_STATE_INITIAL]" << std::endl; + stream << " :: (" << _prefix << "ctx.entry_set[i] &&" << std::endl; + stream << " !" << _prefix << "config[i] && " << std::endl; + stream << " /* these are no proper states */" << std::endl; + stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] && " << std::endl; + stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] && " << std::endl; + stream << " !" << _prefix << "states[i].type[USCXML_STATE_INITIAL]" << std::endl; stream << " ) -> {" << std::endl; -#if 0 - stream << " BIT_SET_AT(i, ctx->config);" << std::endl; - stream << std::endl; -#endif - - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Entering State %d\\n\", i);" << std::endl; - stream << "#endif" << std::endl; + TRACE_EXECUTION_V("Entering state %d", "i"); stream << " " << _prefix << "config[i] = true;" << std::endl; stream << std::endl; - #if 0 - stream << " /* initialize data */" << std::endl; - stream << " if (!BIT_HAS(i, ctx->initialized_data)) {" << std::endl; - stream << " if unlikely(USCXML_GET_STATE(i).data != NULL && ctx->exec_content_init != NULL) {" << std::endl; - stream << " ctx->exec_content_init(ctx, USCXML_GET_STATE(i).data);" << std::endl; - stream << " }" << std::endl; - stream << " BIT_SET_AT(i, ctx->initialized_data);" << std::endl; - stream << " }" << std::endl; - stream << std::endl; - -#endif - stream << " if" << std::endl; stream << " :: !" << _prefix << "initialized_data[i] -> {" << std::endl; stream << " /* TODO: late data binding not supported yet */" << std::endl; @@ -2119,22 +2128,15 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " :: else -> skip;" << std::endl; stream << " fi" << std::endl; stream << std::endl; - -#if 0 - stream << " if (USCXML_GET_STATE(i).on_entry != NULL) {" << std::endl; - stream << " if unlikely((err = USCXML_GET_STATE(i).on_entry(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)" << std::endl; - stream << " return err;" << std::endl; - stream << " }" << std::endl; - stream << std::endl; - #endif - + stream << " /* Process executable content for entering a state */" << std::endl; stream << " if" << std::endl; for (auto i = 0; i < _states.size(); i++) { std::list onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onentry" , _states[i]); if (onentries.size() > 0) { stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for entering state %d", "i"); for (auto onentry : onentries) writeExecContent(stream, onentry, 5); stream << " }" << std::endl; @@ -2144,136 +2146,172 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " fi" << std::endl; stream << std::endl; -#if 0 - stream << " /* take history and initial transitions */" << std::endl; - stream << " for (j = 0; j < USCXML_NUMBER_TRANS; j++) {" << std::endl; - stream << " if unlikely(BIT_HAS(j, trans_set) &&" << std::endl; - stream << " (ctx->machine->transitions[j].type & (USCXML_TRANS_HISTORY | USCXML_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 (ctx->machine->transitions[j].on_transition != NULL) {" << std::endl; - stream << " if unlikely((err = ctx->machine->transitions[j].on_transition(ctx," << std::endl; - stream << " &USCXML_GET_STATE(i)," << std::endl; - stream << " ctx->event)) != USCXML_ERR_OK)" << std::endl; - stream << " return err;" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; - -#endif - stream << " /* take history and initial transitions */" << std::endl; - stream << " j = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: (trans_set[j] &&" << std::endl; - stream << " (" << _prefix << "transitions[j].type[USCXML_TRANS_HISTORY] ||" << std::endl; - stream << " " << _prefix << "transitions[j].type[USCXML_TRANS_INITIAL]) && " << std::endl; - stream << " " << _prefix << "states[" << _prefix << "transitions[j].source].parent == i) -> {" << std::endl; - stream << " /* Call executable content in history or initial transition */" << std::endl; - stream << " if" << std::endl; - for (auto i = 0; i < _transitions.size(); i++) { - stream << " :: j == " << toStr(i) << " -> {" << std::endl; - writeExecContent(stream, _transitions[i], 8); - stream << " skip;" << std::endl; - stream << " }" << std::endl; + if (_transitions.size() > 0) { + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "ctx.trans_set[j] &&" << std::endl; + stream << " (" << _prefix << "transitions[j].type[USCXML_TRANS_HISTORY] ||" << std::endl; + stream << " " << _prefix << "transitions[j].type[USCXML_TRANS_INITIAL]) && " << std::endl; + stream << " " << _prefix << "states[" << _prefix << "transitions[j].source].parent == i) -> {" << std::endl; + stream << " /* Call executable content in history or initial transition */" << std::endl; + stream << " if" << std::endl; + for (auto i = 0; i < _transitions.size(); i++) { + stream << " :: j == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for transition %d", "j"); + + writeExecContent(stream, _transitions[i], 8); + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else ->skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; } - stream << " :: else ->skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; + stream << " /* handle final states */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_FINAL] -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[" << _prefix << "states[i].parent].children[1] -> {" << std::endl; + stream << " /* exit topmost SCXML state */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " /* raise done event */" << std::endl; + stream << " if" << std::endl; + std::string insertOp = "!"; +// if (_analyzer->usesEventField("delay")) +// insertOp += "!"; -#if 0 - stream << " /* handle final states */" << std::endl; - stream << " if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_FINAL) {" << std::endl; -#endif + for (auto state : _states) { + if (state->getParentNode() == NULL || state->getParentNode()->getNodeType() != DOMNode::ELEMENT_NODE) + continue; + + if (!isFinal(state)) + continue; + + DOMElement* parent = static_cast(state->getParentNode()); + if (!HAS_ATTR(parent, "id")) + continue; - stream << " /* handle final states */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_FINAL] -> {" << std::endl; + std::string doneEvent = _analyzer->macroForLiteral("done.state." + ATTR_CAST(state->getParentNode(), "id")); + stream << " :: (i == " << ATTR(state, "documentOrder") << ") -> {" << std::endl; -#if 0 - stream << " if unlikely(USCXML_GET_STATE(i).ancestors[0] == 0x01) {" << std::endl; - stream << " ctx->flags |= USCXML_CTX_TOP_LEVEL_FINAL;" << std::endl; - stream << " } else {" << std::endl; - stream << " /* raise done event */" << std::endl; - stream << " const uscxml_elem_donedata* donedata = &ctx->machine->donedata[0];" << std::endl; - stream << " while(USCXML_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, &ctx->machine->states[USCXML_GET_STATE(i).parent], (USCXML_ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl; - stream << " }" << std::endl; -#endif + if (_analyzer->usesComplexEventStruct()) { + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 7); + stream << typeReset << std::endl; + stream << " " << _prefix << "_tmpE.name = " << doneEvent << ";" << std::endl; + + std::list donedatas = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "donedata" , state); + if (donedatas.size() > 0) { + writeRaiseDoneDate(stream, donedatas.front(), 8); + } + + doneEvent = _prefix + "_tmpE"; + } + + + stream << " " << _prefix << "iQ" << insertOp << doneEvent << ";" << std::endl; + stream << " }" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[" << _prefix << "states[i].parent].children[1] -> {" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] = true;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - stream << " /* TODO: raise done event */" << std::endl; - stream << " skip;" << std::endl; + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; stream << " fi" << std::endl; + stream << " /**" << std::endl; + stream << " * are we the last final state to leave a parallel state?:" << std::endl; + stream << " * 1. Gather all parallel states in our ancestor chain" << std::endl; + stream << " * 2. Find all states for which these parallels are ancestors" << std::endl; + stream << " * 3. Iterate all active final states and remove their ancestors" << std::endl; + stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl; + stream << " */" << std::endl; + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[j].type[USCXML_STATE_PARALLEL] && " << _prefix << "states[i].ancestors[j] -> {" << std::endl; + stream << " " << _prefix << "STATES_CLEAR(" << _prefix << "ctx.tmp_states)" << std::endl; -#if 0 - stream << std::endl; - stream << " /**" << std::endl; - stream << " * are we the last final state to leave a parallel state?:" << std::endl; - stream << " * 1. Gather all parallel states in our ancestor chain" << std::endl; - stream << " * 2. Find all states for which these parallels are ancestors" << std::endl; - stream << " * 3. Iterate all active final states and remove their ancestors" << std::endl; - stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl; - stream << " */" << std::endl; - stream << " for (j = 0; j < USCXML_NUMBER_STATES; j++) {" << std::endl; - stream << " if unlikely(USCXML_STATE_MASK(ctx->machine->states[j].type) == USCXML_STATE_PARALLEL &&" << std::endl; - stream << " BIT_HAS(j, USCXML_GET_STATE(i).ancestors)) {" << std::endl; - stream << " bit_clear_all(tmp_states, nr_states_bytes);" << std::endl; - stream << " for (k = 0; k < USCXML_NUMBER_STATES; k++) {" << std::endl; - stream << " if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {" << std::endl; - stream << " if (USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_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, 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; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << " }" << std::endl; - stream << std::endl; + stream << " k = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[k].ancestors[j] && " << _prefix << "config[k] -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[k].type[USCXML_STATE_FINAL] -> {" << std::endl; + + stream << " " << _prefix << "STATES_AND_NOT(" << _prefix << "ctx.tmp_states, " << _prefix << "states[k].ancestors)" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + + stream << " " << _prefix << "ctx.tmp_states[k] = true;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "STATES_HAS_ANY(" << _prefix << "ctx.tmp_states) -> {" << std::endl; + stream << " if" << std::endl; - stream << " return USCXML_ERR_OK;" << std::endl; - stream << "}" << std::endl; - stream << std::endl; - stream << std::endl; -#endif + for (auto state : _states) { + if (isParallel(state) && HAS_ATTR(state, "id")) { + stream << " :: j == " << toStr(ATTR(state, "documentOrder")) << " -> {" << std::endl; + + std::string doneEvent = _analyzer->macroForLiteral("done.state." + ATTR(state, "id")); + + if (_analyzer->usesComplexEventStruct()) { + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 10); + stream << typeReset << std::endl; + stream << " " << _prefix << "_tmpE.name = " << doneEvent << ";" << std::endl; + + std::list donedatas = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "donedata" , state); + if (donedatas.size() > 0) { + writeRaiseDoneDate(stream, donedatas.front(), 11); + } + doneEvent = _prefix + "_tmpE"; + } + + stream << " " << _prefix << "iQ" << insertOp << doneEvent << ";" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; - stream << " /** TODO:" << std::endl; - stream << " * are we the last final state to leave a parallel state?:" << std::endl; - stream << " * 1. Gather all parallel states in our ancestor chain" << std::endl; - stream << " * 2. Find all states for which these parallels are ancestors" << std::endl; - stream << " * 3. Iterate all active final states and remove their ancestors" << std::endl; - stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl; - stream << " */" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; stream << " }" << std::endl; @@ -2288,150 +2326,120 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << " fi;" << std::endl; stream << " }" << std::endl; stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Done\\n\");" << std::endl; - stream << "#endif" << std::endl; - - stream << "}" << std::endl; + stream << " od;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << "} }" << std::endl; stream << ":: else -> break;" << std::endl; stream << "od" << std::endl; + stream << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << _prefix << "TERMINATE_MACHINE:" << std::endl; + TRACE_EXECUTION("Machine finished"); + + stream << "/* exit all remaining states */" << std::endl; + stream << "i = " << _prefix << "USCXML_NUMBER_STATES;" << std::endl; + stream << "do" << std::endl; + stream << ":: i > 0 -> {" << std::endl; + stream << " i = i - 1;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "config[i] && " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + stream << " /* call all on exit handlers */" << std::endl; + stream << " if" << std::endl; + for (auto i = 0; i < _states.size(); i++) { + std::list onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); + if (onentries.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for exiting state %d", "i"); + for (auto onentry : onentries) + writeExecContent(stream, onentry, 2); + stream << " }" << std::endl; + } + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + stream << " skip;" << std::endl; + stream << " " << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "invocations[i] -> {" << std::endl; + stream << " /* cancel invocations */" << std::endl; + stream << " " << _prefix << "invocations[i] = false;" << std::endl; + stream << " if" << std::endl; + + for (auto machine : _machinesNested) { + stream << " :: i == " << ATTR_CAST(machine.first->getParentNode(), "documentOrder") << " -> {" << std::endl; + stream << " " << machine.second->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " skip;" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << "}" << std::endl; + stream << ":: else -> break;" << std::endl; + stream << "od;" << std::endl; + stream << std::endl; - stream << "} }" << std::endl; - stream << std::endl; - -} - -#if 0 - -void ChartToPromela::writeProgram(std::ostream& stream) { - - _traceTransitions = envVarIsTrue("USCXML_PROMELA_TRANSITION_TRACE"); - _writeTransitionPrintfs = envVarIsTrue("USCXML_PROMELA_TRANSITION_DEBUG"); - - if (!HAS_ATTR(_scxml, "datamodel") || ATTR(_scxml, "datamodel") != "promela") { - LOG(ERROR) << "Can only convert SCXML documents with \"promela\" datamodel"; - return; - } - - if (HAS_ATTR(_scxml, "binding") && ATTR(_scxml, "binding") != "early") { - LOG(ERROR) << "Can only convert for early data bindings"; - return; - } - - // std::cerr << _scxml << std::endl; - - stream << "/* " << (std::string)_baseURL << " */" << std::endl; - stream << std::endl; - - initNodes(); - - for (std::map, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { - if (nestedIter->second->_start == NULL) { - nestedIter->second->interpret(); - } - nestedIter->second->initNodes(); - } - - writeEvents(stream); - stream << std::endl; - writeStates(stream); - stream << std::endl; - writeStrings(stream); - stream << std::endl; - if (_analyzer->usesInPredicate()) { - writeStateMap(stream); - stream << std::endl; - } - if (_historyMembers.size() > 0) { - writeHistoryArrays(stream); - stream << std::endl; - } - writeTypeDefs(stream); - stream << std::endl; - writeDeclarations(stream); - stream << std::endl; - - for (std::map, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { - nestedIter->second->writeDeclarations(stream); - stream << std::endl; - } - - stream << std::endl << "/* global inline functions */" << std::endl; - - if (_analyzer->usesComplexEventStruct()) { - stream << "hidden _event_t tmpE;" << std::endl; - } else { - stream << "hidden int tmpE;" << std::endl; - } - stream << "hidden int tmpIndex;" << std::endl; - + if (_machinesAll->size() > 1 && _analyzer->usesEventField("delay")) { + /* TODO: We nee to clear all events if we were canceled */ + TRACE_EXECUTION("Removing pending events"); + stream << "removePendingEventsFromInvoker(" << _analyzer->macroForLiteral(_invokerid) << ")" << std::endl; + } -#if NEW_DELAY_RESHUFFLE - if (_analyzer->usesEventField("delay")) { - writeInsertWithDelay(stream); - stream << std::endl; - } -#endif + + if (_parent != NULL) { + stream << "/* send done event */" << std::endl; + stream << "if" << std::endl; + stream << ":: " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + + if (_analyzer->usesComplexEventStruct()) { + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 2); + stream << typeReset << std::endl; + stream << " " << _prefix << "_tmpE.name = " << _analyzer->macroForLiteral("done.invoke." + _invokerid) << std::endl; + + if (_analyzer->usesEventField("invokeid")) { + stream << " " << _prefix << "_tmpE.invokeid = " << _analyzer->macroForLiteral(_invokerid) << std::endl; + } + + } else { + stream << " " << _prefix << "_tmpE = " << _analyzer->macroForLiteral("done.invoke." + _invokerid) << std::endl; + } + + + TRACE_EXECUTION("Sending DONE.INVOKE"); + + stream << " " << _parent->_prefix << "eQ!" << _prefix << "_tmpE;" << std::endl; + if (_analyzer->usesEventField("delay")) { + stream << " insertWithDelay(" << _parent->_prefix << "eQ);" << std::endl; + } + stream << "}" << std::endl; + stream << ":: else -> skip" << std::endl; + stream << "fi" << std::endl; + stream << std::endl; - if (_analyzer->usesEventField("delay") && _machines.size() > 0) { - writeDetermineShortestDelay(stream); - stream << std::endl; - writeAdvanceTime(stream); - stream << std::endl; - writeRescheduleProcess(stream); - stream << std::endl; - writeScheduleMachines(stream); - stream << std::endl; - } + } + + stream << std::endl; + + TRACE_EXECUTION("Done"); - { - NodeSet cancels = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "cancel", _scxml, true); - if (cancels.size() > 0) { - writeCancelEvents(stream); - stream << std::endl; - } - } - { - NodeSet invokes = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); - if (invokes.size() > 0 && _analyzer->usesEventField("delay")) { - writeRemovePendingEventsFromInvoker(stream); - stream << std::endl; - } - } - stream << std::endl; - writeEventSources(stream); - stream << std::endl; - writeFSM(stream); - stream << std::endl; - writeMain(stream); + stream << "} }" << std::endl; stream << std::endl; - for (std::map, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { - nestedIter->second->writeFSM(stream); - stream << std::endl; - } - - // write ltl expression for success - std::stringstream acceptingStates; - std::string seperator; - - for (std::map::iterator stateIter = _activeConf.begin(); stateIter != _activeConf.end(); stateIter++) { - FlatStateIdentifier flatId(stateIter->first); - if (std::find(flatId.getActive().begin(), flatId.getActive().end(), "pass") != flatId.getActive().end()) { - acceptingStates << seperator << _prefix << "s == s" << stateIter->second->activeIndex; - seperator = " || "; - } - } - if (acceptingStates.str().size() > 0) { - stream << "ltl { eventually (" << acceptingStates.str() << ") }" << std::endl; - } } -#endif void ChartToPromela::writeIfBlock(std::ostream& stream, std::list& condChain, size_t indent) { if (condChain.size() == 0) @@ -2534,7 +2542,7 @@ std::string ChartToPromela::dataToAssignments(const std::string& prefix, const D std::stringstream retVal; if (data.atom.size() > 0) { if (data.type == Data::VERBATIM) { - retVal << prefix << " = " << _analyzer.macroForLiteral(data.atom) << ";" << std::endl; + retVal << prefix << " = " << _analyzer->macroForLiteral(data.atom) << ";" << std::endl; } else { retVal << prefix << " = " << data.atom << ";" << std::endl; } @@ -2588,30 +2596,279 @@ std::string ChartToPromela::declForRange(const std::string& identifier, long min } } +void ChartToPromela::writeDetermineShortestDelay(std::ostream& stream, int indent) { + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + stream << padding << "inline determineSmallestDelay(smallestDelay, queue) {" << std::endl; + // stream << padding << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + stream << padding << " if" << std::endl; + stream << padding << " :: len(queue) > 0 -> {" << std::endl; + stream << padding << " queue?;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: (tmpE.delay < smallestDelay) -> { smallestDelay = tmpE.delay; }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "}" << std::endl; +} + +void ChartToPromela::writeScheduleMachines(std::ostream& stream, int indent) { + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + stream << padding << "inline scheduleMachines() {" << std::endl; + std::list queues; + queues.push_back("eQ"); + + if (_allowEventInterleaving) + queues.push_back("tmpQ"); + + stream << " /* schedule state-machines with regard to their event's delay */" << std::endl; + stream << " skip;" << std::endl; + stream << " d_step {" << std::endl; + + stream << std::endl << "/* determine smallest delay */" << std::endl; + stream << " int smallestDelay = 2147483647;" << std::endl; + + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " determineSmallestDelay(smallestDelay, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + + TRACE_EXECUTION_V("Smallest delay is %d", "smallestDelay"); + + stream << std::endl << "/* prioritize processes with lowest delay or internal events */" << std::endl; + + for (auto machine : *_machinesAll) { + stream << " rescheduleProcess(smallestDelay, " + << machine.second->_prefix << "procid, " + << machine.second->_prefix << "iQ, " + << machine.second->_prefix << "eQ"; + if (_allowEventInterleaving) { + stream << ", " << machine.second->_prefix << "tmpQ);" << std::endl; + } else { + stream << ");" << std::endl; + } + } + + stream << std::endl << "/* advance time by subtracting the smallest delay from all event delays */" << std::endl; + stream << " if" << std::endl; + stream << " :: (smallestDelay > 0) -> {" << std::endl; + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " advanceTime(smallestDelay, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " set_priority(_pid, 10);" << std::endl << std::endl; + stream << padding << "}" << std::endl; +} + +void ChartToPromela::writeAdvanceTime(std::ostream& stream, int indent) { + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + stream << padding << "inline advanceTime(increment, queue) {" << std::endl; + stream << padding << " tmpIndex = 0;" << std::endl; + stream << padding << " do" << std::endl; + stream << padding << " :: tmpIndex < len(queue) -> {" << std::endl; + stream << padding << " queue?tmpE;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: tmpE.delay >= increment -> tmpE.delay = tmpE.delay - increment;" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi" << std::endl; + stream << padding << " queue!tmpE;" << std::endl; + stream << padding << " tmpIndex++;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> break;" << std::endl; + stream << padding << " od" << std::endl; + stream << padding << "}" << std::endl; +} + +void ChartToPromela::writeInsertWithDelay(std::ostream& stream, int indent) { + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + uint32_t maxExternalQueueLength = 1; + for(auto machine : *_machinesAll) { + maxExternalQueueLength = MAX(maxExternalQueueLength, machine.second->_externalQueueLength); + } + + maxExternalQueueLength += 6; + + if (maxExternalQueueLength <= 1) { + stream << padding << "/* noop for external queues with length <= 1 */" << std::endl; + stream << padding << "inline insertWithDelay(queue) {}" << std::endl; + } + + stream << padding << "hidden _event_t _iwdQ[" << maxExternalQueueLength - 1 << "];" << std::endl; + stream << padding << "hidden int _iwdQLength = 0;" << std::endl; + stream << padding << "hidden int _iwdIdx1 = 0;" << std::endl; + stream << padding << "hidden int _iwdIdx2 = 0;" << std::endl; + stream << padding << "hidden _event_t _iwdTmpE;" << std::endl; + stream << padding << "hidden _event_t _iwdLastE;" << std::endl; + stream << padding << "bool _iwdInserted = false;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << "/* last event in given queue is potentially at wrong position */" << std::endl; + stream << padding << "inline insertWithDelay(queue) {" << std::endl; + stream << padding << " d_step {" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " /* only process for non-trivial queues */" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: len(queue) > 1 -> {" << std::endl; + + TRACE_EXECUTION("Reshuffling events") + + stream << padding << "" << std::endl; + stream << padding << " /* move all events but last over and remember the last one */" << std::endl; + stream << padding << " _iwdIdx1 = 0;" << std::endl; + stream << padding << " _iwdQLength = len(queue) - 1;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " do" << std::endl; + stream << padding << " :: _iwdIdx1 < _iwdQLength -> {" << std::endl; + stream << padding << " queue?_iwdTmpE;" << std::endl; + stream << padding << " _iwdQ[_iwdIdx1].name = _iwdTmpE.name;" << std::endl; + + stream << _analyzer->getTypeAssignment("_iwdQ[_iwdIdx1]", "_iwdTmpE", _analyzer->getType("_event"), 8); + + stream << padding << " _iwdIdx1++;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> break;" << std::endl; + stream << padding << " od" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " queue?_iwdLastE;" << std::endl; + + stream << padding << "" << std::endl; + stream << padding << " /* _iwdQ now contains all but last item in _iwdLastE */" << std::endl; + stream << padding << " assert(len(queue) == 0);" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " /* reinsert into queue and place _iwdLastE correctly */" << std::endl; + stream << padding << " _iwdInserted = false;" << std::endl; + stream << padding << " _iwdIdx2 = 0;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " do" << std::endl; + stream << padding << " :: _iwdIdx2 < _iwdIdx1 -> {" << std::endl; + stream << padding << " _iwdTmpE.name = _iwdQ[_iwdIdx2].name;" << std::endl; + + stream << _analyzer->getTypeAssignment("_iwdTmpE", "_iwdQ[_iwdIdx2]", _analyzer->getType("_event"), 4); + + stream << padding << "" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: _iwdTmpE.delay > _iwdLastE.delay && !_iwdInserted -> {" << std::endl; + stream << padding << " queue!_iwdLastE;" << std::endl; + TRACE_EXECUTION_V("Event %d has delay %d (last)", "_iwdLastE.name, _iwdLastE.delay"); + + stream << padding << " _iwdInserted = true;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " queue!_iwdTmpE;" << std::endl; + TRACE_EXECUTION_V("Event %d has delay %d", "_iwdTmpE.name, _iwdTmpE.delay"); + + stream << padding << " _iwdIdx2++;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> break;" << std::endl; + stream << padding << " od" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: !_iwdInserted -> {" << std::endl; + stream << padding << " queue!_iwdLastE;" << std::endl; + TRACE_EXECUTION_V("Event %d has delay %d (last)", "_iwdLastE.name, _iwdLastE.delay"); + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << "}" << std::endl; +} + +void ChartToPromela::writeRescheduleProcess(std::ostream& stream, int indent) { + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + if (_allowEventInterleaving) { + stream << padding << "inline rescheduleProcess(smallestDelay, procId, internalQ, externalQ, tempQ) {" << std::endl; + } else { + stream << padding << "inline rescheduleProcess(smallestDelay, procId, internalQ, externalQ) {" << std::endl; + } + // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + + stream << padding << " set_priority(procId, 1);" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: len(internalQ) > 0 -> set_priority(procId, 10);" << std::endl; + stream << padding << " :: else {" << std::endl; + stream << padding << " if" << std::endl; + + stream << padding << " :: len(externalQ) > 0 -> {" << std::endl; + stream << padding << " externalQ?;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: smallestDelay == tmpE.delay -> set_priority(procId, 10);" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + + if (_allowEventInterleaving) { + stream << padding << " :: len(tempQ) > 0 -> {" << std::endl; + stream << padding << " tempQ?;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: smallestDelay == tmpE.delay -> set_priority(procId, 10);" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + } + + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "}" << std::endl; +} + void ChartToPromela::writeCancelEvents(std::ostream& stream, int indent) { std::list queues; queues.push_back("eQ"); if (_allowEventInterleaving) queues.push_back("tmpQ"); - stream << "inline cancelSendId(sendIdentifier, invokerIdentifier) {" << std::endl; + stream << "inline cancelSendId(sendIdentifier, source) {" << std::endl; for (auto machine : *_machinesAll) { for (auto queue : queues) { - stream << " cancelSendIdOnQueue(sendIdentifier, " << machine.second->_prefix << queue << ", invokerIdentifier);" << std::endl; + stream << " cancelSendIdOnQueue(sendIdentifier, source, " << machine.second->_prefix << queue << ");" << std::endl; } } stream << "}" << std::endl; stream << std::endl; - stream << "inline cancelSendIdOnQueue(sendIdentifier, queue, invokerIdentifier) {" << std::endl; + stream << "inline cancelSendIdOnQueue(sendIdentifier, source, queue) {" << std::endl; stream << " tmpIndex = 0;" << std::endl; // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); stream << " do" << std::endl; stream << " :: tmpIndex < len(queue) -> {" << std::endl; stream << " queue?tmpE;" << std::endl; stream << " if" << std::endl; - stream << " :: tmpE.invokeid != invokerIdentifier || tmpE.sendid != sendIdentifier || tmpE.delay == 0 -> queue!tmpE;" << std::endl; + stream << " :: tmpE.sendid != sendIdentifier || tmpE.origin != source || tmpE.delay == 0 -> queue!tmpE;" << std::endl; stream << " :: else -> skip;" << std::endl; stream << " fi" << std::endl; stream << " tmpIndex++;" << std::endl; @@ -2621,5 +2878,52 @@ void ChartToPromela::writeCancelEvents(std::ostream& stream, int indent) { stream << "}" << std::endl; } +void ChartToPromela::writeRemovePendingEventsFromInvoker(std::ostream& stream, int indent) { + std::list queues; + queues.push_back("eQ"); + if (_allowEventInterleaving) + queues.push_back("tmpQ"); + + stream << "inline removePendingEventsFromInvoker(invoker) {" << std::endl; + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " removePendingEventsFromInvokerOnQueue(invoker, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + stream << "}" << std::endl; + stream << std::endl; + + stream << "inline removePendingEventsFromInvokerOnQueue(invoker, queue) {" << std::endl; + stream << " tmpIndex = len(queue);" << std::endl; + // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + stream << " do" << std::endl; + stream << " :: tmpIndex > 0 -> {" << std::endl; + stream << " queue?tmpE;" << std::endl; + stream << " if" << std::endl; + stream << " :: false || "; + if (_analyzer->usesEventField("delay")) + stream << "tmpE.delay == 0 || "; + if (_analyzer->usesEventField("invokeid")) + stream << "tmpE.invokeid != invoker" << std::endl; + stream << " -> {" << std::endl; + + TRACE_EXECUTION_V("Reenqueing event %d", "tmpE.name"); + + stream << " queue!tmpE;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + + TRACE_EXECUTION_V("Dropping event %d", "tmpE.name"); + + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " tmpIndex = tmpIndex - 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << "}" << std::endl; +} + } diff --git a/src/uscxml/transform/ChartToPromela.h b/src/uscxml/transform/ChartToPromela.h index cfba760..8df3dca 100644 --- a/src/uscxml/transform/ChartToPromela.h +++ b/src/uscxml/transform/ChartToPromela.h @@ -45,72 +45,58 @@ protected: void writeTransitions(std::ostream& stream); void writeStates(std::ostream& stream); + + void writeCommonTypeDefs(std::ostream& stream); + void writeCommonVariables(std::ostream& stream); void writeTypeDefs(std::ostream& stream); - void writeTypes(std::ostream& stream); + void writeVariables(std::ostream& stream); + +// void writeTypeDefs(std::ostream& stream); +// void writeTypes(std::ostream& stream); void writeMacros(std::ostream& stream); - void writeHelpers(std::ostream& stream); void writeFSM(std::ostream& stream); void writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent = 0); + void writeRaiseDoneDate(std::ostream& stream, const XERCESC_NS::DOMElement* donedata, size_t indent = 0); + void writeStrings(std::ostream& stream); void writeCancelEvents(std::ostream& stream, int indent = 0); + void writeScheduleMachines(std::ostream& stream, int indent = 0); + void writeDetermineShortestDelay(std::ostream& stream, int indent = 0); + void writeRescheduleProcess(std::ostream& stream, int indent = 0); + void writeInsertWithDelay(std::ostream& stream, int indent = 0); + void writeAdvanceTime(std::ostream& stream, int indent = 0); + void writeRemovePendingEventsFromInvoker(std::ostream& stream, int indent = 0); void prepare(); - void bit_clear_all(std::ostream& stream, - const std::string& identifier, - size_t length, - size_t indent = 0); - - void bit_copy(std::ostream& stream, - const std::string& from, - const std::string& to, - size_t length, - size_t indent = 0); - - void bit_or(std::ostream& stream, - const std::string& to, - const std::string& mask, - size_t length, - size_t indent = 0); - - void bit_and(std::ostream& stream, - const std::string& to, - const std::string& mask, - size_t length, - size_t indent = 0); - - void bit_and_not(std::ostream& stream, - const std::string& to, - const std::string& mask, - size_t length, - size_t indent = 0); - - void bit_has_and(std::ostream& stream, - const std::string& a, - const std::string& b, - size_t length, - size_t indent = 0); + void writeBitClearMacro(std::ostream& stream); + void writeBitHasAndMacro(std::ostream& stream); + void writeBitHasAnyMacro(std::ostream& stream); + void writeBitOrMacro(std::ostream& stream); + void writeBitCopyMacro(std::ostream& stream); + void writeBitAndMacro(std::ostream& stream); + void writeBitAndNotMacro(std::ostream& stream); void printBitArray(std::ostream& stream, const std::string& array, size_t length, size_t indent = 0); - PromelaCodeAnalyzer _analyzer; + PromelaCodeAnalyzer* _analyzer = NULL; - ChartToPromela* _parentTopMost; - ChartToPromela* _parent; + ChartToPromela* _parentTopMost = NULL; + ChartToPromela* _parent = NULL; std::string _invokerid; size_t _internalQueueLength = 7; size_t _externalQueueLength = 7; bool _allowEventInterleaving = false; - std::map _machinesPerId; - std::map* _machinesAllPerId = NULL; - std::map _machines; - std::map* _machinesAll = NULL; + std::map _machinesPerId; + std::map* _machinesAllPerId = NULL; + std::map _machinesNested; + std::map* _machinesAll = NULL; std::set _dataModelVars; std::list _varInitializers; // pending initializations for arrays diff --git a/src/uscxml/transform/Transformer.h b/src/uscxml/transform/Transformer.h index fcfda01..5b2fbdb 100644 --- a/src/uscxml/transform/Transformer.h +++ b/src/uscxml/transform/Transformer.h @@ -39,11 +39,17 @@ public: _binding = other.getImpl()->_binding; } + + virtual void writeTo(std::ostream& stream) = 0; virtual operator Interpreter() { throw std::runtime_error("Transformer cannot be interpreted as an Interpreter again"); } + virtual XERCESC_NS::DOMDocument* getDocument() const { + return _document; + } + protected: std::multimap _extensions; std::list _options; diff --git a/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp b/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp index 4d1d8d5..7cb69d7 100644 --- a/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp +++ b/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp @@ -67,16 +67,25 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { if (boost::ends_with(eventName, ".")) eventName = eventName.substr(0, eventName.size() - 1); if (eventName.size() > 0) - _eventTrie.addWord(eventName); + addEvent(eventName); } } } for (auto state : interpreter->_states) { if (HAS_ATTR(state, "id") && (isCompound(state) || isParallel(state))) { - _eventTrie.addWord("done.state." + ATTR(state, "id")); + addEvent("done.state." + ATTR(state, "id")); } } + + std::list invokers = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml, false); + for (auto invoker : invokers) { + addCode("_event.invokeid", interpreter); + + if (HAS_ATTR(invoker, "id")) { + addEvent("done.state." + ATTR(invoker, "id")); + } + } } // add event names from trie to string literals @@ -94,7 +103,9 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { }, interpreter->_scxml); for (auto content : contents) { - std::string contentStr = spaceNormalize(X(((DOMElement*)content)->getFirstChild()->getNodeValue())); + if (!content->hasChildNodes()) + continue; + std::string contentStr = spaceNormalize(X(content->getFirstChild()->getNodeValue())); if (!isNumeric(contentStr.c_str(), 10)) { addLiteral(contentStr); } @@ -192,7 +203,7 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { std::list cancels = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "cancel"}, interpreter->_scxml); if (cancels.size() > 0) { - addCode("_event.invokeid", interpreter); + addCode("_event.origin", interpreter); _usesCancel = true; } @@ -207,6 +218,9 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { // do we need delays? if (HAS_ATTR(send, "delay") || HAS_ATTR(send, "delayexpr")) { + size_t delay = strTo(ATTR(send, "delay")); + if (delay > largestDelay) + largestDelay = delay; addCode("_event.delay", interpreter); #if NEW_DELAY_RESHUFFLE #else @@ -236,6 +250,11 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { } +void PromelaCodeAnalyzer::addEvent(const std::string& eventName) { + addLiteral(eventName); + _eventTrie.addWord(eventName); +} + std::string PromelaCodeAnalyzer::sanitizeCode(const std::string& code) { std::string replaced = code; boost::replace_all(replaced, "\"", "'"); @@ -504,6 +523,8 @@ std::string PromelaCodeAnalyzer::adaptCode(const std::string& code, const std::s if (std::all_of(token.begin(), token.end(), ::isupper) && false) { // assume it is a state-name macro processedStr << code.substr(lastPos, posIter->first - lastPos) << token; + } else if (boost::starts_with(prefix, token)) { + processedStr << code.substr(lastPos, posIter->first - lastPos) << token; } else { processedStr << code.substr(lastPos, posIter->first - lastPos) << prefix << token; } @@ -572,8 +593,11 @@ std::list > PromelaCodeAnalyzer::getTokenPositions(con return posList; } -std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const PromelaTypedef& type, const std::string padding) { +std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const PromelaTypedef& type, size_t indent) { std::stringstream assignment; + std::string padding; + for (size_t i = 0; i < indent; i++) + padding += " "; std::map::const_iterator typeIter = type.types.begin(); while(typeIter != type.types.end()) { @@ -583,7 +607,7 @@ std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const Prom assignment << padding << var << "." << typeIter->first << "[" << i << "] = 0;" << std::endl; } } else if (innerType.types.size() > 0) { - assignment << getTypeReset(var + "." + typeIter->first, typeIter->second, padding); + assignment << getTypeReset(var + "." + typeIter->first, typeIter->second, indent); } else { assignment << padding << var << "." << typeIter->first << " = 0;" << std::endl; } @@ -593,4 +617,27 @@ std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const Prom } +std::string PromelaCodeAnalyzer::getTypeAssignment(const std::string& varTo, const std::string& varFrom, const PromelaTypedef& type, size_t indent) { + std::stringstream assignment; + std::string padding; + for (size_t i = 0; i < indent; i++) + padding += " "; + + std::map::const_iterator typeIter = type.types.begin(); + while(typeIter != type.types.end()) { + const PromelaTypedef& innerType = typeIter->second; + if (innerType.arraySize > 0) { + for (size_t i = 0; i < innerType.arraySize; i++) { + assignment << padding << varTo << "." << typeIter->first << "[" << i << "] = " << varFrom << "." << typeIter->first << "[" << i << "];" << std::endl; + } + } else if (innerType.types.size() > 0) { + assignment << getTypeAssignment(varTo + "." + typeIter->first, varFrom + "." + typeIter->first, typeIter->second, indent); + } else { + assignment << padding << varTo << "." << typeIter->first << " = " << varFrom << "." << typeIter->first << ";" << std::endl; + } + typeIter++; + } + return assignment.str(); +} + } diff --git a/src/uscxml/transform/promela/PromelaCodeAnalyzer.h b/src/uscxml/transform/promela/PromelaCodeAnalyzer.h index 656b24e..83ee684 100644 --- a/src/uscxml/transform/promela/PromelaCodeAnalyzer.h +++ b/src/uscxml/transform/promela/PromelaCodeAnalyzer.h @@ -76,8 +76,10 @@ public: return false; } - std::string getTypeAssignment(const std::string& varTo, const std::string& varFrom, const PromelaTypedef& type, const std::string padding = ""); - std::string getTypeReset(const std::string& var, const PromelaTypedef& type, const std::string padding = ""); + size_t largestDelay = 0; + + std::string getTypeAssignment(const std::string& varTo, const std::string& varFrom, const PromelaTypedef& type, size_t indent = 0); + std::string getTypeReset(const std::string& var, const PromelaTypedef& type, size_t indent = 0); bool usesInPredicate() { return _usesInPredicate; @@ -119,12 +121,12 @@ public: } std::string sanitizeCode(const std::string& code); + void addEvent(const std::string& eventName); + std::string createMacroName(const std::string& literal); protected: - void addEvent(const std::string& eventName); void addState(const std::string& stateName, size_t index); - std::string createMacroName(const std::string& literal); int enumerateLiteral(const std::string& literal, int forceIndex = -1); std::map _strMacros; // macronames for string literals diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index da70494..bc61a2a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -set(TEST_TIMEOUT 15) +set(TEST_TIMEOUT 30) set(TEST_BENCHMARK_ITERATIONS 1000) find_program(SPIN spin) diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in index c5c2bd6..f63b925 100644 --- a/test/ctest/CTestCustom.ctest.in +++ b/test/ctest/CTestCustom.ctest.in @@ -134,67 +134,67 @@ set(CTEST_CUSTOM_TESTS_IGNORE ### Ignore for SPIN model checking # manual tests - # "w3c/spin/promela/test178.scxml" # two identical params in _event.raw - FAILED - # "w3c/spin/promela/test230.scxml" # autoforwarded events are identical - PASSED - # "w3c/spin/promela/test250.scxml" # no onexit in cancelled invoker - PASSED - # "w3c/spin/promela/test307.scxml" # declare variable via script - FAILED - # "w3c/spin/promela/test313.scxml" # assignment of 'return' - # "w3c/spin/promela/test314.scxml" # assignment of 'return' - # "w3c/spin/promela/test415.scxml" # terminate on toplevel final - PASSED + "w3c/spin/promela/test178.scxml" # two identical params in _event.raw - FAILED + "w3c/spin/promela/test230.scxml" # autoforwarded events are identical - PASSED + "w3c/spin/promela/test250.scxml" # no onexit in cancelled invoker - PASSED + "w3c/spin/promela/test307.scxml" # declare variable via script - FAILED + "w3c/spin/promela/test313.scxml" # assignment of 'return' + "w3c/spin/promela/test314.scxml" # assignment of 'return' + "w3c/spin/promela/test415.scxml" # terminate on toplevel final - PASSED # "w3c/spin/promela/test513.txt" # manual test - FAILED - # "w3c/spin/promela/test301.scxml" # reject invalid script - PASSED - # "w3c/spin/promela/test436.scxml" # In(s) -> _x.states[s] prevents completion as NULL dm is hardcoded + "w3c/spin/promela/test301.scxml" # reject invalid script - PASSED + "w3c/spin/promela/test436.scxml" # In(s) -> _x.states[s] prevents completion as NULL dm is hardcoded # fail for syntax - # "w3c/spin/promela/test152.scxml" # test that an illegal array or item value causes error.execution - # "w3c/spin/promela/test156.scxml" # test that an error causes the foreach to stop execution - # "w3c/spin/promela/test224.scxml" # string operation startWith - # "w3c/spin/promela/test277.scxml" # platform creates unbound variable if we assign an illegal value to it - # "w3c/spin/promela/test280.scxml" # late data binding / undeclared variable - # "w3c/spin/promela/test286.scxml" # assignment to a non-declared var causes an error - # "w3c/spin/promela/test294.scxml" # mixed types for event.data via donedata - # "w3c/spin/promela/test309.scxml" # 'return' as an invalid boolean expression ought to eval to false - # "w3c/spin/promela/test311.scxml" # assignment to a non-declared var - # "w3c/spin/promela/test312.scxml" # assignment of 'return' - # "w3c/spin/promela/test322.scxml" # assignment to _sessionid - # "w3c/spin/promela/test324.scxml" # assignment to _name - # "w3c/spin/promela/test325.scxml" # assignment from _ioprocessor - # "w3c/spin/promela/test326.scxml" # assignment from _ioprocessor - # "w3c/spin/promela/test329.scxml" # test that none of the system variables can be modified - # "w3c/spin/promela/test344.scxml" # 'return' as a cond - # "w3c/spin/promela/test346.scxml" # assignment to system variables - # "w3c/spin/promela/test350.scxml" # string concatenation - # "w3c/spin/promela/test354.scxml" # mixed types for event.data - # "w3c/spin/promela/test401.scxml" # variable not declared - # "w3c/spin/promela/test402.scxml" # variable not declared - # "w3c/spin/promela/test487.scxml" # assignment of 'return' - # "w3c/spin/promela/test509.scxml" # string operation contains - # "w3c/spin/promela/test518.scxml" # string operation contains - # "w3c/spin/promela/test519.scxml" # string operation contains - # "w3c/spin/promela/test520.scxml" # string operation contains - # "w3c/spin/promela/test525.scxml" # assumes unbound arrays - # "w3c/spin/promela/test530.scxml" # assigns DOM node to variable - # "w3c/spin/promela/test534.scxml" # string operation contains + "w3c/spin/promela/test152.scxml" # test that an illegal array or item value causes error.execution + "w3c/spin/promela/test156.scxml" # test that an error causes the foreach to stop execution + "w3c/spin/promela/test224.scxml" # string operation startWith + "w3c/spin/promela/test277.scxml" # platform creates unbound variable if we assign an illegal value to it + "w3c/spin/promela/test280.scxml" # late data binding / undeclared variable + "w3c/spin/promela/test286.scxml" # assignment to a non-declared var causes an error + "w3c/spin/promela/test294.scxml" # mixed types for event.data via donedata + "w3c/spin/promela/test309.scxml" # 'return' as an invalid boolean expression ought to eval to false + "w3c/spin/promela/test311.scxml" # assignment to a non-declared var + "w3c/spin/promela/test312.scxml" # assignment of 'return' + "w3c/spin/promela/test322.scxml" # assignment to _sessionid + "w3c/spin/promela/test324.scxml" # assignment to _name + "w3c/spin/promela/test325.scxml" # assignment from _ioprocessor + "w3c/spin/promela/test326.scxml" # assignment from _ioprocessor + "w3c/spin/promela/test329.scxml" # test that none of the system variables can be modified + "w3c/spin/promela/test344.scxml" # 'return' as a cond + "w3c/spin/promela/test346.scxml" # assignment to system variables + "w3c/spin/promela/test350.scxml" # string concatenation + "w3c/spin/promela/test354.scxml" # mixed types for event.data + "w3c/spin/promela/test401.scxml" # variable not declared + "w3c/spin/promela/test402.scxml" # variable not declared + "w3c/spin/promela/test487.scxml" # assignment of 'return' + "w3c/spin/promela/test509.scxml" # string operation contains + "w3c/spin/promela/test518.scxml" # string operation contains + "w3c/spin/promela/test519.scxml" # string operation contains + "w3c/spin/promela/test520.scxml" # string operation contains + "w3c/spin/promela/test525.scxml" # assumes unbound arrays + "w3c/spin/promela/test530.scxml" # assigns DOM node to variable + "w3c/spin/promela/test534.scxml" # string operation contains # fail for semantics - # "w3c/spin/promela/test159.scxml" # error raised causes all subsequent elements to be skipped - # "w3c/spin/promela/test194.scxml" # illegal target for send - # "w3c/spin/promela/test199.scxml" # invalid send type - # "w3c/spin/promela/test216.scxml" # nested SCXML document with srcexpr at invoke - # "w3c/spin/promela/test298.scxml" # non-existent data model location - # "w3c/spin/promela/test331.scxml" # tests _error.type via 'error.execution' - # "w3c/spin/promela/test332.scxml" # tests _error.sendid via 'error.execution' - # "w3c/spin/promela/test343.scxml" # test that illegal produces error.execution - # "w3c/spin/promela/test488.scxml" # illegal expr in produces error.execution - # "w3c/spin/promela/test496.scxml" # tests error.communication with illegal target - # "w3c/spin/promela/test521.scxml" # tests error.communication with illegal target - # "w3c/spin/promela/test528.scxml" # illegal 'expr' produces error.execution - # "w3c/spin/promela/test531.scxml" # uses _ioprocessors.basichttp.location - # "w3c/spin/promela/test532.scxml" # uses _ioprocessors.basichttp.location - # "w3c/spin/promela/test553.scxml" # error in namelist - # "w3c/spin/promela/test554.scxml" # evaluation of 's args causes an error - # "w3c/spin/promela/test577.scxml" # send without target for basichttp + "w3c/spin/promela/test159.scxml" # error raised causes all subsequent elements to be skipped + "w3c/spin/promela/test194.scxml" # illegal target for send + "w3c/spin/promela/test199.scxml" # invalid send type + "w3c/spin/promela/test216.scxml" # nested SCXML document with srcexpr at invoke + "w3c/spin/promela/test298.scxml" # non-existent data model location + "w3c/spin/promela/test331.scxml" # tests _error.type via 'error.execution' + "w3c/spin/promela/test332.scxml" # tests _error.sendid via 'error.execution' + "w3c/spin/promela/test343.scxml" # test that illegal produces error.execution + "w3c/spin/promela/test488.scxml" # illegal expr in produces error.execution + "w3c/spin/promela/test496.scxml" # tests error.communication with illegal target + "w3c/spin/promela/test521.scxml" # tests error.communication with illegal target + "w3c/spin/promela/test528.scxml" # illegal 'expr' produces error.execution + "w3c/spin/promela/test531.scxml" # uses _ioprocessors.basichttp.location + "w3c/spin/promela/test532.scxml" # uses _ioprocessors.basichttp.location + "w3c/spin/promela/test553.scxml" # error in namelist + "w3c/spin/promela/test554.scxml" # evaluation of 's args causes an error + "w3c/spin/promela/test577.scxml" # send without target for basichttp ### Ignore for generated C sources diff --git a/test/ctest/scripts/run_promela_test.cmake b/test/ctest/scripts/run_promela_test.cmake index 271434f..4acf628 100644 --- a/test/ctest/scripts/run_promela_test.cmake +++ b/test/ctest/scripts/run_promela_test.cmake @@ -20,8 +20,8 @@ if(CMD_RESULT) endif() message(STATUS "time for transforming to c") -message(STATUS "${CC_BIN} -DMEMLIM=1024 -DVECTORSZ=8192 -O2 -DXUSAFE -w -o ${OUTDIR}/pan ${OUTDIR}/pan.c") -execute_process(COMMAND time -p ${CC_BIN} -DMEMLIM=1024 -DVECTORSZ=8192 -O2 -DXUSAFE -w -o ${OUTDIR}/pan ${OUTDIR}/pan.c WORKING_DIRECTORY ${OUTDIR} RESULT_VARIABLE CMD_RESULT) +message(STATUS "${CC_BIN} -DMEMLIM=1024 -DVECTORSZ=2048 -O2 -DXUSAFE -w -o ${OUTDIR}/pan ${OUTDIR}/pan.c") +execute_process(COMMAND time -p ${CC_BIN} -DMEMLIM=1024 -DVECTORSZ=2048 -O2 -DXUSAFE -w -o ${OUTDIR}/pan ${OUTDIR}/pan.c WORKING_DIRECTORY ${OUTDIR} RESULT_VARIABLE CMD_RESULT) if(CMD_RESULT) message(FATAL_ERROR "Error running gcc ${CC_BIN}: ${CMD_RESULT}") endif() diff --git a/test/w3c/analyze_tests.pl b/test/w3c/analyze_tests.pl index 7a6ed08..bdb9dd8 100755 --- a/test/w3c/analyze_tests.pl +++ b/test/w3c/analyze_tests.pl @@ -1,5 +1,11 @@ #!/usr/bin/perl -w +#./analyze_tests.pl \ +# w3c pml.topml pml.toc pml.tobin pml.verify \ +#|awk '{printf("%f\n", ($2 + $3 + $4)); }' \ +#|sort -rn \ +#|gnuplot -e "set term png;p '-' u 0:1" > test.png + use strict; use File::Spec; use File::Basename; @@ -148,6 +154,101 @@ while ($block = ) { } } + # New Promela Tests ======== + if ($block =~ + / + uscxml-transform[^\n]+tpml + /x ) { + + if ($block =~ + / + \nreal\s+(\d+.?\d+) + \nuser\s+(\d+.?\d+) + \nsys\s+(\d+.?\d+) + \n--\stime\sfor\stransforming\sto\spromela + /x ) { + $test->{$currTest}->{'pml'}->{'toPML'} = $1; + } + + if ($block =~ + / + \nreal\s+(\d+.?\d+) + \nuser\s+(\d+.?\d+) + \nsys\s+(\d+.?\d+) + \n--\stime\sfor\stransforming\sto\sc + /x ) { + $test->{$currTest}->{'pml'}->{'toC'} = $1; + } + + if ($block =~ + / + \nreal\s+(\d+.?\d+) + \nuser\s+(\d+.?\d+) + \nsys\s+(\d+.?\d+) + \n--\stime\sfor\stransforming\sto\sbin + /x ) { + $test->{$currTest}->{'pml'}->{'toBIN'} = $1; + } + + if ($block =~ + / + \nreal\s+(\d+.?\d+) + \nuser\s+(\d+.?\d+) + \nsys\s+(\d+.?\d+) + \n--\stime\sfor\sverification + /x ) { + $test->{$currTest}->{'pml'}->{'verify'} = $1; + } + + if ($block =~ /State-vector (\d+) byte, depth reached (\d+), errors: (\d+)/) { + $test->{$currTest}->{'pml'}->{'states'}->{'stateSize'} = $1; + $test->{$currTest}->{'pml'}->{'states'}->{'depth'} = $2; + $test->{$currTest}->{'pml'}->{'states'}->{'errors'} = $3; + } + if ($block =~ + / + \s+(\d+)\sstates,\sstored\s\((\d+)\svisited\)\n + \s+(\d+)\sstates,\smatched\n + \s+(\d+)\stransitions\s\(=\svisited\+matched\)\n + \s+(\d+)\satomic\ssteps\n + hash\sconflicts:\s+(\d+)\s\(resolved\) + /x ) { + $test->{$currTest}->{'pml'}->{'states'}->{'stateStored'} = $1; + $test->{$currTest}->{'pml'}->{'states'}->{'stateVisited'} = $2; + $test->{$currTest}->{'pml'}->{'states'}->{'stateMatched'} = $3; + $test->{$currTest}->{'pml'}->{'states'}->{'transitions'} = $4; + $test->{$currTest}->{'pml'}->{'states'}->{'atomicSteps'} = $5; + $test->{$currTest}->{'pml'}->{'hashConflicts'} = $6; + } + + if ($block =~ + / + \s+([\d\.]+)\sequivalent\smemory\susage\sfor\sstates.* + \s+([\d\.]+)\sactual\smemory\susage\sfor\sstates\n + \s+([\d\.]+)\smemory\sused\sfor\shash\stable\s\(-w(\d+)\)\n + \s+([\d\.]+)\smemory\sused\sfor\sDFS\sstack\s\(-m(\d+)\) + \s+([\d\.]+)\stotal\sactual\smemory\susage + /x ) { + $test->{$currTest}->{'pml'}->{'memory'}->{'states'} = $1; + $test->{$currTest}->{'pml'}->{'memory'}->{'actual'} = $2; + $test->{$currTest}->{'pml'}->{'memory'}->{'hashTable'} = $3; + $test->{$currTest}->{'pml'}->{'memory'}->{'hashLimit'} = $4; + $test->{$currTest}->{'pml'}->{'memory'}->{'dfsStack'} = $5; + $test->{$currTest}->{'pml'}->{'memory'}->{'dfsLimit'} = $6; + $test->{$currTest}->{'pml'}->{'memory'}->{'total'} = $7; + } + + if ($block =~ + / + pan:\selapsed\stime\s(.*)\sseconds\n + /x ) { + $test->{$currTest}->{'pml'}->{'duration'} = $1; + } + + } + + + # Promela Test ======== if ($block =~ / -- cgit v0.12