diff options
author | Stefan Radomski <sradomski@mintwerk.de> | 2016-02-14 14:14:28 (GMT) |
---|---|---|
committer | Stefan Radomski <sradomski@mintwerk.de> | 2016-02-14 14:14:28 (GMT) |
commit | 8e62f3801b98bf4b7f7f85b848b2fe6339c99162 (patch) | |
tree | a6c593bc3e59a864ddb69b6160e3db610fe995d6 /docs | |
parent | 7b428e5435f83a7e7db37094a9197afa2dd09bf5 (diff) | |
download | uscxml-8e62f3801b98bf4b7f7f85b848b2fe6339c99162.zip uscxml-8e62f3801b98bf4b7f7f85b848b2fe6339c99162.tar.gz uscxml-8e62f3801b98bf4b7f7f85b848b2fe6339c99162.tar.bz2 |
More work on ANSI C transformation
Diffstat (limited to 'docs')
-rw-r--r-- | docs/NATIVE_CODE.md | 138 |
1 files changed, 100 insertions, 38 deletions
diff --git a/docs/NATIVE_CODE.md b/docs/NATIVE_CODE.md index 91af599..c6f2416 100644 --- a/docs/NATIVE_CODE.md +++ b/docs/NATIVE_CODE.md @@ -9,9 +9,8 @@ native description of the state-chart. To embed the control flow described within an SCXML document in most variances of the C language, we provide a transformation onto ANSI C (C89) as a proper -subset of virtually any more modern C/C++ dialect. There are two general -approaches to achieve this. In any case, you need to transform your SCXML -state-chart onto ANSI C by invoking <tt>uscxml-transform</tt>: +subset of virtually any more modern C/C++ dialect. First, you need to transform +your SCXML state-chart onto ANSI C by invoking <tt>uscxml-transform</tt>: $ uscxml-transform -tc -i INPUT_FILE -o OUTPUT_FILE @@ -47,9 +46,21 @@ allow you to influence important characteristics of you state-machine. state and <tt>transitions[USCXML_MAX_NR_TRANS_BYTES]</tt> for one bit per transition. + * <tt>**USCXML_ELEM_X_IS_SET**</tt>: + + These macros are defined for <tt>DATA</tt>, <tt>PARAM</tt> and + <tt>DONEDATA</tt> and allow to iterate instances. For all of the + corresponding SCXML elements, a callback might be supplied with a set + of instances (e.g. <tt>invoke</tt> takes a set of <tt><param></tt> + elements). They are contained in a continuous memory region and can be + iterated by merely increasing the respective pointer. The macros allow + to check whether the pointer is still valid or whether there are no + more instances of the given structure. + * There are some other macros defined, but they are rather for micro-optimizations. Have a look at a generated file. + 2. All compound data **types** (<tt>struct</tt>) to encode an SCXML state-machine. These will refer to the macros above to require memory for a state-chart's states and transitions, so make sure that the macros are set if you @@ -64,7 +75,8 @@ document twice, you might end up with duplicate symbols, yet again, the state-chart's will be functionally identical as they contained the same content. In order for not having to guess the prefix when referring to any machine - in application code, the tranformation will define three additional macros: + in user-supplied application code, the tranformation will define three + additional macros: #ifndef USCXML_MACHINE # define USCXML_MACHINE _uscxml_BC220711_machine @@ -89,42 +101,41 @@ inclusion by pre-defining respective macros (have a look at a generated source file). Now in order to actually use an SCXML document to manage the control flow among -a set of functions, there are two general approaches. Both use the generated -ANSI C source code above, but require more or less resources at runtime as -detailled below. +a set of functions, you will need to allocate and clear memory for a +<tt>uscxml_ctx</tt> structure, set its machine field to a +<tt>uscxml_machine</tt> structure and register user-supplied callbacks. + +### Context Callbacks -### Fully Compliant +An SCXML interpreter does more than to perform a series of microsteps for an +event over a set of states and transitions and there are quite a few +responsibilities not implemented in the generated ANSI C code. These will be +delegated to user-supplied code via callbacks if they are required for the interpretation of a given SCXML file. -An SCXML interpreter does more than to perform a series of microsteps for event -over a set of states and transitions and there are quite a few responsibilities -not implemented in the generated ANSI C code: +There is already a scaffolding providing most of the callbacks implemented in +the [test-c-machine.c](../test/src/test-c-machine.c) test file and you can just +isolate the <tt>StateMachine</tt> class contained within. It does everything +but custom invocations but requires linking with <tt>libuscxml</tt> for the +datamodel implementations and several other functions. Depending on the number +of SCXML language features you employ, you can get away with providing +considerably fewer callbacks as detailled below. 1. **Event Queues**: A compliant interpreter is required to maintain two event queues, an - internal and an external one. With the generated ANSI C source, these are - integrated via four callbacks and will need to be implemented in - user-supplied code: + internal and an external one. These queues can grow to arbitrary size and + we made a decision, not to employ <tt>malloc</tt> for heap allocations in + the generated ANSI-C source. As such, it is the responsibility of the + user-supplied code to manage the queues via the following callbacks: - 1. <tt>**uscxml_ctx.dequeue_internal**</tt>: This callback is invoked - whenever the interpreter needs an event from the internal event queue. It - is passed an instance of a <tt>uscxml_ctx</tt> structure and is supposed to - return an opaque pointer to an event. If the internal queue is empty, - <tt>NULL</tt> is to be returned. + | Callback | Comments | Required For | + |-|-|-| + | <tt>**dequeue_internal**</tt> | This callback is invoked whenever the interpreter needs an event from the internal event queue. It is passed an instance of a <tt>uscxml_ctx</tt> structure and is supposed to return an opaque pointer to an event. If the internal queue is empty, <tt>NULL</tt> is to be returned. | Dequeuing *internal* events | + | <tt>**dequeue_external**</tt> | This callback is functionally equivalent to <tt>uscxml_ctx.dequeue_internal</tt> but invoked, when an external event is to be dequeued. | Dequeuing *external* events | + | <tt>**exec_content_send**</tt> | Whenever there is an <tt><send></tt> element encountered in executable content, the generated ANSI C code will invoke this callback with a context and an <tt>uscxml_elem_send</tt> instance and the user code registered at the callback is expected to handle the send request as per SCXML recommendation. | Delivering events via <tt><send></tt> | + | <tt>**exec_content_raise**</tt> | This callback is invoked for any <tt><raise></tt> element processed as part of executable content and is expected to deliver an event to the internal event queue. | Delivering events via <tt><raise></tt> | - 2. <tt>**uscxml_ctx.dequeue_external**</tt>: This callback is functionally - equivalent to <tt>uscxml_ctx.dequeue_internal</tt> but invoked, when an - external event is to be dequeued. - - 3. <tt>**uscxml_ctx.exec_content_send**</tt>: Whenever there is an - <tt><send></tt> element encountered in executable content, the generated - ANSI C code will invoke this callback with a context and an - <tt>uscxml_elem_send</tt> instance and the user code registered at the - callback is expected to handle the send request as per recommendation. - - 4. <tt>**uscxml_ctx.exec_content_raise**</tt>: This callback is invoked for - any <tt><raise></tt> element processed as part of executable content and - is expected to deliver an event to the internal event queue. + The events themselves are represented as opaque pointers and the generated ANSI-C code will never access any of its members. 2. **Transition Matching / Enabling** @@ -132,11 +143,62 @@ not implemented in the generated ANSI C code: source will already make sure that only valid sets of transitions can be selected to constitute the optimal transition set for a microstep, but user-supplied code will have to decide whether a transition is matched and - enabled. This is done via the <tt>**uscxml_ctx.is_enabled**</tt> callback. - It receives a context, a <tt>uscxml_transition</tt> structure and the - opaque event pointer and will have to return <tt>0</tt> for when the - transition is not matched and enabled by the given event and <tt>1</tt> if - it is. + enabled. + + | Callback | Comments | Required For | + |-|-|-| + | <tt>**is_matched**</tt> | This callback receives a context, an <tt>uscxml_transition</tt> structure and the opaque event pointer. It is expected to return <tt>0</tt> for when the transition is not matched by the given event and <tt>1</tt> if it is. You can assume that non-spontaneous transitions are not checked for the null-event and vice versa. | Event name *matching* of a transition. | + | <tt>**is_enabled**</tt> | This callback receives a context and a <tt>uscxml_transition</tt> structure. It is expected to return <tt>0</tt> for when the transition is not enabled and <tt>1</tt> if it is. Only transitions with an actual <tt>condition</tt> attribute will be checked. | Determining *enabled* status of a transition. | + +3. **Invocations** + + The transformation will generate machine structures for all SCXML + state-charts found within a document, but will make no attempt to invoke + them automatically. Instead, the generated ANSI-C code will call upon the respective callback in the <tt>uscxml_ctx</tt> structure: + + | Callback | Comments | Required For | + |-|-|-| + | <tt>**invoke**</tt> | The call back is provided with a context and an <tt>uscxml_elem_invoke</tt> structure. This structure will contain all the information pertaining to the <tt><invoke></tt> element, with an additional optional member <tt>machine</tt>, which points to the <tt>uscxml_machine</tt> structure in case another, nested SCXML machine is to be invoked. It is your responsibility to create a <tt>uscxml_ctx</tt> for this new machine and run it or start any other type of invocation specified in the given structure. | Invoking external components via <tt><invoke></tt> | + +4. **Executable Content** + + In general, every instance of an element for executable content has a respective callback in the <tt>uscxml_ctx</tt> structure. There are a few examples, wherein an element is transformed onto control flow that will invoke multiple callbacks: + + | Callback | Comments | Required For | + |-|-|-| + | <tt>**exec_content_log**</tt> | | <tt><log></tt> | + | <tt>**exec_content_raise**</tt> | | <tt><raise></tt> | + | <tt>**exec_content_send**</tt> | | <tt><send></tt> | + | <tt>**is_true**</tt> | | <tt><if> / <elseif> / <else></tt> | + | <tt>**exec_content_foreach_init**</tt> <tt>**exec_content_foreach_next**</tt> <tt>**exec_content_foreach_done**</tt> | | <tt><foreach></tt> | + | <tt>**exec_content_assign**</tt> | | <tt><assign></tt> | + | <tt>**exec_content_init**</tt> | | <tt><data></tt> | + | <tt>**exec_content_cancel**</tt> | | <tt><cancel></tt> | + | <tt>**exec_content_script**</tt> | | <tt><script></tt> | + +5. **Done Events** + + Finally, there is a callback that is invoked if a <tt><final></tt> state is entered. + + | Callback | Comments | Required For | + |-|-|-| + | <tt>**raise_done_event**</tt> | The callback is provided with a context, the state for which a done event is to be raised and a <tt>uscxml_elem_donedata</tt> structure. | <tt><final></tt> | + + +### Inline SCXML + +An alternative to writing an external SCXML file is to embed the document into the actual C code as a comment: + + /** INLINE SCXML BEGIN + <scxml name="test-inline" datamodel="native"> + <state id="foo"> + <onentry> + enteredFoo(); + </onentry> + </state> + </scxml> + INLINE SCXML END */ +If you pass an arbitrary input file to <tt>uscxml_transform</tt>, it will realize that it does not constitute a proper SCXML document and attempt to isolate an actual SCXML state-chart by searching for the string literals <tt>INLINE SCXML BEGIN</tt> and <tt>INLINE SCXML END</tt>. Everything in between is isolated and treated as if it was a proper SCXML document. -### Light-Weight +Here, you can also see a variation with the <tt>datamode="native"</tt> attribute. If this is given, the transformation will write any text child of executable content as an unescaped, verbatim string literal into the respective function, allowing you to address any of your C functions and variables directly.
\ No newline at end of file |