Guest post by Vincent Aranega on his UML to ArnoldC code generator. Enter Vincent.

ArnoldC is an attempt to build a new programming language using quotes from the well known one-liner actor Arnold Schwarzenegger. The gap between the programming world and the Schwarzenegger world could seems huge, but finally someone filled it.

The only last remaining gap was the UML to Schwarzenegger one. To join the UML world and the Schwarzenegger world, the uml2arnoldc code generator was born. This code generator provides facilities to easily create ArnoldC
program from UML activity diagram. The main generator is written in a single Acceleo file. There is also some dedicated files that prepare the code generator to be used as a GenMyModel custom generator.

In this article, I’ll try to briefly explain the choices we made to build this generator, from the UML diagram choice to the implementation choices.

Quick Look at the Generator Anatomy

First, let me give you a quick tour and present you the ArnoldC features/limitations:

  • there is a main method,
  • all code (main and functions) must be in a single file,
  • ArnoldC is a fully imperative language,
  • variables can only be 16bits signed integer,
  • functions can be defined in any order,
  • functions can have zero or many parameters,
  • functions can only return a single value,
  • function and variable name cannot contain other char than ‘a-zA-Z0-9’,
  • data structure does not exist,
  • there is no way to insert comments in code,
  • there is if/then/else control structure as well as while control structure.
  • true and false are managed as in C (false is 0 and true is everything else),
  • there is no way to define global variables.

So dealing with it… is not going to be easy. To tackle the ArnoldC limitations, we choose a subset of the Activity Diagram. Indeed, in order to catch the language “imperative” nature and as there is no way to define data-structures in ArnoldC, a behavioral diagram seems to be a reasonable solution. The activity diagram allows you to build actions and can define an execution flow using control flow links. In addition to these basic elements, fork/join nodes express actions synchronization and decision/merge nodes introduce control structures.
Finally, the activity diagram elements we choose to handle are initial, final, action, control flow, fork/join and decision/merge nodes. With these nodes, I can express different kind of independent actions, an idea of action precedence, action interactions and a kind of if structure.

In order to catch synchronization, the activity diagram is translated to a kind of petri net. This way, we can express this precedence idea without computing function call graph during generation. In this context, each activity diagram node handled by the generator is translated to an ArnoldC function. Each “control flow” is translated to a function call and “control flow guards” are used to pass parameters from functions to others. As illustration, the following paragraphs shows as example an input simple activity diagram and the code generator logic.

SimpleActivity

For this diagram, each node will be translated to a function. Obviously, a “Action” and “Action2” function will be generated, as well as a “Fork”, a “Join”, an “Init” and a “Final” function. Easily, the generated “Actions”, “Initial” and “Final” function body only display a message on stdout. In the “Fork” function, a call to the “Action” function and a call to the “Action2” function are generated (there is no specific order). In these two functions, a call is generated to the “Join” function.

Here was the easy part. Most of the work is in the “Join” function. This function must be visited twice before it can call the “Final” function. This behavior is implemented using a variable which is used as a global registry of the visited “Join” node. It gathers a counter call for each “Join” node. As the language does not enable us to deal with global variable, this “state” variable is passed to each function and is used as return value. As I wrote, this variable is used as a gobal registry. Once again, as we cannot define data structure in ArnoldC, we had to cheat by splitting an Integer. Each number position acting as an index of a table. Each “Join” function is generated with an UID that corresponds to an index in the “state” global registry. The following code shows the function generated from the “Action2” node.

1.  LISTEN TO ME VERY CAREFULLY Action2FromSimpleSync
2.  I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE state
3.  GIVE THESE PEOPLE AIR
4.      TALK TO THE HAND "Entering Action2FromSimpleSync"
5.      GET YOUR ASS TO MARS state
6.      DO IT NOW JoinNodeFromSimpleSync state
7.      I'LL BE BACK state
8.  HASTA LA VISTA, BABY

Lines 1 to 3 define the function signature. It only takes a “state” variable as parameter (the global registry). Line 4 simply displays a text to stdout while lines 4 and 5 affect to the “state” variable the return value of the “Join” function call. Then, line 7 returns the global registry and, finally, line 8 ends the function declaration.

To end the example, the following snippet exposes the “Join” function.

 1. LISTEN TO ME VERY CAREFULLY JoinNodeFromSimpleSync
 2. I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE state
 3. GIVE THESE PEOPLE AIR
 4.     GET YOUR ASS TO MARS state
 5.     DO IT NOW incState state 1
 6.     HEY CHRISTMAS TREE myState
 7.     YOU SET US UP 0
 8.     GET YOUR ASS TO MARS myState
 9.     DO IT NOW getState state 1
10.     GET TO THE CHOPPER myState
11.     HERE IS MY INVITATION myState
12.     YOU ARE NOT YOU YOU ARE ME 2
13.     ENOUGH TALK
14.     BECAUSE I'M GOING TO SAY PLEASE myState
15.         GET YOUR ASS TO MARS state
16.         DO IT NOW ActivityFinalNodeFromSimpleSync state
17.     YOU HAVE NO RESPECT FOR LOGIC
18.     I'LL BE BACK state
19. HASTA LA VISTA, BABY

As for the previous example, line 1 to 3 define the function signature. The call counter relative to the ID 1 is incremented in the global registry (line 4 and 5), then, the current call counter is fetched (line 6 to 9). This counter is compared to 2 which is the number of call required by the join node (line 11 to 14), if the function had been called twice, the “Final” function is called (line 15 to 16). Finally, the global registry is returned (line 18) and the function ends (line 19).

Advanced Usage Overview

To manage variables manipulation, the generator performs a kind of parsing work on control flow guards. It can thus creates or transmit variables to other functions. Using this feature with a little bit of manual coding, you can easily generates recursive loops…etc. The generated code is also split in many module file. An sh script (also generated) is used to join all the module files and launch the ArnoldC code compilation/execution.

As project example, I used the generator to produce a Brainfuck to C translator (model is here ). Event if the produced code is huge, almost 400 lines (as a comparison, this kind of translator can be done in about 10 lines of AWK), more than 90% of the application was generated and it asked a very low development effort :).

How to run it

There is two ways of using the uml2arnoldc code generator. You can use it online in GenMyModel (register it as a “custom generator”, save it and launch it on an activity diagram) or you can use it in Eclipse (modeling flavour).

Under eclipse, you can import the “.mtl” files in a new project, build a UML activity diagram in your favourite UML modeler and finally launch the scripts. The two main scripts are “arnoldc.mtl” and “build.mtl”.

If you want more details about how the generator is build, its ability, how ArnoldC limitations are handled and how to use it, you can look at the README.md in the github repository. I invite you to boost your productivity with ArnoldC language, any comment is welcome.

Want to build better software faster?

Want to build better software faster?

Read about the latest trends on software modeling and low-code development

You have Successfully Subscribed!

Pin It on Pinterest

Share This