What is Unimal? ( Contents)
(Initial intro is here. For a brief
executive summary click here).
Complete online
manual (large) is available in a new window.
Unimalis an advanced
preprocessor, or macro processor, which is designed
to be independent of the target programming language.
Therefore, Unimal supplements existing programming
languages with common macro facility.
How a preprocessor such as
Unimal can improve project maintainability and data
optimization is described in the white
paper, also available in PDF
format.
Independence
of the target language allows parameter
sharing among the different languages used in a
project, e.g., C++, Assembler and the make utility
language.
To
maximize the benefits of parameter sharing,
Unimal is capable of switching among different
preprocessor output files on the fly.
The Unimal language
is powerful enough to enable very sophisticated
compile-time (static) initialization of constant
objects. So, what otherwise had to be done in runtime
(e.g., during initialization), can now be done in
compile time. For embedded systems, it also means
freeing up precious RAM by keeping pre-calculated data
in ROM.
In addition, Unimal has a
full-blown 32-bit integer math capability with standard math library
floating-point extensions.
And, of course, Unimal has
operators normally expected from a macro processor:
conditional branches, loops, composite names, macros and
include files.
What is in Unimal
for me? ( Contents)
Like other macro
preprocessors, Unimal is a means
of improving maintainability, reusability and quality
of code. What sets Unimal apart is what exactly can be
accomplished by appropriate "code" written in Unimal:
the language power makes the difference. Here are some
examples of compile-time applications:
- automatically
generating a tabulated function, with
parameter-controlled resolution
- fully automatic
generation of constant lookup tables
- compaction of sparse
tables
- exporting configuration
parameters (e.g., array size) to different languages
Unimal does not provide
most of these capabilities as part of the language.
Instead, it is the language that makes
implementation of complex compile-time algorithms
possible.
If you choose to download
Unimal, take a look in the AppNotes directory for
a few application examples.
You can also read the
Application notes online in PDF format (to get the
optional sample files, click here):
Application Note
1.
Managing unstructured data layouts from legacy
code |
Relations between
strings and names in Unimal
|
Application Note
2.
Stretching
Unimal |
Extend Unimal
capabilities using temporary files
|
Application Note
3.
Computing a
remainder modulo a constant |
Develop an algorithm,
then implement it at compile time
|
Application Note
4.
Automating sparse
and lookup tables |
Examples of
developing rather complex algorithms and
implementing them at compile time:
- storage and maintenance optimization for
sparse tables;
- zero-maintenance lookup tables for accessing
constant data
|
Application
Note 5.
Common
string conversions |
Conversions between numbers and
strings
Replacing characters in strings (e.g., converting
to uppercase)
Generating an error message algorithmically
|
Application
Note 6.
Compile-time
sorting of symbolic constants |
Seamless
integration of Unimal with the C language.
Complex
compile-time algorithm implemented jointly by
Unimal and C |
Application
Note 7.
Guarding
the include files |
When to guard and when not to guard
Unimal include files. Using uAutoLine as an
include file guardian |
Application
Note 8.
Implementing
complex string algorithms at compile time |
Representation of pre-defined encoding
of strings in predefined charset
Generating tree-like
structures and recursive macro expansion
Generating a containing
superstring and multi-suffix composite names
Pretty-formatting the
output |
New
Application Notes |
(not
yet in unimal2.zip) |
Stay tuned! |
|
Also, a few examples and
motivations were presented at DesignCon 2001
in Santa Clara, CA, TecForum HP-TF2. For your
convenience, you can download the presentation here.
It's probably worth noting
that some macroassemblers provide number crunching macro
facilities comparable to that of Unimal. A generic
treatment of this issue was (supposed to be) the topic
of Class #347 at Embedded
Systems Conference West 2000 in San Jose, CA. The
paper and the handouts are available for download here.
Note however that the same algorithm implemented in
Unimal will run faster, and probably much faster.
Unimal 2.1 as a command line
utility is available for Win32 and Linux
platforms. Other platforms can be supported if requested.
You can download Unimal 2.1
for Win32 and use it freely for unlimited evaluation. Any
use of Unimal output, whether verbatim or however
modified, in a product requires a license. You can
purchase a license now by clicking the "Purchase" button
on the left. For volume discounts, please, contact
MacroExpressions.
How Unimal works (
Contents)
The Unimal preprocessor
utility takes an input file and produces an output file,
which presumably is a source code file in a target
programming language. The input file is a source file in
the target language, marked up (sometimes, very
generously) with the Unimal language statements. (In
fact, Unimal can produce several output files, maybe, in
different target languages.)
The Unimal language
consists of two related parts: Unimal
operators and Unimal
target language interface. In somewhat
simplistic terms, operators manipulate signed 32-bit
numbers, and the target language interface submits the
numbers to the target language.
Unimal
operators are line-based. They start with
a signature #MP at the beginning of the line,
with optional preceding white spaces. (To demystify the
signature, "MP" stands for "Macro Parameter.") Example:
#MP
Set mything
= 17
assigns the value of 17 to
the macro parameter mything. Unimal operators manipulate
macro parameters for their own sake; they do not produce
any output to the (target language) source code file.
Any line starting with an #MP is considered a
Unimal operator. If Unimal fails to figure out what it
means, it will generate an error.
Any line in the input file
not starting with an #MP is considered a
line in the target language possibly sprinkled with
Unimal target language interface statements. Unimal
replaces any target language
interface statements with appropriately
formatted numbers and copies the transformed line to the
output file. The way the language interface works is
very simple: Unimal finds any occurrence of the sequence
#mp<format><name>
in the source code and
replaces it with the value currently held by <name>. <format>
specifies how exactly the value is "printed" into the
target language source file. Example:
int
x
=#mp%dmything;
will generate the code
int
x
=17;
in the source file,
provided that mything is still 17. Note the C style
format "%d" meaning "render as decimal number."
As an illustrative
example, consider tabulating
a sine wave in the interval [0, ?/2] with the
scale factor 10000 and integer precision. The number N+1
of tabulation points may change from time to time. Here
is a snippet of Unimal-enhanced C definition:
#MP
Set N=30 ; for example, 31
points
int const
sine_wave[] = {
#MP For I=0,
N ;from
0 to N inclusive
#MP X = Usin(10000,
1, I, N)
#MP ;Now,
render computed value
as decimal
#mp%dX,
#MP Endfor
};
This simple example
demonstrates that tabulating a function is as easy as
calculating its value in Unimal. And, most
importantly, all maintenance
reduces to setting a single parameter (N, in
our case).
Is it hard to write Unimal code? ( Contents)
The Unimal language is
very simple. So, simple (yet useful) tasks like in the
example above are simple to code.
But then, one may
want to venture in more complicated algorithms. Unimal
sets no limit on the algorithm's complexity. In some
cases, Unimal reduces complexity because of its built-in
capabilities, but in general, the Unimal code is going
to be accordingly complex. The reward, though, is that
Unimal code written once improves the maintainability
for the lifetime of the project family.
The good news is that
Unimal code implementing a complex algorithm does not
have to be very efficient. Indeed, since
Unimal is a preprocessor, the only thing sacrificed by
inefficient Unimal code is the compilation time.
Probably, reasonable efforts should be taken not to make
inefficient code (like unused parameters), but other
than that ? who cares?
Unimal comes with a number
of Application Notes; they can be downloaded separately
or viewed online.
Any debugging aids? (
Contents)
To debug Unimal code, you
need to insert artificial "target language" statements
providing debugging information. It is similar to
old-fashioned debug prints in common programming
languages, except that you inspect the debug information
in the Unimal output file rather than during the program
execution.
A powerful technique of
debugging Unimal code is to craft appropriately and
employ the special macro uAutoLine which expands
automatically. Please see the manual for more
information on this automatic macro.
Currently, there is no
interactive debugger for Unimal. If you would like to
see interactive debugging capabilities in Unimal,
please, let us know.
How about a convincing example? ( Contents)
"Unimal
allows reducing code maintenance complexity, reducing
the project's memory requirements and (in embedded
systems) putting in ROM what otherwise had to be
calculated in runtime." To support this claim,
consider the following example.
A project uses a table of
objects of some sort. Each object is equipped with its
unique numeric key. In C, it might look like this:
const
ob_type myobjects[] = {
{9, myob},
{11, yourob},
{24, ourob},
{27, theirob},
};
It is required to create a
very fast access method to the objects by the key ,
i.e., a function that takes the key as an argument and
returns a 1-based index of the object's entry (or 0 if
no such object exists). Below is Unimal implementation
of a two-tier key lookup table search ("Expand" is the
macro invocation operator; for explanation of the Unimal
macros used here, please, refer to Unimal Application
Note 4).
#MP Set SplitDivisor
= 4 ;algorithm
parameter
#MP Expand StartTable(myobjects)
#MP Expand ObjDef
(9, myob)
#MP Expand ObjDef
(11, yourob)
#MP Expand ObjDef(24, ourob)
#MP Expand ObjDef(27, theirob)
#MP Expand EndTable()
Here is the C code Unimal
generates:
const
ob_type myobjects[] = {
{9, myob},
{11, yourob},
{24, ourob},
{27, theirob},
}; //End of the original object table const int
mylookup[]={//merged lookup table(s)
0,
1,
3,
2,
2,
4,
}; //done with common table
myaccess(int key)
//access method
{
int Ob; //index of the object in
ObjTable
Ob =
mylookup[mylookup[key/4-2]+key%4];
if(Ob<1 || Ob >4) return 0;
//out of range
if(myobjects[Ob-1].key!=key)
return 0;
//check failed
return Ob;
}
One can see that the
access method is very efficient and the necessary lookup
table is very small. So, we've got a fast and
compact access function with performance
independent of the size of the table.
The next observation: If
the table of objects changes, the new access method will
be generated automatically at the next compilation, so
we've got zero-maintenance implementation.
And indeed, our lookup
table is calculated in compile time and can be ROM'ed,
so we've got start-up time and RAM consumption
reduced.
Including Unimal in a toolchain ( Contents)
This is fairly
straightforward. Since Unimal is a console (command
line) utility, it is included in a project pretty much
like any compiler is.
If
you use Make utility to build your project, you can
define dependencies on Unimal files, or you can define
inference rules for Unimal file extension(s). Unimal
can generate include file dependencies, so it is
possible to use it in professionally robust makefiles.
To include
Unimal in an integrated development environment, such as
Codewright, the simplest way is to define Unimal
as a compiler and associate Unimal file extension(s)
with this new compiler.
It is also
possible to include Unimal in proprietary IDEs which
allow third-party tools integration (such as, for
instance, IAR Embedded Workbench).
To make the
integration with IDE error parsers and code browsers
easier, Unimal supports customization of error message
format and can emit input and output file and line
information.
If you have
any difficulties integrating Unimal, please, contact
us and we will be happy to help.
|