code_generation_intro.textile 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. ==<div style="counter-reset: h1 6">==
  2. h1(#codegen_generating_state_machine_code). Generating state machine code
  3. Ultimately, you will need your state machine not only as a nice graphical statechart model, but rather in the form of executable code that you can integrate with your software project as a component. You will want to send events to the state machine, receive events from it, retrieve information regarding the currently active state (or states), set and get state machine variables, and have the state machine invoke specific behaviour that is external to it.
  4. YAKINDU Statechart Tools comes with a couple of code generators that save you from the time-consuming and error-prone task of coding your state machine manually. The YAKINDU code generators transform your statechart into source code of a target programming language in an instant. The generated code is always correct, at least in the sense that it is a true one-to-one mapping of your statechart – and at least unless a code generator is buggy itself.
  5. Use "SCTUnit":../user-guide/sctunit.html#sctunit_test-driven_statechart_development_with_sctunit in order to test whether your state machine is also correct in the sense that it does what it is intended to do.
  6. Currently YAKINDU Statechart Tools support code generation for the following programming languages:
  7. * "C":../user-guide/code_generation_generators.html#codegen_c_code_generator
  8. * "C++":../user-guide/code_generation_generators.html#codegen_cpp_code_generator
  9. * "Java":../user-guide/code_generation_generators.html#codegen_java_code_generator
  10. YSCT also includes a "statechart image generator":../user-guide/code_generation_generators.html#codegen_statechart_images_generator.
  11. ###. CHECK: YSCT supports code generation for C, C++, Java, and statechart images.
  12. Additionally, you can install a couple of code generators from the "YAKINDU Labs update site":https://updates.yakindu.com/statecharts/labs/. To do so, select _Help → Install new software …_ in the main menu, and use "https://updates.yakindu.com/statecharts/labs/":https://updates.yakindu.com/statecharts/labs/ as the site location. The following code generators are available; click on the link to find more information about the respective generator:
  13. * "Python":https://blogs.itemis.com/en/python-code-generation-with-yakindu-statechart-tools
  14. * "Swift":https://www.itemis.com/en/yakindu/state-machine/documentation/examples/example/SwiftExample
  15. * "TypeScript":https://blogs.itemis.com/en/typescript-code-generation-with-yakindu-statechart-tools
  16. ###. CHECK: YAKINDU Labs generators: Python, Swift, TypeScript
  17. bq. *Please note:* Code generators in YAKINDU Labs are still in their beta phase and might well contain some rough edges. If you encounter any problems, please let us know!
  18. If these code generators don't suit your needs, you are free to develop your very own "custom code generator":../user-guide/code_generation_generators.html#codegen_custom_code_generators.
  19. h2(#codegen_general_concepts_of_the_state_machine_code). General concepts of the state machine code
  20. h3(#codegen_execution_schemes). Execution schemes
  21. The generated state machine code implements one of two execution schemes:
  22. * In the _cycle-based execution scheme_, the state machine will first collect events and later process them in a run-to-completion step. Run-to-completion steps are typically executed in regular time intervals.
  23. * In the _event-driven execution scheme_, the state machine becomes active each time an event arrives and processes it right away in a run-to-completion step.
  24. You can select the execution scheme via the <code>@CycleBased</code> or <code>@EventDriven</code> annotations. Write the appropriate annotation to the top of your statechart's definition section, see sections "&quot;@CycleBased&quot;":../user-guide/statechart_language.html#sclang_cyclebased and "&quot;@EventDriven&quot;":../user-guide/statechart_language.html#sclang_eventdriven.
  25. h4(#codegen_cycle-based_execution_scheme). Cycle-based execution scheme
  26. In the cycle-based execution scheme, each run cycle consists of two different phases:
  27. # In the first phase, incoming events and time events are collected.
  28. # In the second phase, _runCycle()_ is executed and processes the events collected in the first phase.
  29. This approach allows for explicitly processing several events at the same time as well as for checking combinations of events, e.g., a guard condition like @[eventA && eventB]@. This is very useful for systems that are close to hardware and input signals. Basically it is the "input-process-output (IPO) model":https://en.wikipedia.org/wiki/IPO_model.
  30. ==<div class="example">==
  31. Example: The sample client code below first raises events _eventA_ and _eventB_ in the state machine. These events are lingering in the state machine until the client code calls _runCycle()_ to actually process the events.
  32. bc. sc_raiseEventA(handle);
  33. sc_raiseEventB(handle);
  34. sc_runCycle(handle);
  35. ==</div>==
  36. bq. *Please note:* In the cycle-based execution scheme, an event that has been raised internally using the "_raise_ statement":../user-guide/statechart_language.html#sclang_raising_an_event is visible in the run cycle "downstream" only, i.e., in such regions and the states therein that have not yet been processed in the current run cycle. Everything that is "upstream" in the run cycle cannot "see" this event. *This is semantically different from the event-driven execution scheme.* Read more on this topic in section "&quot;Raising and processing an event&quot;":../user-guide/statechart_language.html#sclang_raising_and_processing_an_event.
  37. h4(#codegen_event-driven_execution_scheme). Event-driven execution scheme
  38. In the _event-driven execution scheme_, each incoming event or time event immediately triggers the execution of a run-to-completion step. As a consequence, the state machine will never process two events simultaneously, and a guard condition like @[eventA && eventB]@ will never become true.
  39. ==<div class="example">==
  40. Example: The sample client code below raises the events _eventA_ and _eventB_. The state machine processes each event immediately as it arrives, triggered by the respective _raise…()_ method. Thus the client code does not need to call _runCycle()_.
  41. bc. sc_raiseEventA(handle);
  42. sc_raiseEventB(handle);
  43. ==</div>==
  44. bq. *Please note:* In the event-driven execution scheme, an event that is raised internally in a run-to-completion step using the "_raise_ statement":../user-guide/statechart_language.html#sclang_raising_an_event will not be acted upon by any active state "downstream" in the event cycle. The reason is that only a single event can be processed at a time, and this is the event that caused the current run cycle to execute in the first place. The internally-raised event will trigger its own run-to-completion step subsequently. Thus it will be visible to all active states in that RTC. *This is semantically different from the cycle-based execution scheme.* Read more on this topic in section "&quot;Raising and processing an event&quot;":../user-guide/statechart_language.html#sclang_raising_and_processing_an_event.
  45. h3(#codegen_responsibilities-of-generated-code). Responsibilities of generated code
  46. The generated source code supports a basic statechart execution model that can be used to implement different variants. It is important to understand the responsibilities of the generated code, i.e., what it cares about and what it doesn't. The remaining issues are out of scope and must be dealt with in the client code the developer has to provide.
  47. The generated code basically takes care about the following:
  48. * It provides the interfaces to access state machine variables and events.
  49. * It initializes the state machine.
  50. * It implements the execution semantics within a run-to-completion (RTC) step. This is everything that is happening within the _runCycle()_ function.
  51. There are some predefined constraints:
  52. * The implementation is not thread-safe. Therefore the _runCycle()_ method must never be called in parallel by different threads.
  53. * All events for a run-to-completion step will be consumed.
  54. Out of scope are:
  55. * *Scheduling:* The code generator cannot make any general assumptions about scheduling mechanisms and constraints.
  56. * *Timers:* The code generator does not know how the system handles times. If any specific time-dependend behavior is required, the client code has to contribute it.
  57. * *Event handling:* The code generator cannot know and does not prescribe how events are entering the system. Therefore deciding when events will be delivered to the state machine is an outside (client code) responsibility.
  58. * *Concurrency:* The client code has to care about any thread synchronization.
  59. * *Memory management:* The generated state machine code will never allocate any memory. Allocating the memory needed for the statechart structure is a responsibility of the client code.
  60. All these things are out of the generated code's scope, since the code generators coming with YAKINDU Statechart Tools cannot provide tailored solutions without knowing any details about a respective specific environment, like runtime system, libraries, etc.
  61. In order to have a better code generator support for specific usage patterns, you would have to implement corresponding code generator extensions.
  62. h3(#codegen_thread-safe_execution). Thread-safe execution
  63. In order to circumvent the missing thread-safety of the _runCycle()_ method, the Java code generator has an option for generating a so-called runnable wrapper, providing event queueing and multi-threading support. For details, see section "&quot;RunnableWrapper&quot;":../user-guide/code_generation_generators.html#codegen_java_runnablewrapper_feature. It is easy to implement this as a general solution for Java, since the programming language provides corresponding standard features that by definition are available everywhere by can simply be used.
  64. The C programming language, however, does not have any standardized threading features. Therefore a general solution cannot be given. Specific solutions for specific threading libraries would require the implementation of a suitable code generator extension.
  65. h2(#setting_up_a_code_generator_project). Setting up a code generator project
  66. In order to deploy a code generator and actually generate code, you have to set up a _code generator project_. This is described in the following subsections.
  67. For configuring the code generation process, YAKINDU Statechart Tools uses a textual generator model called _SGen_. It can be created either by using the _YAKINDU Statechart generator model_ wizard or by creating a text file with the filename extension _.sgen_.
  68. To create a generator model using the wizard, proceed as follows:
  69. # In the _project explorer_ view, right-click on your project. The context meu opens.
  70. # In the context menu, select _New → Code generator model_.
  71. # The _New YAKINDU SGen model_ wizard opens.
  72. # Select an appropriate folder and specify the filename of your SGen model. The filename must have the extension _.sgen_.
  73. # Click on _Next >_.
  74. # From the _Generator_ drop-down menu, choose the code generator you want to use, e.g., _YAKINDU SCT Java code generator_.
  75. # Check the statechart(s) to generate code from.
  76. # Click on _Finish_.
  77. !images/docu_genmodelwizardchooselanguage.jpg(Selecting code generator and statecharts)!
  78. p=. Selecting code generator and statecharts
  79. The result is the specified _.sgen_ file. It has the following format:
  80. bc.
  81. GeneratorModel for [GeneratorId] {
  82. statechart [StatechartReference] {
  83. feature [Feature] {
  84. [ParameterName] = [ParameterValue]
  85. }
  86. }
  87. }
  88. The _[GeneratorId]_ represents the unique ID of the chosen generator. Currently, YAKINDU Statechart Tools supports the following code generators out of the box:
  89. * @yakindu::java@ – Generator ID for the Java code generator
  90. * @yakindu::c@ – Generator ID for the C code generator
  91. * @yakindu::cpp@ – Generator ID for the C++ code generator
  92. * @yakindu::generic@ – Generator ID for custom Java-based code generators
  93. * @sctunit::c@ – Generator ID for SCTUnit/C code generator
  94. A single generator model may contain multiple @statechart … { … }@ blocks and thus specify the code generation for multiple statecharts. For each statechart, the generator process can be configured with _Features_. Each feature has one or more parameters. These parameters can be configured with _ParameterName_ @=@ _ParameterValue_.
  95. h2(#running_a_generator). Running a generator
  96. Provided you have created the generator model, proceed as follows:
  97. # In the project explorer view, right-click on the _.sgen_ file containing the generator model. The context menu opens.
  98. # In the context menu, select _Generate Code Artifacts_.
  99. # The generator is executed.
  100. The source files the generator produces depend on the generator itself. Each generator makes use of its specific target language and the latter's features and best practices. For example, the Java generator generates Java interfaces and classes, and the C and C++ generators generate _.h_ header files and _.c_ source files. The _location_ of the generated sources can be changed in the generator model. The respective options are explained in the following section.
  101. The generator model is executed by a so-called Eclipse builder. Thus, the artifacts are generated automatically whenever the statechart is modified, as long as _Project → Build Automatically_ is checked. If you want or need to execute your generator model manually, select _Generate Statechart Artifacts_ from the _package explorer_'s context menu.
  102. h2(#codegen_configuring_a_generator). Configuring a generator
  103. As mentioned above, all generators can be set up and customized by a generator model. The following screenshot shows a sample configuration for the Java code generator.
  104. !images/docu_sGenEditor.png(SGen generator model with default values)!
  105. p=. SGen generator model with default values
  106. ###. FIXME: Explain what a "builder" is!
  107. The following sections describe _core features_, which are available for _all_ code generators. Individual code generators usually support specific additional features; please see the respective code generator documentation for details.
  108. ==<!-- Start sgen_feature_outlet -->==
  109. h3(#codegen_outlet_feature). Outlet feature
  110. The *Outlet* feature specifies target project and target folder for the generated artifacts. It is a _required_ feature and has the following parameters:
  111. * _targetProject_ (String, required): The project to write the generated artifacts to.
  112. * _targetFolder_ (String, required): The folder within the _target folder_ to write the generated artifacts to. If a _library target folder_ (see below) is specified, only the model-dependent artifacts are generated in the _target folder_. All artifacts in this folder will be overwritten during re-generation.
  113. * _libraryTargetFolder_ (String, optional): The folder to write the model-independent artifacts to. If this parameter is not specified, these artifacts will be generated in the _target folder_ (see above). All artifacts in this folder will be preserved during re-generation. Manual modifications of these artifacts will _not_ be overwritten upon re-generation.
  114. * _apiTargetFolder_ (String, optional): The folder to write API code to, e.g., interfaces or header files. If this parameter is not specified, these artifacts will be generated in the _target folder_ (see above).
  115. * _skipLibraryFiles_ (Boolean, optional): If you wish to exclude the static files from the code generation, i.e., those that are put into the _libraryTargetFolder_, you can set this value to _true_. If the value is _false_ or not specified at all, the files are generated as usual. Currently supported for the Java, C and C++ generators.
  116. ==<div class="example">==
  117. Example:
  118. bc. feature Outlet {
  119. targetProject = "SampleProject"
  120. targetFolder = "src-gen"
  121. libraryTargetFolder = "src"
  122. apiTargetFolder = "api-gen"
  123. }
  124. ==</div>==
  125. ==<!-- End sgen_feature_outlet -->==
  126. ==<!-- Start sgen_feature_licenseheader -->==
  127. h3(#codegen_generating_code_licenseheader_feature). LicenseHeader feature
  128. The *LicenseHeader* feature specifies the license text to be added as a header to the generated artifacts. It is an _optional_ feature and has the following parameter:
  129. * _licenseText_ (String, required): License text to be added as a file header
  130. ==<div class="example">==
  131. Example:
  132. bc. feature LicenseHeader {
  133. licenseText = "Copyright (c) 2017 committers of YAKINDU and others."
  134. }
  135. ==</div>==
  136. ==<!-- End sgen_feature_licenseheader -->==
  137. ==<!-- Start sgen_feature_functioninlining -->==
  138. h3(#codegen_generating_code_functioninlining_feature). FunctionInlining feature
  139. The *FunctionInlining* feature enables the inlining of expressions instead of generating separate functions or methods. This might reduce the readability of the generated code, but increases performance, because less operation calls are necessary. This is an _optional_ feature and has the following parameters:
  140. * _inlineReactions_ (Boolean, optional): inlines the expression for reactions
  141. * _inlineEntryActions_ (Boolean, optional): inlines the expression for entry actions
  142. * _inlineExitActions_ (Boolean, optional): inlines the expression for exit actions
  143. * _inlineEnterSequences_ (Boolean, optional): inlines the expression for state-entering sequences
  144. * _inlineExitSequences_ (Boolean, optional): inlines the expression for state-exiting sequences
  145. * _inlineChoices_ (Boolean, optional): inlines the expression for choices
  146. * _inlineEnterRegion_ (Boolean, optional): inlines the expression for region-entering sequences
  147. * _inlineExitRegion_ (Boolean, optional): inlines the expression for region-exiting sequences
  148. * _inlineEntries_ (Boolean, optional): inlines the expression for entries
  149. ALl parameters of the *FunctionInlining* feature are _false_ by default.
  150. ==<div class="example">==
  151. Example:
  152. bc. feature FunctionInlining {
  153. inlineChoices = false
  154. inlineEnterRegion = true
  155. inlineEntries = true
  156. }
  157. ==</div>==
  158. ==<!-- End sgen_feature_functioninlining -->==
  159. ==<!-- Start sgen_feature_debug -->==
  160. h3(#codegen_generating_code_debug_feature). Debug feature
  161. The *Debug* feature dumps the execution model to the target folder as an XMI model. It is an _optional_ feature and has the following parameter:
  162. * _dumpSexec_ (Boolean, required): dumps the execution model as XMI model (default: _false_)
  163. ==<div class="example">==
  164. Example:
  165. bc. feature Debug {
  166. dumpSexec = true
  167. }
  168. ==</div>==
  169. ==<!-- End sgen_feature_debug -->==
  170. h3(#codegen_using_properties_and_expressions_in_generator_models). Using properties and expressions in generator models
  171. An SGen generator model may assign values to properties and later use these properties in expressions. The following sample generator model uses the *var* keyword to declare the properties _projectName_, _version_, _isBeta_, and _generateTimerService_ with their respective types and default values. The model then uses these values in *feature* clauses by referring to the properties:
  172. bc..
  173. GeneratorModel for yakindu::java {
  174. var projectName : string = "light_switch"
  175. var version : string = "1.0"
  176. var isBeta : boolean = true
  177. var generateTimerService : boolean = true
  178. statechart myStateAutomaton {
  179. feature Outlet {
  180. targetProject = projectName
  181. targetFolder = "src-gen/" + version + (isBeta ? "beta" : "")
  182. libraryTargetFolder = "src"
  183. }
  184. feature GeneralFeatures {
  185. TimerService = generateTimerServce
  186. }
  187. }
  188. }
  189. p. The syntax rules for expressions in generator models are the same as for statechart language expressions, see section "&quot;Expressions&quot;":../user-guide/statechart_language.html#sclang_expressions. However, expressions are constrained to a subset that semantically makes sense in the context of a generator model. That means that, for example, while you can use the @+@ operator to concatenate strings, you cannot use statechart-related constructs like the _after_ keyword or the _active()_ built-in function.
  190. In the properties definition section near the top of a generator model, a value assigned to a property must be given as a _literal_. More complex expressions are not supported there.
  191. h4(#codegen_built-in_variables). Built-in variables
  192. There are several built-in read-only variables which can be used in expressions in generator models:
  193. * _SCTVERSION_ (String): the current version of YAKINDU Statechart Tools, for example, "3.4.0"
  194. * _TIMESTAMP_ (String): the current date and time as a localized string, for example "11.12.2017 17:08:14"
  195. * _USER_ (String): the name of the current user who started this instance of YAKINDU Statechart Tools (via @System.getProperty("user.name")@)
  196. * _HOSTNAME_ (String): the host name of the machine on which YAKINDU Statechart Tools is running.
  197. * _SHA256_ (String): The hash of the referenced file (for example, the statechart file).
  198. * _SCTFILE_ (String): Path to the statechart file relative to the workspace.
  199. bq. *Please note:* Neither _USER_ nor _HOSTNAME_ should be used for any security-related tasks. Especially the username can be spoofed easily, if anyone wanted to.
  200. h4(#codegen_overriding_variables_in_a_headless_build). Overriding variables in a headless build
  201. The values assigned to properties are _default_ values only. That means, you can override them by different values when actually executing a generation model by way of running the "headless code generator":../user-guide/generating_code_headless.html#hdls_headless_code_generation.
  202. For example, the command to call the headless generator might look like this:
  203. bc. scc -m myGenmodel.sct -v version=2.0;isBeta=false
  204. The name/value pairs specified by the @-v@ option would override the corresponding default values of the properties in the generator model. In this case, the properties _version_ and _isBeta_ would be set to the values "2.0" and "false", respectively. The variables _projectName_ and _generateTimerServce_ would maintain their default values as specified in the SGen file.
  205. ==</div>==