diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/uscxml-analyze.cpp | 193 | ||||
-rw-r--r-- | apps/uscxml-browser.cpp | 36 | ||||
-rw-r--r-- | apps/uscxml-transform.cpp | 119 |
3 files changed, 291 insertions, 57 deletions
diff --git a/apps/uscxml-analyze.cpp b/apps/uscxml-analyze.cpp new file mode 100644 index 0000000..75ec48c --- /dev/null +++ b/apps/uscxml-analyze.cpp @@ -0,0 +1,193 @@ +#include "uscxml/config.h" +#include "uscxml/Interpreter.h" +#include "uscxml/transform/ChartToFSM.h" +#include "uscxml/DOMUtils.h" +#include <glog/logging.h> +#include <fstream> +#include <iostream> + +#include "uscxml/Factory.h" +#include "uscxml/server/HTTPServer.h" +#include "getopt.h" + +#ifdef HAS_SIGNAL_H +#include <signal.h> +#endif + +#ifdef HAS_EXECINFO_H +#include <execinfo.h> +#endif + +#ifdef HAS_DLFCN_H +#include <dlfcn.h> +#endif + +#define ANNOTATE(envKey, annotationParam) \ +envVarIsTrue(envKey) || std::find(annotations.begin(), annotations.end(), annotationParam) != annotations.end() + +void printUsageAndExit(const char* progName) { + // remove path from program name + std::string progStr(progName); + if (progStr.find_last_of(PATH_SEPERATOR) != std::string::npos) { + progStr = progStr.substr(progStr.find_last_of(PATH_SEPERATOR) + 1, progStr.length() - (progStr.find_last_of(PATH_SEPERATOR) + 1)); + } + + printf("%s version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n", progStr.c_str()); + printf("Usage\n"); + printf("\t%s", progStr.c_str()); +#ifdef BUILD_AS_PLUGINS + printf(" [-p pluginPath]"); +#endif + printf(" [URL]"); + printf("\n"); + exit(1); +} + +int main(int argc, char** argv) { + using namespace uscxml; + + std::string outType; + std::string pluginPath; + std::string inputFile; + std::string outputFile; + std::list<std::string> annotations; + +#if defined(HAS_SIGNAL_H) && !defined(WIN32) + signal(SIGPIPE, SIG_IGN); +#endif + + // setup logging + google::LogToStderr(); + google::InitGoogleLogging(argv[0]); + + optind = 0; + opterr = 0; + + struct option longOptions[] = { + {"help", required_argument, 0, 'p'}, + {"plugin-path", required_argument, 0, 'p'}, + {"loglevel", required_argument, 0, 'l'}, + {0, 0, 0, 0} + }; + + // parse global options + int optionInd = 0; + int option; + for (;;) { + option = getopt_long_only(argc, argv, "p:l:h", longOptions, &optionInd); + if (option == -1) { + break; + } + switch(option) { + // cases without short option + case 0: { + break; + } + // cases with short-hand options + case 'p': + pluginPath = optarg; + break; + case 'l': + break; + case 'h': + case '?': { + printUsageAndExit(argv[0]); + break; + } + default: + break; + } + } + + if (optind < argc) { + inputFile = argv[optind]; + } + + // register plugins + if (pluginPath.length() > 0) { + Factory::setDefaultPluginPath(pluginPath); + } + + // start HTTP server + HTTPServer::getInstance(31444, 31445, NULL); + + Interpreter interpreter; + try { + if (inputFile.size() == 0 || inputFile == "-") { + LOG(INFO) << "Reading SCXML from STDIN"; + std::stringstream ss; + std::string line; + while (std::getline(std::cin, line)) { + ss << line; + } + URL tmp("anonymous.scxml"); + tmp.toAbsoluteCwd(); + interpreter = Interpreter::fromXML(ss.str(), tmp); + } else { + interpreter = Interpreter::fromURL(inputFile); + } + if (!interpreter) { + LOG(ERROR) << "Cannot create interpreter from " << inputFile; + exit(EXIT_FAILURE); + } + + // analyze here + Arabica::XPath::NodeSet<std::string> states = interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "state"); + Arabica::XPath::NodeSet<std::string> final = interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "final"); + Arabica::XPath::NodeSet<std::string> parallels = interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "parallel"); + Arabica::XPath::NodeSet<std::string> shallowHistories = interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "history[@type='shallow']"); + shallowHistories.push_back(interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "history[not(@type)]")); + Arabica::XPath::NodeSet<std::string> deepHistories = interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "history[@type='deep']"); + Arabica::XPath::NodeSet<std::string> transitions = interpreter.getNodeSetForXPath("//" + interpreter.getNameSpaceInfo().xpathPrefix + "transition"); + + std::cout << "# Number of elements" << std::endl; + std::cout << "nr_states: " << (states.size() + final.size() + parallels.size()) << std::endl; + std::cout << "nr_parallel: " << parallels.size() << std::endl; + std::cout << "nr_hist_flat: " << shallowHistories.size() << std::endl; + std::cout << "nr_hist_deep: " << deepHistories.size() << std::endl; + std::cout << "nr_trans: " << transitions.size() << std::endl; + + + std::cout << "# Transition Histogram: number of transitions, number of active configurations" << std::endl; + + size_t numberOfLegalConfs = 0; + size_t lastBin = 0; + std::map<size_t, size_t> histogram = Complexity::getTransitionHistogramm(interpreter.getDocument().getDocumentElement()); + for (std::map<size_t, size_t>::iterator binIter = histogram.begin(); binIter != histogram.end(); binIter++) { + while (binIter->first > lastBin) { + std::cout << "th: " << toStr(lastBin++) << ", 0" << std::endl; + } + std::cout << "th: " << toStr(binIter->first) << ", " << binIter->second << std::endl; + numberOfLegalConfs += binIter->second; + lastBin = binIter->first + 1; + } + + std::stringstream transPowerSetSS; + std::string transPowerSetSeperator = ""; + for (std::map<size_t, size_t>::reverse_iterator binIter = histogram.rbegin(); binIter != histogram.rend(); binIter++) { + transPowerSetSS << transPowerSetSeperator << binIter->second << " * " << "2**" << binIter->first; + transPowerSetSeperator = " + "; + } + std::cout << "# Sum of Powersets:" << std::endl; + std::cout << "ps_sum: " << transPowerSetSS.str() << std::endl; + std::cout << "# Upper bounds:" << std::endl; + std::cout << "# \tActive configurations: " << std::endl; + std::cout << "up_ac: " << numberOfLegalConfs << std::endl; + std::cout << "# \tGlobal configurations: " << std::endl; + std::cout << "up_gc: " << Complexity::stateMachineComplexity(interpreter.getDocument().getDocumentElement()) << std::endl; + + std::cout << "# \tGlobal configurations (no history): " << std::endl; + std::cout << "up_gcnh: " << Complexity::stateMachineComplexity(interpreter.getDocument().getDocumentElement(), uscxml::Complexity::IGNORE_HISTORY) << std::endl; + + std::cout << "# \tGlobal configurations (no nested data): " << std::endl; + std::cout << "up_gcnd: " << Complexity::stateMachineComplexity(interpreter.getDocument().getDocumentElement(), uscxml::Complexity::IGNORE_NESTED_DATA) << std::endl; + + std::cout << "# \tGlobal configurations (no nested data, no history): " << std::endl; + std::cout << "up_gcnhd: " << Complexity::stateMachineComplexity(interpreter.getDocument().getDocumentElement(), uscxml::Complexity::IGNORE_HISTORY_AND_NESTED_DATA) << std::endl; + + } catch (Event e) { + std::cout << e << std::endl; + } + + return EXIT_SUCCESS; +}
\ No newline at end of file diff --git a/apps/uscxml-browser.cpp b/apps/uscxml-browser.cpp index 87b1b1d..0562ba7 100644 --- a/apps/uscxml-browser.cpp +++ b/apps/uscxml-browser.cpp @@ -22,40 +22,6 @@ #include <dlfcn.h> #endif -class VerboseMonitor : public uscxml::InterpreterMonitor { - void onStableConfiguration(uscxml::Interpreter interpreter) { - printConfig(interpreter.getConfiguration()); - } - - void beforeProcessingEvent(uscxml::Interpreter interpreter, const uscxml::Event& event) { - switch (event.eventType) { - case uscxml::Event::INTERNAL: - std::cout << "Internal Event: " << event.name << std::endl; - break; - case uscxml::Event::EXTERNAL: - std::cout << "External Event: " << event.name << std::endl; - break; - case uscxml::Event::PLATFORM: - std::cout << "Platform Event: " << event.name << std::endl; - break; - } - } - - void beforeCompletion(uscxml::Interpreter interpreter) { - printConfig(interpreter.getConfiguration()); - } - - void printConfig(const Arabica::XPath::NodeSet<std::string>& config) { - std::string seperator; - std::cout << "Config: {"; - for (int i = 0; i < config.size(); i++) { - std::cout << seperator << ATTR_CAST(config[i], "id"); - seperator = ", "; - } - std::cout << "}" << std::endl; - } -}; - #ifdef CMAKE_BUILD_TYPE_DEBUG #ifdef HAS_EXECINFO_H @@ -206,7 +172,7 @@ int main(int argc, char** argv) { interpreter.setCapabilities(options.getCapabilities()); if (options.verbose) { - VerboseMonitor* vm = new VerboseMonitor(); + StateTransitionMonitor* vm = new StateTransitionMonitor(); interpreter.addMonitor(vm); } diff --git a/apps/uscxml-transform.cpp b/apps/uscxml-transform.cpp index d8a9013..055c1ae 100644 --- a/apps/uscxml-transform.cpp +++ b/apps/uscxml-transform.cpp @@ -1,6 +1,7 @@ #include "uscxml/config.h" #include "uscxml/Interpreter.h" #include "uscxml/transform/ChartToFlatSCXML.h" +#include "uscxml/transform/ChartToTex.h" #include "uscxml/transform/ChartToMinimalSCXML.h" #include "uscxml/transform/ChartToPromela.h" #include "uscxml/DOMUtils.h" @@ -24,6 +25,9 @@ #include <dlfcn.h> #endif +#define ANNOTATE(envKey, annotationParam) \ +envVarIsTrue(envKey) || std::find(annotations.begin(), annotations.end(), annotationParam) != annotations.end() + class VerboseMonitor : public uscxml::InterpreterMonitor { void onStableConfiguration(uscxml::Interpreter interpreter) { printConfig(interpreter.getConfiguration()); @@ -58,20 +62,29 @@ void printUsageAndExit(const char* progName) { printf("%s version " USCXML_VERSION " (" CMAKE_BUILD_TYPE " build - " CMAKE_COMPILER_STRING ")\n", progStr.c_str()); printf("Usage\n"); printf("\t%s", progStr.c_str()); - printf(" [-t pml|flat] [-v] [-lN]"); + printf(" [-t pml|flat|min|tex] [-a {OPTIONS}] [-v] [-lN]"); #ifdef BUILD_AS_PLUGINS printf(" [-p pluginPath]"); #endif printf(" [-i URL] [-o FILE]"); printf("\n"); printf("Options\n"); - printf("\t-t flat : flatten to SCXML state-machine\n"); - printf("\t-t pml : convert to spin/promela program\n"); - printf("\t-t min : minimize SCXML state-chart\n"); - printf("\t-v : be verbose\n"); - printf("\t-lN : Set loglevel to N\n"); - printf("\t-i URL : Input file (defaults to STDIN)\n"); - printf("\t-o FILE : Output file (defaults to STDOUT)\n"); + printf("\t-t flat : flatten to SCXML state-machine\n"); + printf("\t-t pml : convert to spin/promela program\n"); + printf("\t-t min : minimize SCXML state-chart\n"); + printf("\t-t tex : write global state transition table as tex file\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 '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-v : be verbose\n"); + printf("\t-lN : Set loglevel to N\n"); + printf("\t-i URL : Input file (defaults to STDIN)\n"); + printf("\t-o FILE : Output file (defaults to STDOUT)\n"); printf("\n"); exit(1); } @@ -84,7 +97,8 @@ int main(int argc, char** argv) { std::string pluginPath; std::string inputFile; std::string outputFile; - + std::list<std::string> annotations; + #if defined(HAS_SIGNAL_H) && !defined(WIN32) signal(SIGPIPE, SIG_IGN); #endif @@ -99,9 +113,10 @@ int main(int argc, char** argv) { struct option longOptions[] = { {"verbose", no_argument, 0, 'v'}, {"type", required_argument, 0, 't'}, + {"annotate", required_argument, 0, 'a'}, {"plugin-path", required_argument, 0, 'p'}, {"input-file", required_argument, 0, 'i'}, - {"output-file", required_argument, 0, 'o'}, + {"output-file", required_argument, 0, 'o'}, {"loglevel", required_argument, 0, 'l'}, {0, 0, 0, 0} }; @@ -110,7 +125,7 @@ int main(int argc, char** argv) { int optionInd = 0; int option; for (;;) { - option = getopt_long_only(argc, argv, "+vp:t:i:o:l:", longOptions, &optionInd); + option = getopt_long_only(argc, argv, "+vp:t:i:o:l:a:", longOptions, &optionInd); if (option == -1) { break; } @@ -132,6 +147,9 @@ int main(int argc, char** argv) { case 'i': inputFile = optarg; break; + case 'a': + annotations = InterpreterImpl::tokenize(optarg, ','); + break; case 'o': outputFile = optarg; break; @@ -145,18 +163,45 @@ int main(int argc, char** argv) { } } - if (outType.length() == 0 && outputFile.length() > 0) { - // try to get type from outfile extension - size_t dotPos = outputFile.find_last_of("."); - if (dotPos != std::string::npos) { - outType= outputFile.substr(dotPos + 1); - } - } + // make sure given annotation options are available in the environment + if(ANNOTATE("USCXML_ANNOTATE_GLOBAL_STATE_STEP", "step")) + setenv("USCXML_ANNOTATE_GLOBAL_STATE_STEP", "YES", 1); + + if (ANNOTATE("USCXML_ANNOTATE_GLOBAL_TRANS_PRIO", "priority")) + setenv("USCXML_ANNOTATE_GLOBAL_TRANS_PRIO", "YES", 1); + + if (ANNOTATE("USCXML_ANNOTATE_VERBOSE_COMMENTS", "verbose")) + setenv("USCXML_ANNOTATE_VERBOSE_COMMENTS", "YES", 1); + + if(ANNOTATE("USCXML_ANNOTATE_GLOBAL_TRANS_MEMBERS", "members")) + setenv("USCXML_ANNOTATE_GLOBAL_TRANS_MEMBERS", "YES", 1); + + if(ANNOTATE("USCXML_ANNOTATE_GLOBAL_TRANS_SENDS", "sends")) + setenv("USCXML_ANNOTATE_GLOBAL_TRANS_SENDS", "YES", 1); + + if(ANNOTATE("USCXML_ANNOTATE_GLOBAL_TRANS_RAISES", "raises")) + setenv("USCXML_ANNOTATE_GLOBAL_TRANS_RAISES", "YES", 1); + + if(ANNOTATE("USCXML_ANNOTATE_PROGRESS", "progress")) + setenv("USCXML_ANNOTATE_PROGRESS", "YES", 1); + +// if (outType.length() == 0 && outputFile.length() > 0) { +// // try to get type from outfile extension +// size_t dotPos = outputFile.find_last_of("."); +// if (dotPos != std::string::npos) { +// outType= outputFile.substr(dotPos + 1); +// } +// } - if (outType.length() == 0) - printUsageAndExit(argv[0]); +// if (outType.length() == 0) +// printUsageAndExit(argv[0]); - if (outType != "flat" && outType != "scxml" && outType != "pml" && outType != "min") + if (outType != "flat" && + outType != "scxml" && + outType != "pml" && + outType != "min" && + outType != "tex" && + std::find(annotations.begin(), annotations.end(), "priority") == annotations.end()) printUsageAndExit(argv[0]); // register plugins @@ -200,7 +245,19 @@ int main(int argc, char** argv) { exit(EXIT_SUCCESS); } - if (outType == "scxml" || outType == "flat") { + if (outType == "tex") { + if (outputFile.size() == 0 || outputFile == "-") { + ChartToTex::transform(interpreter).writeTo(std::cout); + } else { + std::ofstream outStream; + outStream.open(outputFile.c_str()); + ChartToTex::transform(interpreter).writeTo(outStream); + outStream.close(); + } + exit(EXIT_SUCCESS); + } + + if (outType == "flat") { if (outputFile.size() == 0 || outputFile == "-") { ChartToFlatSCXML::transform(interpreter).writeTo(std::cout); } else { @@ -224,6 +281,24 @@ int main(int argc, char** argv) { exit(EXIT_SUCCESS); } +#if 1 + if (annotations.size() > 0) { + ChartToFSM annotater(interpreter); + if (std::find(annotations.begin(), annotations.end(), "priority") != annotations.end()) + annotater.indexTransitions(); + + if (outputFile.size() == 0 || outputFile == "-") { + std::cout << annotater.getDocument(); + } else { + std::ofstream outStream; + outStream.open(outputFile.c_str()); + outStream << annotater.getDocument(); + outStream.close(); + } + exit(EXIT_SUCCESS); + } +#endif + } catch (Event e) { std::cout << e << std::endl; } |