As users have become accustomed in past releases, in Release 8 the EMME/2 macro language has again been the subject of major improvements and enhancements.
The most important of these developments is certainly the
introduction of the new floating point registers.
Up to 250 general purpose floating point registers can now
be used to store and manipulate floating point values. These registers
are named r1
, ..., r250
, but can also be accessed
using one of the integer registers x
, y
or z
(e.g. ry
), similar to the indexed addressing of scalars.
Floating point registers can be used in the same manner
as the integer registers x
, y
or z
, i.e. their
values can be set (e.g. ~r15=3.141593
),
operated upon (~rx*%ms91%
), substituted (%r3%
)
and tested in conditions (~?r243>0.5
).
In substitutions, the number of decimals used can optionally
be specified using the .
D known from scalar
substitution (%r3.2%
).
The availability of floating point registers will simplify the writing
of macros which are based on non-integer parameters and control variables.
Whereas before all floating point operations had to be done
via scalars operated upon by one of the calculator modules,
macros can now manipulate floating point values directly.
As is the case for the integer registers x
, y
and z
,
a local set of the floating point registers r
N
is available within each macro. When one macro
calls another macro, the initial values of the r
N
registers in the called macro are set to their current values
in the calling macro.
In addition to these general purpose floating point registers,
the current contents of the
get()
/put()
stack of the expression parser
is also accessible as a set of special floating point
registers named g1
, ..., g250
. As these are
implemented as full fledged read/write registers, macros can now
directly interact with the get()
/put()
stack.
Thus, any side results which are computed in the stack
during expression evaluations can be retrieved directly
by a macro (before, this was only possible in the calculator modules
and only after explicitly copying the stack values into scalars).
Also, by writing into the g
N registers, a macro
can load arbitrary values into the stack (e.g. lookup tables),
which can afterwards
be accessed in the expressions via the intrinsic function get()
.
As the g
N registers are tied directly to the
get()
/put()
stack, its values are global
(i.e. shared by all levels of macro invocation) and
are reinitialized to zero each time a new module is entered.
The g
N registers can, of course, also be used
in modules which do not perform expression evaluations, in this
case they simply constitute a second, global set of 250 floating point
registers, which can be used in exactly the same way as the
r
N registers.
Another new general feature of the macro language is the optional
field width suffix _
W which is now
available for all numerical register and scalar substitutions. The value of
W
specifies the total number of characters used for the substitution.
If the actual substitution requires less the W characters,
the necessary number of blank characters is prepended, so that the
register value appears right justified.
The ``~~/
...'' variant of the standard macro comment command
``~/
...'' will echo the comment text without terminating
the output line with a carriage return. With this, a single output line
on the screen can be written in several steps, which is useful to
implement progress reports that build up on the screen as the macro
executes.
We conclude this section with a small macro enhancement that will
be of particular interest to the real macro experts:
A new control bit (bit 6) is introduced in the output control
register o
. If activated, the macro will read an additional
input line whenever a programmed pause is encountered (regardless
whether actual pause is suppressed by bit 5 or not) and just before
leaving a module. With this new possibility, macros can finally
intervene even in the rare places where this was impossible before.
This bit can be used to have a macro insert prompts into pauses
(to avoid having the information on the screen flushed automatically
after a few seconds) or ``collect'' data
(such as the contents of the get()/put()
stack) just before
it is lost when the module is exited.