summaryrefslogtreecommitdiffstats
path: root/scc
diff options
context:
space:
mode:
authorNo'am Rosenthal <noam.rosenthal@nokia.com>2009-08-06 17:05:28 -0700
committerNo'am Rosenthal <noam.rosenthal@nokia.com>2009-08-06 17:05:28 -0700
commit82c237bd9ed36c2140ccfbde994a80b321594d97 (patch)
treeee52404159165df0f5f29828d4f48ad0425aeede /scc
parent7092b921c0c18f7ba202eb5a01934cc1a850c04a (diff)
perlimiary statechart compiler (scxml -> c++)
Diffstat (limited to 'scc')
-rw-r--r--scc/main.cpp25
-rw-r--r--scc/scc.pro16
-rw-r--r--scc/scc.qrc6
-rw-r--r--scc/scc.xslt266
4 files changed, 313 insertions, 0 deletions
diff --git a/scc/main.cpp b/scc/main.cpp
new file mode 100644
index 0000000..4ed1aff
--- /dev/null
+++ b/scc/main.cpp
@@ -0,0 +1,25 @@
+#include <QtCore/QCoreApplication>
+#include <QXmlQuery>
+#include <QUrl>
+#include <QStringList>
+#include <QFile>
+#include <QFileInfo>
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+ QXmlQuery query(QXmlQuery::XSLT20);
+ QUrl target = QUrl::fromLocalFile(a.arguments()[1]);
+ query.setFocus(target);
+ QFile q(":/scc/scc.xslt");
+ q.open(QIODevice::ReadOnly);
+ query.bindVariable("target",QXmlItem(QFileInfo(target.toLocalFile()).baseName()));
+ query.setQuery(QString(q.readAll()));
+ QString s;
+ query.evaluateTo(&s);
+ s = s.replace("&lt;","<").replace("&gt;",">").replace("&amp;","&");
+ QFile f(a.arguments()[2]);
+ f.open(QIODevice::WriteOnly);
+ f.write(s.toUtf8());
+ return 0;
+// return a.exec();
+}
diff --git a/scc/scc.pro b/scc/scc.pro
new file mode 100644
index 0000000..db41f1e
--- /dev/null
+++ b/scc/scc.pro
@@ -0,0 +1,16 @@
+# -------------------------------------------------
+# Project created by QtCreator 2009-08-02T10:07:01
+# -------------------------------------------------
+QT += network \
+ xmlpatterns
+QT -= gui
+TARGET = scc
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+SOURCES += main.cpp
+OTHER_FILES += scc.xslt \
+ test.scxml \
+ scc-example.hh \
+ xipr.xsl
+RESOURCES += scc.qrc
diff --git a/scc/scc.qrc b/scc/scc.qrc
new file mode 100644
index 0000000..a03d93a
--- /dev/null
+++ b/scc/scc.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/scc" >
+ <file>scc.xslt</file>
+ <file>xipr.xsl</file>
+ </qresource>
+</RCC>
diff --git a/scc/scc.xslt b/scc/scc.xslt
new file mode 100644
index 0000000..de42521
--- /dev/null
+++ b/scc/scc.xslt
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:template name="smname"><xsl:choose><xsl:when test="string(/scxml/@name)=''"><xsl:value-of select="$target" /></xsl:when>
+ <xsl:otherwise><xsl:value-of select="/scxml/@name" /></xsl:otherwise></xsl:choose>
+</xsl:template>
+<xsl:template mode="stateid" match="*">
+ <xsl:choose >
+ <xsl:when test="name()='scxml'">this</xsl:when>
+ <xsl:when test="string(@id) != ''" >state_<xsl:value-of select="@id" /></xsl:when>
+ <xsl:otherwise>state_<xsl:value-of select="generate-id()" /></xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<xsl:template mode="execContext" match="if">
+ if (<xsl:value-of select="@cond" />) {
+ <xsl:apply-templates mode="execContext" />
+ }
+</xsl:template>
+<xsl:template mode="execContext" match="else">
+ } else {
+</xsl:template>
+<xsl:template mode="execContext" match="elseif">
+ } else if (<xsl:value-of select="@cond" />) {
+</xsl:template>
+<xsl:template mode="execContext" match="log">
+ QDebug((QtMsgType)<xsl:if test="string(@level)=''">0</xsl:if><xsl:value-of select="@level" />) &lt;&lt; "<xsl:value-of select="@label" />" &lt;&lt; <xsl:value-of select="@expr" />;
+</xsl:template>
+<xsl:template mode="execContext" match="assign">
+ <xsl:if test="string(@dataid) != ''">
+ set_<xsl:value-of select="@dataid" />(<xsl:value-of select="@expr" />);
+ </xsl:if>
+</xsl:template>
+<xsl:template mode="execContext" match="raise|send">
+ <xsl:choose>
+ <xsl:when test="name()='raise' or target='_internal'">postInternalEvent(</xsl:when>
+ <xsl:otherwise><xsl:if test="string(@id)!=''">
+ eventSenders[<xsl:value-of select="@id" />] = </xsl:if>new SCC_EventSender(this,<xsl:if test="string(@delay)=''">0</xsl:if>
+ <xsl:value-of select="@delay" />,
+ </xsl:otherwise>
+ </xsl:choose>new QSignalEvent(<xsl:if
+ test="string(@target)=''">this</xsl:if><xsl:value-of
+ select="@target" />,(*metaObject()).indexOfSignal("<xsl:value-of select="replace(@event,'\.','__')" />"),QVariantList()<xsl:for-each
+ select="param"><xsl:text><![CDATA[<<]]></xsl:text> QVariant(<xsl:value-of select="@expr" /><xsl:value-of select="text()" />)
+ </xsl:for-each>));
+</xsl:template>
+<xsl:template mode="execContext" match="cancel">
+ { QObject* obj = eventSenders[<xsl:value-of select="@id" />]; if (obj) { (*obj).cancel(); }
+</xsl:template>
+
+<xsl:template match="/">
+#include "QStateMachine"
+#include "QSignalTransition"
+<xsl:if test="count(//send[@target!='_internal']) != 0">
+#include "QTimer"
+</xsl:if>
+<xsl:if test="count(//final)!=0">
+ #include "QFinalState"
+</xsl:if>
+<xsl:if test="count(//history)!=0">
+ #include "QHistoryState"
+</xsl:if>
+#include "QHash"
+#include "QSignalEvent"
+#include "QEventTransition"
+<xsl:if test="count(//log)!=0">
+#include "QDebug"
+</xsl:if>
+#ifndef __SMCLASS_<xsl:call-template name="smname" />_H
+#define __SMCLASS_<xsl:call-template name="smname" />_H
+class SMClass_<xsl:call-template name="smname" />;
+ <xsl:if test="count(//transition[string(@event)='' and string(@cond)=''])!=0">
+ class SCC_UnconditionalTransition : public QAbstractTransition
+ {
+ public:
+ SCC_UnconditionalTransition(QState* s)
+ : QAbstractTransition(s) {}
+ protected:
+ void onTransition(QEvent *) {}
+ bool eventTest(QEvent *) { return true; }
+ };
+ </xsl:if>
+ <xsl:if test="count(//send[string(@target)!='_internal'])!=0">
+ class SCC_EventSender : public QTimer
+ {
+ Q_OBJECT
+ private:
+ QStateMachine* machine;
+ QEvent* event;
+ public:
+ SCC_EventSender(QStateMachine* m, int delay, QEvent* e) : QTimer(m), machine(m), event(e)
+ {
+ setInterval(delay);
+ setSingleShot(true);
+ connect(this,SIGNAL(timeout()),this,SLOT(send()));
+ }
+ public Q_SLOTS:
+ void cancel() { stop(); deleteLater(); }
+ void send() { machine->postEvent(event); }
+ };
+ </xsl:if>
+ <xsl:if test="count(//transition[string(@cond) != '']) !=0">
+namespace {
+ <xsl:for-each select="//transition[string(@cond) != '']">
+ class Transition_<xsl:value-of select="generate-id()" /> : public Q<xsl:if test="string(@event) != ''">Signal</xsl:if>Transition
+ {
+ SMClass_<xsl:call-template name="smname" />* stateMachine;
+ public:
+ Transition_<xsl:value-of select="generate-id()" />(QState* parent)
+ : Q<xsl:if test="string(@event) != ''">Signal</xsl:if>Transition(parent),stateMachine((SMClass_<xsl:call-template name="smname" />*)(*parent).machine())
+ {
+ }
+
+ protected:
+ bool eventTest(QEvent* e);
+ };
+
+ </xsl:for-each>
+};
+ </xsl:if>
+class SMClass_<xsl:call-template name="smname" /> : public QStateMachine
+{
+ Q_OBJECT
+<xsl:for-each select="//datamodel/data">
+ Q_PROPERTY(<xsl:value-of select="concat(@type,' ')" /> <xsl:value-of select="@id" /> READ get_<xsl:value-of select="@id" /> WRITE set_<xsl:value-of select="@id" /> NOTIFY <xsl:value-of select="@id" />_changed)
+</xsl:for-each>
+<xsl:for-each select="//transition/@animation">
+ Q_PROPERTY(QAbstractAnimation* <xsl:value-of select="string()" /> READ anim_<xsl:value-of select="string()" /> WRITE setAnim_<xsl:value-of select="string()" />)
+</xsl:for-each>
+
+ public:
+ SMClass_<xsl:call-template name="smname" />(QObject* o) : QStateMachine(o) {}
+ <xsl:for-each select="//state|//parallel|//initial[count(transition/*)!=0]">
+ QState* <xsl:apply-templates mode="stateid" select="current()" />;</xsl:for-each>
+ <xsl:for-each select="//final">
+ QFinalState* <xsl:apply-templates mode="stateid" select="current()" />;
+ </xsl:for-each>
+ <xsl:for-each select="//history">
+ QHistoryState* <xsl:apply-templates mode="stateid" select="current()" />;
+ </xsl:for-each>
+ <xsl:for-each select="//transition[string(@cond) != '']">
+ bool testCondition_<xsl:value-of select="generate-id()" />(const QEvent &amp; _event)
+ {
+ Q_UNUSED(_event)
+ return <xsl:if test="string(@cond)=''">true</xsl:if><xsl:value-of select="@cond"/>;
+ }
+ </xsl:for-each>
+ <xsl:for-each select="//datamodel/data">
+ <xsl:value-of select="@type" /> get_<xsl:value-of select="@id" />() const
+ {
+ return _data.<xsl:value-of select="@id" />;
+ }
+ void set_<xsl:value-of select="@id" />(const <xsl:value-of select="@type" /> &amp; value)
+ {
+ _data.<xsl:value-of select="@id" /> = value;
+ emit <xsl:value-of select="@id" />_changed(value);
+ }
+ </xsl:for-each>
+ <xsl:if test="count(//datamodel/data) != 0">
+ protected:
+ struct {
+ <xsl:for-each select="//datamodel/data">
+ <xsl:text> </xsl:text><xsl:value-of select="@type" /><xsl:text> </xsl:text><xsl:value-of select="@id" />;</xsl:for-each>
+ } _data;
+ </xsl:if>
+ <xsl:if test="(count(//datamodel/data)+count(/scxml/script))!=0">
+ void initScript()
+ {
+<xsl:for-each select="//datamodel/data">
+ <xsl:if test="string(@expr) != ''">
+ _data.<xsl:value-of select="@id" /> = <xsl:value-of select="@expr"/><xsl:value-of select="text()"/>;
+ </xsl:if>
+</xsl:for-each>
+ <xsl:value-of select="/scxml/script/text()" />
+ }
+</xsl:if>
+ private Q_SLOTS:
+ <xsl:for-each select="//transition|//onentry|//onexit"><xsl:if test="count(*) != 0">
+ void exec_<xsl:value-of select="generate-id()" />()
+ {
+ <xsl:apply-templates mode="execContext" />
+ }
+ </xsl:if></xsl:for-each>
+ Q_SIGNALS:<xsl:for-each select="distinct-values(//node()[not (starts-with(@event,'done.state.') or contains(@event,':'))]/@event)">
+ void event_<xsl:value-of select="replace(string(),'\.','__')" />();</xsl:for-each>
+ <xsl:for-each select="//datamodel/data">
+ void <xsl:value-of select="@id" />_changed(const <xsl:value-of select="@type" /> &amp;);
+ </xsl:for-each>
+ <xsl:if test="count(//property)!=0">
+ protected:
+#ifndef QT_NO_PROPERTIES
+ virtual void endSelectTransitions(QEvent *event)
+ {
+ <xsl:for-each select="//property">
+ (*<xsl:apply-templates mode="stateid" select=".." />).assignProperty(<xsl:value-of
+ select="@object" />,"<xsl:value-of select="@name" />",QVariant(<xsl:value-of select="@expr" />));
+ </xsl:for-each>
+ }
+#endif
+ </xsl:if>
+<xsl:if test="count(//send[string(@target)!='internal']) != 0">
+ private:
+ <xsl:text><![CDATA[QHash<QString,SCC_EventSender>]]></xsl:text> _eventSenders;
+</xsl:if>
+ public:
+ void setupStateMachine()
+ {
+ setObjectName("<xsl:call-template name="smname" />");
+ <xsl:for-each select="//state|//parallel|//final|//history|//initial">
+ <xsl:apply-templates mode="stateid" select="." /> = new <xsl:choose>
+ <xsl:when test="name()='final'">QFinalState</xsl:when>
+ <xsl:when test="name()='history'">QHistoryState</xsl:when>
+ <xsl:otherwise>QState</xsl:otherwise>
+ </xsl:choose>(<xsl:apply-templates mode="stateid" select=".." />);
+ (*<xsl:apply-templates mode="stateid" select="." />).setObjectName("<xsl:value-of select="@id" />");
+ <xsl:if
+ test="name()='initial' or @id=../@initial">
+ (*<xsl:apply-templates mode="stateid" select=".." />).setInitialState(<xsl:apply-templates mode="stateid" select="." />);</xsl:if>
+ <xsl:if test="name()='parallel'">
+ (*<xsl:apply-templates mode="stateid" select="." />).setChildMode(ParallelStates);
+ </xsl:if>
+ <xsl:if test="name()='history'">
+ (*<xsl:apply-templates mode="stateid" select="." />).setHistoryType(QHistoryState::<xsl:choose>
+ <xsl:when test="@type='deep'">Deep</xsl:when>
+ <xsl:otherwise>Shallow</xsl:otherwise>
+ </xsl:choose>History);
+ </xsl:if>
+ </xsl:for-each>
+ QAbstractTransition* transition;<xsl:for-each select="//transition">
+ transition = new <xsl:choose>
+ <xsl:when test="string(@cond)!=''">Transition_<xsl:value-of
+ select="generate-id()" />(</xsl:when>
+ <xsl:when test="starts-with(@event,'q-event:')">QEventTransition(<xsl:value-of
+ select="substring-after(@event,'q-event:')" />,</xsl:when>
+ <xsl:when test="starts-with(@event,'done.state.')">QSignalTransition(state_<xsl:value-of
+ select="substring-after(@event,'done.state.')" />,SIGNAL(finished()),</xsl:when>
+ <xsl:when test="string(@event)!=''">QSignalTransition(this,SIGNAL(event_<xsl:value-of select="replace(@event,'\.','__')" />()),</xsl:when>
+ <xsl:otherwise>SCC_UnconditionalTransition(</xsl:otherwise></xsl:choose><xsl:apply-templates mode="stateid" select=".." />);<xsl:if test="count(*) != 0">
+ connect(transition,SIGNAL(triggered()),this,SLOT(exec_<xsl:value-of select="generate-id()" />()));</xsl:if>
+ <xsl:if test="string(@animation) != ''">
+ (*transition).addAnimation(<xsl:value-of select="@animation" />);</xsl:if><xsl:if
+ test="string(@target) != ''"></xsl:if>
+ <xsl:choose>
+ <xsl:when test="string(@target)=''" />
+ <xsl:when test="count(tokenize(@target,'\s+'))=1">
+ (*transition).setTargetState(state_<xsl:value-of select="@target" />);</xsl:when>
+ <xsl:otherwise>(*transition).setTargetStates(QList&lt;QAbstractState*&gt;()<xsl:for-each
+ select="tokenize(@target,'\s+')"> &lt;&lt; state_<xsl:value-of select="." /></xsl:for-each>);</xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:for-each select="//onentry|//onexit"><xsl:if test="count(*) != 0">
+ connect(<xsl:apply-templates mode="stateid" select=".." />, SIGNAL(<xsl:choose>
+ <xsl:when test="name()='onentry'">entered</xsl:when>
+ <xsl:when test="name()='onexit'">exited</xsl:when>
+ </xsl:choose>()),this,SLOT(exec_<xsl:value-of select="generate-id()" />()));</xsl:if></xsl:for-each>
+ }
+};
+ <xsl:for-each select="//transition[string(@cond) != '']">
+ bool Transition_<xsl:value-of select="generate-id()" />::eventTest(QEvent* e)
+ {
+ return Q<xsl:if test="string(@event) != ''">Signal</xsl:if>Transition::eventTest(e)
+ &amp;&amp; stateMachine-&gt;testCondition_<xsl:value-of select="generate-id()" />(e?(*e):QEvent(QEvent::None));
+ }
+ </xsl:for-each>
+#endif
+ </xsl:template>
+
+</xsl:stylesheet>