Since the introduction of the enhanced macro commands with Release 3.0, several users have suggested that in addition to the information made available in the User's Manual and in previous issues of EMME/2 News, it would be useful to illustrate these new macro commands by means of small example macro files. The following is an attempt to do just that.
We do not repeat here the description and syntax of the macro commands. These can be found in section III-2.2 of the User's Manual (assuming that you have updated your copy of the manual with the replaced pages that were sent out with Release 3.0), as well as in the February issue of EMME/2 News. It might be helpful to have these references handy for understanding fully the examples that follow.
As a first simple example, using the standard link subset selection, we would like to select all links that are contained entirely in a given rectangular network window. The window is specified by its lower left and upper right x/y coordinates. For the window LL=480/100 UR=880/400, this can be done without using a macro as follows:
Enter: Desired link types or attributes (from,to) = xi=480,880 = and xj=480,880 = and yi=100,400 = and yj=100,400 =
If this type of selection occurs often within an application, it might be a good idea to define a macro called window in the following way
Enter: Desired link types or attributes (from,to) = ~>window 480 100 880 400 xi=%1%,%3% = and xj=%1%,%3% = and yi=%2%,%4% = and yj=%2%,%4% = = ~>
The values 480, 100, 880 and 400 are the initial values for the macro
parameters %1%
, %2%
, %3%
and %4%
, to be used during the
saving phase of the macro. The so saved macro can from now on be
recalled for any other window, just by calling the macro with the
new window coordinates, e.g. entering
~<window 330 145 370 175
will generate the dialog using these new window coordinates
Enter: Desired link types or attributes (from,to) = < xi=330,370 = < and xj=330,370 = < and yi=145,175 = < and yj=145,175 = < = <~<
This demonstrates how to create and recall macros using parameters. The macro file created in this way is an ordinary sequential text file called "window" which contains the lines as they were entered, i.e.
xi=%1%,%3% and xj=%1%,%3% and yi=%2%,%4% and yj=%2%,%4%
It is a good practice to include comments and tests into macros, that are used for production purposes. As an example, here is a more complete version of the same macro window, which is commented and which checks that it is indeed called at the level of an Enter-question and that there are four parameters specified:
~/ ---------------------------------------------------------------- ~/ window - select links that are within a specified network window ~/ usage: window <xll> <yll> <xur> <yur> 88-07-01 HS ~/ ---------------------------------------------------------------- ~?q>0 / Is it really an enter question? ~$error ~x=%0% / At least 4 arguments? ~?x<4 ~$error xi=%1%,%3% / Select link subset. and xj=%1%,%3% and yi=%2%,%4% and yj=%2%,%4% ~$end ~:error ~/ usage: window <xll> <yll> <xur> <yur> ~:end
While the above macro may be more complex than needed, given the simplicity of the
task it performs, it illustrates well some of the more elaborate
macro commands. The "~/
" lines are simply comments. The "~?q>0
"
tests if the current question is of the Enter variety or not.
If not (q>0), the "~$error
" command branches to the label "~:error
"
and displays an appropriate error message. If the type of question
is correct, the macro proceeds to check the number of arguments, contained
in the read-only register %0%
. The "~x=%0%
" command sets the register
x to the number of arguments, which is then tested to be at least 4
by means of the command "~?x<4
" (if not branching again to the "~:error
"
label).
In the second example, we look at the task of punching out several matrices with a single macro invocation. Module 3.14 allows the punching of one matrix only at a time and for a large application this task is quite time consuming. Having a macro "punchmat" that punches out all the matrices given as arguments saves waiting in front of the terminal for the individual punches to be completed. Here is one way to accomplish this task:
~/ ----------------------------------------------------------------- ~/ punchmat - punch the matrices specified as arguments 88-07-01 HS ~/ ----------------------------------------------------------------- 3.14 / call module 3.14 ~y=0 / reset register y ~:next 3 / punch %1% / matrix identifier
~?q=1 no / not the same constraint matrix / no constraint matrix ~?q=1 no / no aggregation by origin ~?q=1 no / no aggregation by destination ~?q=1 no / no submatrix ~% / shift macro arguments one to the left ~y+1 / count number of matrices punched so far ~x=%0% / x is now the number of arguments left ~?x>0 / branch if still work to do ~$next q / back to main menu ~/ Matrix punch complete, %y% matrices punched ^G^G^G^G
Note that this macro contains already some "bells and whistles" that are not absolutely necessary, but make its use more easy. We will not explain the macro line by line, but rather point out some interesting details. (See section IV-3.14-3 of the EMME/2 User's Manual for the details of the dialog this macro is running through.)
~?q=1
" will
insert the answer "no" only if the question is indeed asked, i.e. if
the current question is of the type Yes/No. The same method is used
for the questions "Aggregation by origins?" (asked only for matrices of types
mo and mf), "Aggregation by destination?" (asked only for matrices of types
md and mf) and "Submatrix?" (not asked for scalar matrices).
~y=0
" and
every time a matrix has been successfully punched, it is incremented
with the command "~y+1
".
It is used to generate a message at the end that displays the number of
matrices that have been punched. This type of message is very useful
at the end of a macro that might take too much time for the user to wait
in front of the terminal. When he returns, the screen will
display this message reminding him of the task that was performed
and confirming that no problems were encountered. The message can
also contain BELL characters (^G
in the above example) which produce a
high-pitched sound when sent to the terminal, informing the user that
the macro has terminated.
~%
" which discards the current parameter %1%
(which has already been handled) and shifts down all remaining
parameters by one, leaving the next in row as %1%
. The number of parameters
left is contained in %0%
, which is copied into the x register where
it can be tested to find out if the job is done.
~$...
" and "~:...
".
The third example performs a task similar to the one we just saw. Instead of punching a set of specified matrices, we now want the macro to punch out all matrices of certain types . It is called "punchall" and takes as arguments any combination of the type identifiers "ms", "mo", "md" and "mf".
~/ -------------------------------------------------------------- ~/ punchall - punch all matrices of the given types 88-06-24 HS ~/ ~/ This macro will punch out all matrices of the specified type ~/ E.g. "~<punchall md" will punch out all destination matrices, ~/ whereas "~<punchall ms md mo mf" will punch out all existing ~/ matrices in the data base. ~/ -------------------------------------------------------------- 3.14 c='punchall %1% %2% %3% %4%' / call mod 3.14 - use log book comment ~x=0 / reset register x (will loop through matrix numbers) ~y=0 / reset register y (number of matrices punched so far) 3 / punch ~:next ~x+1 / set next matrix number ~?x>25 / all matrices tested? (max number of matrices is here 25) ~$ntype %1%%x% / matrix identifier ~?e ~$next ~?q=1 no / not the same constraint matrix / no constraint matrix ~?q=1 no / no aggregation by origin ~?q=1 no / no aggregation by destination ~?q=1 no / no submatrix ~y+1 / count number of matrices punched so far 3 / punch ~$next ~:ntype ~% / shift macro arguments one to the left ~z=%0% / z is now the number of arguments left ~x=0 / reset register x to prepare for new matrix type ~?z>0 / branch if still work to do ~$next / no more matrix to punch q / back to main menu, display message ~/ Matrix punch complete, %y% matrices punched
Of course, the notes a) to d) given in the last example are also valid here, but there are some more points that merit special attention:
%1%
contains
the matrix type. For matrices that are not defined, entering the identifier
at the line %1%%x%
will cause an error. Usually, when any error
condition is detected
the macro processing is immediately terminated with the message "<ERROR!<".
In this case, however, the line "~?e
" tests if an error has occurred, thus
preventing the macro from aborting prematurely.
The only macro command that we have not encountered in any of the above
examples, is the read line command "~*
". It can be used to take the
input to a given question not from the macro file, but have the user enter
it from the terminal. As very simple example, consider the following
small macro file named newtitle:
1.23 / call module 1.23, "modify titles and units" 1 / change project title ~* / <<<< the title is entered here by the user q / back to the main menu
This last example shows how the "~*
" command could be used
to write macros that answer some of the questions automatically,
leaving some others to the user to enter interactively.