next up previous
Next: 3. Hierarchical Macro Calls Up: A Tutorial on the Previous: 1. Introduction

2. Macro Command Language Summary

  This section is not intended as a general introduction to EMME/2 macros. Rather, it was written with the intention of being ``a quick refresher'' for users that have already worked with the macro language, but do not have the same degree of familiarity with all features of the language.

In order to get an idea what the concept of ``macros'' in the context of EMME/2 is all about, let us first look at the general framework how the operation of the EMME/2 package is controlled by the user.

The basic method of telling EMME/2 what to do is based on the notion of dialog. The dialog consists of a sequence of interactions in which the system asks questions, which in turn are answered by the user. The structure of this dialog is quite simple, as there are only three well defined types of questions that make up the dialog:

Yes/No Question:
This question is identified by the question mark ``?''. Possible answers are limited to ``yes'', ``no'', ``restart'' (back to beginning of current module) or ``quit'' (back to main menu).
Select Question:
A choice of two or more alternatives is presented to the user, each one preceded by a sequential number. The user answers by choosing one of the alternatives by entering the corresponding number, or she has the possibility to ``restart'' or ``quit''.
Enter Question:
This type of question is always used when the user is prompted to enter one or several textual or numerical data items. The question terminates with an equal sign ``='' as prompt for the user to enter the data. If the ``='' appears on the same line with the question text, the answer is limited to a single line, but if the ``='' appears on a separate line underneath the question text, the answer is composed of multiple input lines, terminated by an empty line.

When EMME/2 is used interactively, all answers to the questions asked in the dialog are provided by the user, who is typing them at the keyboard as he goes along. The macro language provided in EMME/2 is simply a mechanism which generates these answers automatically, according to a macro script. In other words, whatever a user can do by operating the EMME/2 dialog interactively can also be implemented in a macro.

Therefore, in its simplest form, a macro consists of just a straight sequence of pre-defined answers that are passed back, one after the other, to the EMME/2 dialog. However, in most real-life applications, this would not be good enough, as the answers that need to be generated by the macro are seldomly exactly the same from one run to the other. To address this need, the macro language incorporates many features that allow the implementation of ``intelligent'' macros, such as:

In the remaining part of this section, a brief overall summary of the EMME/2 macro language is given, based on the implementation in EMME/2 Release 8.

Various types of macro registers are available. Some of them are read-only registers which contain system defined parameters, others are writable by the macro, so that they take the role of programming variables, which can be used for computations, counters, etc. All numeric registers are restricted to integer values. Text registers have a maximum length of 128, but since the maximum macro line length is also limited to 128, it is normally not possible to attain this maximum. The following table gives an overview of all available registers.

