What's so good about visual programming? Very simple: the eye can identify the correctness and meaning of visual patterns much more so than algorithms expressed as lines of text. Also, GOOFEE diagrams are very simple and concise and show all relationships for unambiguous code generation. The cherry on the cake is that GOOFEE visual programming is a total analysis, design, documentation, and implementation tool, in a single diagram. There is nothing else out there that comes even close to these goals.
GOOFEE Diagrammer generates C code. It is possible to design almost 100% of a program visually, and automatically generate all of the C code. To get a feel for the possibilities, the TUTORIAL\ directory on the companion disk has a simple example:
A first look
You will need these files:
goofee.exe
v1.4 (about 200K, requires
Windows 3.1/95/NT) demo1.c
demo1.goo
demo1.h
goofee.exe
is the diagramming tool and code
generator. demo1.c
is a C source code file. demo1.goo
is the example diagram that you can open inside goofee.exe
.
demo1.h
is the header file for the generated
source files.
There is nothing to install, just put these four files into
the same directory and execute goofee.exe
. Go
to "File/Open" to open demo1.goo
, then you
will see instructions to double-click on a node -- this will open
demo1.c
, which will tell you more.
NOTE: The companion disk has goofee.exe in the root directory. Copy
it into the TUTORIAL\
directory, so all the above files are in the same directory. Note
that it is always best to have a copy of goofee.exe in the current project
directory.
Here is a snapshot of demo1.goo
:
Note that when you open demo1.goo
in the GOOFEE
Diagrammer, the resources (rectangles) will look slightly
different from the above figure. I experimented with
changes in v1.3betas3/4 to more clearly distinguish the
visibility and lifetime options.
This is just a fragment of a complete solution to a baby breathing monitor, further described in the book. There are a lot of features that the GOOFEE Diagrammer is capable of, not shown here. For example, it automatically detects if data is external to current thread, or if data is dynamic (temporary), and composes correct C code. Node 008 is called a clone, and the thick line connecting it is called a relation bar (or joining bar). Clones can be in a tree structure, with one root node, and terminals can be overridden or not. Clones allow code/resource sharing and object orientation -- this is an extremely powerful feature.
For more details, read my book. Note that one deviation from the first edition of my book is that for iterative nodes first entry is at ring 1, the innermost, as is final execution exit. Local iterations, i.e., loops, are exits and returns to any of the other rings >1. On entry to any ring, the condition expressions are evaluated from inner to outer, failing which exit is from the next-inner ring without a condition.
"?" means condition expression, "!" means action statement/s. "!!" means action followed by immediate exit from ring 1 of the node (called "double action").
"SEQUENCER" cycles through, calling node 009, "count breaths", then "update", never exiting. When "update" receives an asynchronous timeout message from the "isr" thread, which happens every minute, "fASYNC" becomes true and "write to display" is called. "b_cnt" is the number of breaths baby has made in a minute.
You should also note that as well as the condition and action wires, nodes can have blocks of C code, for each ring. This allows the diagram to be as "coarse grained" as you want. Double-click inside any ring to bring up the editor for that ring. After you exit from the editor, you will notice that the node has a pale yellow colour -- but GOOFEE will only do that if the node was previously set to "no fill", i.e., you had not previously assigned it a fill colour. The pale-yellow colour-fill is your visual cue that this node has a code block inside.
1.3beta3 added support for pointers, i.e., simple indirection.
The following Figure is demo2.goo
, that you
will find in the goofee.zip
file. Here is a snapshot
of demo2.goo
:
It's very simple: you turn a resource into a pointer by attaching a tunnel subnode to it. The private resource named "resprivate" can be accessed by the name "resprivate" or by "Tresprivate". The latter accesses what "resprivate" points to, and is a simple way to avoid using the "*" -- pointer manipulation is the curse of C, and my simple technique makes life much easier. By the way, a private resource is visible only inside the node it is attached to -- right-click the mouse on the resource to bring up a dialog box, to view visibility and lifetime settings.
The example also shows how the "A" thread detects and composes external resources. Node 004 is a clone, and thread "A" really calls node 005. If you are adventurous, experiment with overriding "resshareable" on clone node 004 with another shareable resource. Be even more adventurous and create another clone hanging off node 004 -- for an arbitrary place to call it from, throw another ring around node 001, and draw a 2-way wire from the new ring to the new clone -- examine what gets generated for thread "A".
No header or other files are required, just demo2.goo
.
Generate the code for each thread, and try it in your
compiler. In this case, all header information is in
"Control/Preliminary code..." (though in a practical
project you would take it out into a header file, and #include
it).
You might like to also take note of the color scheme for text. All red text ends up in the final generated code, while blue text ends up as comments in the generated code file.
1.3beta4, released early March 98, supported arrays. The
following figure illustrates, and the file is demo3.goo
:
Generate the code for each thread -- you should find the generated C source to be quite clear.
Ready-made library functions, or those you have pre-written yourself, can be called in 1.3beta4 by embedding a block of source code inside a node. However, it is very easy to add visual modeling of this also -- and I decided that it's useful enough to be brought out in this beta release. This is a node that you can pass multiple parameters to, as required by the function, and for which you supply the prototype.
The example file is func1.goo
and the figure is:
The code generator composes passed parameters, return parameter and function name as-is. Obviously you should make sure the parameters are in-scope, and I have declared them as temporary resources. Note that with dataflow wires to normal nodes, the code generator declares passed parameters as temporary-private (automatic) data if not already defined by a resource ("z" and "p" are examples of this), but current version isn't doing this for the wire to a library function node.
The library function node will mean that suddenly GOOFEE graduates from its humble beginnings as a tool for embedded microcontrollers, and is suitable for designing -- for example -- a Windows application that uses the standard Windows API. No, I haven't got as far as thinking about the MFCs (class libraries) yet! -- the modeling details are worked out though, but implementation is awhile off. That is, you could probably call methods (functions) in class libraries, but I have in mind some visual aids -- maybe the next version.
Is somebody out there interested in experimenting with GOOFEE designs of Windows applications? You are welcome to get involved, and I would like to put your stuff on the web. One thing I suggest, as Windows callbacks involve big Case structures, that you make use of the "!!" (double action), as illustrated:
Normally, when execution reenters a ring, all conditions are evaluated. To force an immediate exit from ring 1 of node 1, use the "!!" -- this is of course the same as using "break" in C.
Note though, that exit is to node 4 if all conditions fail, at first entry to the node (ring 1), as well as on return to a ring. It may be that you want to separate these two, for example, call the Windows default message handler function if all conditions fail, then return to node 1, then exit from ring 1 -- easy, add another ring without a condition -- if the conditions fail, exit will be from the outermost ring without an attached condition, i.e., ring 4 rather than ring 1.
This multiple-ring condition/action mechanism is quite simple once you get the hang of it, and it covers all that you could conceive of with if-else, do-while, for-next, etc.
You do need one more thing to design Windows applications -- support for structures. Although you can resort to blocks of C code to do anything special, structures are a natural for visual modeling in GOOFEE diagrams. Windows applications make heavy use of structures, and of course they are useful in just about any C program. The following Figure illustrates:
The small grey circle is a structure subnode. Basically, grey-fill is a visual cue to prewritten/predefined code, as for example in the library function node. Right-clicking on it brings up a dialog box, and an initialisation string may optionally be entered straight in. Or, again optionally, the entire structure may be constructed visually -- this is helpful as a visual cue to what the structure consists of, and for initialisation of complicated structures. The member subnode has a dot in the middle, and a dialog box that allows specification of the element and initialisation. Also, each element can be a pointer, an array, another structure, etc., simply by attaching the appropriate subnodes. Visual modeling of structures was first supported in v1.4 beta1.
Another feature added with v1.4 beta1 was in-line expansion. With earlier versions, every node is a C function. This has two problems. Firstly, if the node performs a very trivial operation, the overhead of function call and return, with parameter passing, lowers execution speed and makes the code bigger. Also, there is the question of the visibility of private resources (variables) -- they are only visible in the node they are attached to. You may wish to jump out of a ring, execute a node, come back into the ring, while having the private variables visible all the time. This is just like a local iteration, or loop, inside a larger function. GOOFEE Diagrammer v1.4 beta1 recognises any node called from a ring >1 of a parent node, and if the called node has no parameters passed to it and has no resources attached to it other than temporary-private, the called node is expanded in-line inside the parent node.
This is an optimisation feature for real-world projects. You
can see this in action in func1.goo
, above.
Nodes 002 and 003 both expand in-line inside node 001.
Note though, that in-line expansion is by default turned
off. Go to "Control/Code generation configuration/Generated
source file" to selectively turn it on.
On the subject of real-world projects, the current version of GOOFEE Diagrammer has a limitation in size of the diagram of 150 nodes, 50 resources, and 300 wires. This may be okay for a very wide range of microcontroller projects, but as we scale up, especially with more than one programmer involved in a project, there is the need to have streamlined integration of multiple diagrams.
Version 1.3 and earlier do allow insertion of blocks of C code in a node, but version 1.4 beta1 allows any node to link to another diagram. Actually, this was supported in earlier versions, but now it is highly automated. You will see in the dialog box for a node, that various responses to a double-click may be chosen. One option is to open another diagram, and there is a field for entry of the filename of the diagram. Where the automation comes in, is if you want to expand a node as another diagram, by double-clicking on it a new diagram is created with everything automatically created. Here is a Figure to illustrate:
Construct this for yourself, and see the surprise. When a node has open-another-diagram double-click action, selected via its dialog box, its color changes to aqua-blue. Also, it must be given a function name, in this example "secondfunc", and the filename of the linked-to diagram is entered into the dialog box. The idea is that another node on another diagram will have the same function name, and that other node will have rings with a diagram expanding out of them. In the diagram above, the code generator will compose a prototype for "secondfunc" but no function. When you double-click (holding down the control-key) on "secondfunc" above, the other diagram will be created or will open, and if required a matching node will be created, as well as the dataflow wire and attached resources. Thus, when code is generated in the other diagram, it will automatically generate the same prototype and the resources will be visible in that diagram and declared as external.
Try it. Construct the above diagram, setup the dialog box for
"secondfunc" node -- select any name for another
diagram, such as DIAG2.GOO
. Holding down the
control-key, double-click on the node. Examine the new
diagram -- you may generate code in the newly-created node, to
see that the skeleton code is all correct. To go back to
the previous diagram, is very simple -- holding down the
control-key, double-click on the new node, and back you go.
Any linker program can put the two files together very easily.
Well, it depends what you mean. You've probably seen C code that you have to look at a hundred times to make sense of it. You could write an operating system in C (Unix for example!). Could GOOFEE diagrams handle a project as challenging as this? Well, I've designed a new version of my CREEM real-time operating system, in C for portability, rather than assembly language (see companion disk GOO-CREE\ directory), and one thing I need is an array of pointers to functions. Can GOOFEE do this? Look:
This example is beautiful, and illustrates how you can avoid the horrible nasties of C coding. The diagram defines an array of pointers to functions, "tsk1," etc., being the functions. The i/o wire binds the variable as private to node 001, while the dataflow/controlflow wire calls the function, passing "x" as the array element. The wire can also pass parameters and have a return parameter. In this example they are "void". The subnode that looks like a small node, is exactly that, and it is called a prototype subnode.
To do the above, you need v1.4 beta2 or above. Note that beta2 has a limitation on the length of the initialisation string for arrays, that should get improved in beta3.
GOOFEE Diagrammer has customisation features for particular C compilers. One of my interests (at the moment) is the 8051 microcontroller, and I have given attention to generating code that is compatible with Keil, Franklin, and SDC51 C compilers. The latter is a freeware compiler (go to the main page at http://www.goofee.com/ for a link to my 8051 links page).
The place where you go to customise for a particular compiler is at the menu "Control/Code generation configuration.../Language & editor...". Also look at "Control/Code generation configuration.../Preliminary code...".
It is important to note that when you first start GOOFEE
Diagrammer, the settings are all at default. When you make
changes, they are saved with the diagram, which is a .GOO file.
Therefore, if you have configured the settings to suit your
compiler, you can make a template by erasing any diagram, from
"File/Erase entire diagram", then "File/Save
as...". Give it an appropriate name, such as
KEILC.GOO.
Whenever you want to create a new diagram using those settings,
just "File/Open..." to open KEILC.GOO and then
"File/Save as..." with a name appropriate to the new
project. A point to note also is that when you double-click on a
node to open a new diagram, the current settings will propogate
to it.
Don't throw out that old PC! I recall back in 1986, running PageMaker desktop publishing software on a Macintosh with only 2M of RAM and 2 floppy drives. Slow, but it worked. Why do modern applications need 100M of drive space, 32M RAM and a fast Pentium? Because they are written on layers of software and are hopelessly inefficient.
GOOFEE Diagrammer is handcrafted in assembly language, and is somewhat of an anacronism, being a sophisticated drawing tool and code generator with extensive error checking, occupying only 200K. I wrote it to run on anything, even an old PC with Windows 3.1, 386SX CPU (I even do all the maths in software, so no maths coprocessor required) and one floppy drive. No, you don't even need a hard drive, though the other tools you use, C compiler etc., will probably want one. I do use the 32-bit registers of the 386, so you can't go back to the old 286 processor -- had to draw the line somewhere!
These examples are only a small sampler of the power of GOOFEE diagrams. I have hardly touched on the ability to design a system progressively, in the one diagram, that is, using GOOFEE diagrams throughout the entire development process. The clone mechanism also is extremely powerful and you can have object oriented designs, yet output in plain C. To understand much of the background reasoning behind GOOFEE diagrams, study the book. Definitely check my Web sites to find out what is going on.