Macro Registers
bintegerread-onlyBatch mode indicator (1:interactive, 2:batch). In batch mode all reports are written to the report file, all plots are written to the plot file, without corresponding select questions and regardless of the settings of switches 0 and 1. Also, in batch mode, no change of range is possible after a plot is generated with modules 2.43, 3.16 or 4.13, the module returns to the primary select right after the plot is terminated.
dintegerread-onlyDate register. Contains a six digit integer value of the form YYMMDD, where YY indicates the year (0-99), MM the month (1-12) and DD the day of the month (1-31).
eintegerread-onlyNumber of last error. This register contains the number of the last error (warning or fatal) which has occurred, as described in Appendix A of the User's Manual. It can be used to take the corrective action after an abortive error condition has been detected, or also to determine, if errors occurred while reading a file using batch input.
fintegerread-onlyScenario status flags for current scenario. This register contains a bit pattern defined as follows: bit 0: protected against forced module execution bit 1: protected against network modifications bit 2: protected against scenario deletion bit 5: ready for an auto assignment bit 6: ready for a transit assignment bit 10: contains valid auto assignment bit 11: contains valid transit assignment
iintegerread-onlyBit pattern containing the current state of switches 0-31. See User's Manual for definition of the individual switches.
mintegerread-onlyCurrent module number. This register contains the number of the currently active module as a 3-digit integer value.
qintegerread-onlyType of current dialog question. This register can be used to determine the type of question the macro is currently expected to answer. A value of 1 indicates a Yes/No question, a value N>1 indicates a Select question with N alternatives, and a value of 0 is used for Enter questions. A value of -1 indicates an extra input line generated when bit 6 of the control register o is set (see section 6 for more information). The register q is very useful to synchronize a macro in situations where the dialog varies depending on the current context (e.g. the dialog of an assignment preparation is slightly different if the scenario already contains a valid assignment).
sintegerread-onlyNumber of the current scenario.
vintegerread-onlyVersion of current module. This register contains an integer value which indicates the major release level (hundreds and up) and the minor update level (last two digits) of the current module.
x,y,zintegerread/writeGeneral purpose integer registers. These three registers can be used by the macro to hold or compute any type of numeric information.
pinteger tex2html_wrap512 The p register provides a convenient mechanism to access system, global and scenario parameters. When a value is written into the p registers, it is interpreted as the address of one of these parameters. When, on the other hand, the value of the p register is read (e.g. in the substitution %p% or in the conditional ~?p>0 ), the value of the corresponding parameter is used. See section 7 for further discussion.
ointegerread/write The o register contains a bit pattern, which can be used to control the various aspects of the dialog output. See section 6 for further discussion.
r1-r250realread/writeGeneral purpose single precision floating point registers. These registers can be used to hold and manipulate any kind of numeric information. Instead of specifying the register number explicitly, it is also possible to use one of the registers x, y or z as index register, e.g. if y=25, accessing ry is the same as accessing r25.
g1-g250realread/writeThese single precision floating point registers are used to directly access the elements of the get()/put() stack. This allows direct two-way interactions between macros and expression evaluations. Instead of specifying the register number explicitly, it is also possible to use one of the registers x, y or z as index register. Since there is only one get()/put()stack, the gN registers are global, i.e. shared by all levels of macro invocation. Note that these registers are reset to zero each time a new module is started.
t0-t9textread/write Ten text registers of up to 128 characters are available. The register t0 is special in that it always corresponds to the current macro calling parameters %1% %2% %3% ... . Thus, changing the contents of t0 will always affect the macro parameters, and, vice versa, modifying the macro parameters (e.g. with the ~% command) will affect t0. The register t9 is a global register, i.e. its value is common to all levels of macro invocation, so that this register can be used to pass return values from the called macro to the calling macro.

As explained above, the basic task of a macro is to provide ``automatic'' answers to the EMME/2 dialog. Since often these answers depend on the context, an important component of the macro language is a general substitution mechanism which can be used to implement such dependencies. Those parts of the answers that are not fixed, but have to be replaced by context dependent information at the time the macro is executed, are coded into the macro text as substitution keys. These keys are always surrounded by % signs (e.g. %1% or %ms77.6%), in order to make them easily recognizable and to prevent ambiguities with the fixed parts of the macro text. At execution time, all valid substitution keys are replaced by their corresponding current value.

The following table contains a list of all possible substitutions:

Macro Substitutions
key:substituted by:
%0% Current number of macro parameters. This number is always between 0 and 9. Since at most 9 parameters are available for direct substitution, the number does not exceed 9, even if the number of actual parameters is larger than 9. Often %0% is used to determine if a macro has been called with the correct number of parameters.
%1% ... %9% Macro parameters 1 to 9. If a parameter is not defined it is substituted by an empty string. Note that the text register t0 always corresponds to the current macro parameters.
%reg% Value of register reg.
%reg_W% Value of integer or floating pointregister reg using a predefined field width of W characters. If the value does not completely use the specified field width, it is adjusted to the right.
%freg.D% Value of integer or floating point register freg using D digits after the decimal point.
%freg.D_W% Value of floating point register freg using D digits after the decimal point and a predefined field width of W characters.
%u% User initials, as specified at session start.
%tN.L.% The first L characters of text register tN.
%tN.-L.% The contents of the text register tN without the first L characters.
%msN.D_W% The substitution key is replaced by the value of a scalar. N can be a number between 1 and 99, or alternatively, one of the letters x, y or z. In the latter case, the scalar is addressed indirectly by using the scalar number which corresponds to the current value of the corresponding register. By default, automatic formatting is used, which eliminates redundant trailing zero decimals. If needed, the scalar identifier can optionally be followed by a decimal point and a digit between 0 and 9, and/or an underscore character followed by a field width. In this case, the format conversion is forced to use the corresponding number of digits after the decimal point and/or the specified field width. Note that when D=9, the default automatic format conversion is used.
%msN.n% Same as above, but the name of the scalar is substituted instead of its value. Any trailing blanks are removed from the 6 character name.
%msN.d% Same as above, but the description of the scalar is substituted instead of the scalar value or name. Trailing blanks are removed from the 40 character description.
%%% This sequence is substituted by a single %. This is often useful for preventing the substitution of a valid substitution key.
Before being executed, each line of the macro file is checked for any of the above substitution keys, and the necessary substitutions are performed. This holds for macro lines that contain dialog answers, as well as lines containing macro commands. The only exceptions are the macro address labels, where, for the sake of efficient branching, no substitution is applied.

All lines in the macro file that do not start with the tilde character (~) are assumed to be dialog answers. After the applicable substitutions have been made (if any), they are passed back to the calling module.

Lines in the macro file which start with a tilde character (~), or alternately with a blank followed by a tilde character, are called macro commands. These commands are used to control the macro's operation without necessarily generating a dialog answer. The following list summarizes the available commands and their syntax.

Macro Commands
~/comment Comment line. When a comment is encountered during the processing of the macro, the comment line is copied to the screen and the processing continues without further actions. If the bit 1 of the o-register is set to OFF, the comment command is copied as a whole to the screen, if set to ON, the leading ~/ characters are omitted, so that the text will not be recognizable as a macro comment.
~~/comment Comment with no line-feed. This variant of the comment command is similar to ~/, but the comment is output without finishing the line with a line-feed character. This allows a macro to write a line on the screen in several steps, which can be useful to implement progress reports as the macro executes.
~*prompt string Read line from keyboard. This command will interactively read one line from the keyboard. An optional text string can be given after the command, which will be displayed as a prompt on the same line on which the answer is to be typed in by the user. If no prompt string is specified, the string ``>>'' is used by default. Normally, the line which is entered interactively by the user is passed directly back to the calling module as answer to the current question. However, if the command appears to the right of a ``set text register'' command (e.g.: ~t2=~*Enter: Matrix to symmetrize=), the command can be used to save the text entered by the user into the specified text register.
~:label Define address label. This command is used to define a branch target address in the macro. The execution of a branch command with the same label string (~$label) will cause the macro to be continued at this address. The label strings of the branch command must exactly match the string in the corresponding label definition command, including leading and trailing blanks! Note that the usual macro substitution (%...%) does not apply to this command (for efficiency reasons).
~$label ~$>label Branch to specified address label. In the simple branch statement (~$), the macro file is rewound to the beginning and the macro file is scanned until a corresponding ~:label is found. In the case of the forward branching (~$>), the macro file is scanned starting from the current position (i.e. is not rewound) for the corresponding label. If the target address is known to be located after the branch command, using the latter form is much more efficient, especially when dealing with large macro files. (In compound macro commands ~+...(see below) an ``empty'' branch command ~$, i.e. without specifying any label, can be used to branch back to the beginning of the compound statement.)
~% Discard current first parameter %1% and shift remaining macro parameters by one position to the left. The second parameter will be moved into position 1 (%1% tex2html_wrap_inline480 %2%) , the third into position 2 (%2% tex2html_wrap_inline480 %3%), and so on. This command is useful when a macro does the same operation on all specified parameters. In this case, the operation is implemented for the first parameter using %1%, then the parameters are shifted using the ~% command, and this sequence is repeated as long as there are still macro parameters remaining.
~reg=value This class of commands is used to initialize a writable text or integer register reg to a given value value. reg can be any of of the integer registers p, o, x, y or z, the floating point registers rN and gN, or the text registers t0 - t9. Since this command is subject to the usual substitutions before being executed, it can also be used to copy values from one register to another , e.g. the command ~x=%z% copies the contents of the register z to register x.
~reg tex2html_wrap_inline494 value This class of commands is used to perform an integer arithmetic operation on a writable numeric register reg, where reg can be any of of the integer registers p, o, x, y or z, or the floating point registers rN and gN, The operator tex2html_wrap_inline494 can be any of + (addition), - (subtraction), * (multiplication), / (division), % (remainder of division), and only for integer registers | (bitwise OR) or & (bitwise AND). The first operand is always the current register value, while the second operand is the specified integer value value. The result of the operation is stored back into register reg. Since the command is subject to the usual substitutions before being executed, standard register substitution can be used for performing operations based on the value of another register. E.g. the command ~z+%y% adds the contents of register y to register z ( tex2html_wrap_inline498 ).
~?reg tex2html_wrap_inline500 value ~?!reg tex2html_wrap_inline500 value Conditional. This command is used to test the current contents of a register reg against a given value value. The following comparison operators tex2html_wrap_inline500 are available: < (less than), = (equal), > (greater than). For text registers, these comparisons are done using the standard ASCII collating sequence. For integer value registers the bitwise AND operator & is also available to test for bit masks. In the first form of the command, the line following the conditional is carried out only if the specified condition is true (skipped otherwise). In the second form (~?!), the condition is complemented, i.e. the following line is executed if the condition is false condition, and skipped if it is true. Note that the latter form in fact allows the implementation of the comparisons tex2html_wrap_inline506 , tex2html_wrap_inline508 and tex2html_wrap_inline510 .
~?e ~?!e Test for error condition. This command is used to detect if an error condition has (or has not) occurred since the last macro command. The line following the ~?e is executed only if an error condition has occurred, whereas the line following the ~?!e is executed only if no error condition has been detected. These two commands can be used to catch and correct error conditions which, if not caught in this way, would cause the macro processing to be interrupted immediately.
~<macro p1 p2 ... Call macro as a sub-procedure of the current macro. The specified macro macro is executed with the given parameters. Upon termination of the lower level macro, the current level macro continues its execution normally. Each level of macro invocation sees its own private set of registers. The values of these private registers are initialized to the current values of the same registers in the calling macro, but they can be modified by the called macro at will, without danger of disturbing the macros at higher levels. Text register t9 and the floating point registers gN are exceptions to this rule, in that all levels of macro invocation share the same (global) value. Thus, these registers (in particular t9) can be used to pass return values back to the calling macro.
~!external cmd Command escape to the operating system. The external command is passed to and executed by the underlying operating system. This command allows any kind of external programs and procedures to be integrated into a macro. Since the operating system depends on the installation, imprudent use of this command will result in macros that will only run in a particular operating environment.
~+X....X....X.... Compound macro command. This command can be used to ``pack'' several dialog answer lines and macro commands into a single physical line of the macro. The character immediately following ~+ is used as separator between the partial commands (here X is used, but any other printable ASCII character can be used). The compound command is not only useful to group dialog answers into logical groups (making the macro file considerably shorter and easier to read), but, immediately after a conditional, it can also be used to make the conditionals act on an entire group of answers or commands. Note that, except for label definitions (~:) and other compound statements (~+), all macro commands can be used as subcommands. The standard substitutions are applied twice, once for the compound command as a whole, and once at the level of each subcommand. Thus, care has to be taken if the registers used in the substitution are also modified within the compound command. An empty branch command (~$, no label) within a compound macro command will cause a branch to the beginning of the compound command. This type of branching is particularly efficient, since it does not imply scanning of the macro file to find the corresponding label.
Since a macro file is a regular ASCII text file, it can be edited using any text editor that the user is familiar with. Usually, a macro is created by first building an initial skeleton version of the macro using the ``save macro'' command ~>macrofile p1 p2 p3 ... (this mode of operation is also referred to as macro learn mode. The basic functions of the macro are then carried out interactively while EMME/2 is transcribing all dialog input into the designated macro file. Note that during this process it is already possible to define and use macro parameters, as well as any other substitution keys. This is done by specifying the values of the macro parameters which are to be used while the macro is being saved on the command line. Then, while interactively creating the macro, whenever a part of the input is not fixed, but needs to be substituted when the macro is executed later on, the user enters the substitution keys instead of their actual current values. The substitution mechanism will now do the necessary replacement even during the interactive macro definition. In this way, a macro is created which already contains the proper substitution keys. An empty save command (~> - no file name!) is used to terminate the saving of a macro in learn mode.

While a macro is created using the ``save macro'' command, it is also possible to enter directly some of the more simple macro commands, such as comments (~/...), register assignments and operations, label definitions and read line (~*). Other commands, such as conditionals, branching and compound commands, are not accepted in the macro learn mode and will have to be added later by explicit editing of the macro file.

Exercise 2.1:
Write a macro sequence to answer the dialog generated by the question ``Enter: Matrix( mf )='', which is asked whenever a full matrix is to be specified in which results are written into. The macro should work equally well whether the matrix already exists or not. If the matrix exists, the values must not be initialized. Newly created matrices are to be initialized to zero. Assume that the matrix identifier is stored in %1%. Matrix name and description are given by the macro context.

Exercise 2.2:
When changing to a new release level, it is possible that existing macros may need to be adapted. How could a macro detect that it is being used with a higher release level than the one it has been tested with so far? Write the necessary macro statements to test for this situation and, if the release level does not match, display an error message and exit.

next up previous
Next: 3. Hierarchical Macro Calls Up: A Tutorial on the Previous: 1. Introduction

Heinz Spiess, EMME/2 Support Center
Fri Sep 27 13:04:28 MET DST 1996