ML/I User's Manual --- Sixth Edition


Node:Top, Next:, Up:(dir)

ML/I User's Manual -- Sixth Edition

This manual applies specifically to version CKL of ML/I. Some features may not be supported by earlier versions; conversely, later versions may support additional features.

Copyright © 1966,1967,1968,1970,1986,2004 R.D. Eager, P.J. Brown

Permission is granted to copy and/or modify this document for private use only. Machine readable versions must not be placed on public web sites or FTP sites, or otherwise made generally accessible in an electronic form. Instead, please provide a link to the original document on the official ML/I web site.

Table of Contents

Preface

This manual describes ML/I in full detail, with examples of its applications. It is not assumed that the reader has any previous knowledge of macro processors.

A shorter, simpler document describing ML/I is also available. This is called The ML/I macro processor: a simple introductory guide. There is also a tutorial document, called An ML/I tutorial, which is probably the best starting point for completely new users. A paper describing how ML/I is implemented appeared in Communications of the ACM 13, 12 (December 1972), pp. 1059-1062; the book Macro Processors and portable software (Wiley, 1974) contains further details.

Preface to the Sixth Edition

This edition is significantly changed from earlier editions. It incorporates, within the main text, all current and new features of ML/I. It has also been rewritten in Texinfo, so that it can be published in both printed and machine readable form; this has necessitated some re-wording and re-ordering of the text.


Node:Chapter 1, Next:, Previous:Top, Up:Top

1 Introduction


Node:General description, Next:, Up:Chapter 1

1.1 General description

ML/I is a general macro processor. It is general in the sense that it can be used to process any kind of text. The text may be in any programming language or natural language, or it may be numerical data. The most important use of ML/I is to provide users with a simple means of adding extra statements (or other syntactic forms) to an existing programming language in order to make the language more suitable for their own field of application. This process of extension may be carried to the level where the extended language could be regarded as a new language in its own right. Other possible uses of ML/I are program parameterisation (e.g. a parameter might determine whether debugging statements are to be included in a program) and various applications in text editing or correction and in data format conversion.

This manual does not assume that the reader has any previous experience of macro processors. However, the reader who is familiar with macro processors might be interested in knowing the main features of ML/I before plunging into details. These features are:


Node:Organisation, Next:, Previous:General description, Up:Chapter 1

1.2 Organisation of this manual

Chapters 2, 3, 4 and 5 of this manual describe ML/I in full detail. Chapter 6 describes error messages, and Chapter 7 contains hints and examples. Readers may find it useful to look ahead to the examples in Chapter 7 if they have any difficulty with the main text. Some Sections of this manual can be omitted on a first reading; these are marked with an asterisk (like this: *). This manual does not describe features of ML/I that are implementation-dependent, e.g. operating instructions, character set, etc. Instead there is an Appendix, which describes the implementation-dependent features, for each implementation.


Node:Notation, Next:, Previous:Organisation, Up:Chapter 1

1.3 Notation for describing syntax

The notation used in this manual to describe syntax should be self-explanatory. An example of its use is the following description of a hypothetical IF statement:

   IF {condition} THEN {statement};
   

As can be seen, a syntactic form is defined by concatenating its constituents. A constituent that is itself the name of a syntactic form is enclosed in braces ({ and }). The remaining constituents are literals.

A well-known notation is used to indicate parts of syntactic forms that may optionally be repeated and/or omitted. In this notation, a constituent or series of constituents that may optionally be omitted is written:

   [{constituents} ?]
   

Constituents that may be repeated any desired number of times are written:

   [{constituents} *]
   

and constituents that may be omitted or repeated are written:

   [{constituents} *?]
   

Thus, if the above IF statement had an optional ELSE clause, it would be written:

   IF {condition} THEN {statement} [ELSE {statement} ?];
   

and a hypothetical SUM statement which permitted any number of arguments, provided there were at least two, might be defined:

   SUM {argument} [,{argument} *];
   

Lastly, when there are several alternative forms for a constituent, these are written:

   ( {form 1} )
   ( {form 2} )
   ( { :: }   )
   ( { :: }   )
   ( {form N} )
   

Thus an expression might be defined as:

   {variable} [ (+) {variable} *?]
                (-)
                (*)
                (/)
   

Note that the asterisk means that the syntactic forms enclosed within the brackets may be repeated; it is not required that identical text be written at each repetition.


Node:Further notation, Next:, Previous:Notation, Up:Chapter 1

1.4 Further points of notation


Node:Improvement, Previous:Further notation, Up:Chapter 1

1.5 Improving ML/I

Readers are invited to criticise and suggest improvements in the specification of ML/I, in the description in this manual or in a particular implementation, and in particular to point out errors and ambiguities. Reports of implementation errors should be accompanied by enough material to reproduce the error and, if applicable, references to the statements in this manual that have been contravened.


Node:Chapter 2, Next:, Previous:Chapter 1, Up:Top

2 The environment and its constituents


Node:Basic action, Next:, Up:Chapter 2

2.1 Basic action of ML/I

The basic action of ML/I is as follows. The user feeds to ML/I some text and an environment. The purpose of the environment is to specify that certain insertions, deletions, expansions, translations or other modifications are to be made in the text. ML/I performs the textual changes specified by the user. This process is called evaluation of text, and the text generated as a result of the changes is called the value text. The text being evaluated is called the scanned text. In many simple applications of ML/I, the process of evaluation consists of a good deal of straight copying, the value being the same as the original, but periodically a change is made and the generated value text is different from the original scanned text.

The purpose of this Chapter is to explain the mechanisms at the disposal of the user, and to give examples of their use. All the possible constituents of the environment will be described, and the resultant textual changes will be explained by describing the form of the scanned text and the form of the corresponding value in each case. The mechanisms for setting up the environment will be explained in subsequent Chapters.


Node:Character set, Next:, Previous:Basic action, Up:Chapter 2

2.2 Character set

The character set of ML/I (i.e. the set of allowable characters in the text it processes) is implementation-defined (see Section 3 of the relevant Appendix). However, the character set will normally contain the upper case letters A-Z, the lower case letters a-z, the numbers 0-9, and a number of characters that are not letters or numbers. Characters that are not letters or numbers are called punctuation characters. If an implementation contains both upper and lower case letters in its character set, then these are treated as entirely different sets of characters, and it is not possible to use a lower case letter interchangeably with its upper case equivalent. As will be seen, all the built-in symbols and characters that have special meaning to ML/I are in upper case (e.g. MCDEF rather than mcdef, and S rather than s).


Node:Text, Next:, Previous:Character set, Up:Chapter 2

2.3 Text

A feature of ML/I is that it does not consider text character by character, but in units of atoms. An atom is a single punctuation character, or a sequence of letters and digits that is surrounded by punctuation characters (assuming an imaginary punctuation character at the beginning and end of the text). There is no restriction on the length of an atom. To take an example, the text:

   Pig , {TAB} LAC {SPACE} 4057
   ___ _ _____ ___ _______ ____
   
    1  2   3    4     5      6
   

would be regarded as six atoms as shown. It is possible to make an exception to this rule in special cases; see the description of system variable S6 in Use of S1 to S9.

The following definitions will be used in the rest of this manual. Text is a (possibly null) sequence of atoms. The source text is the text supplied as input to ML/I, and the output text is the text derived from evaluating the source text. The physical form of the source text and output text is implementation-defined (see Section 2 of the relevant Appendix). The action of evaluating a particular piece of source text is called a process.


Node:Macros and delimiters, Next:, Previous:Text, Up:Chapter 2

2.4 Macros and delimiter structures

Before defining a macro, it may be useful to consider the sort of text replacement that macros are designed to achieve. The assembly language for a hypothetical X123 machine will be used in several examples in this manual. Assume the user wants to introduce a new instruction of the form:

ESUB X meaning `subtract X from the accumulator'

which does not exist in the X123 instruction set, but whose effect can be achieved by the sequence of three X123 instructions:

CMA complement accumulator
ADD X add X to accumulator
CMA complement accumulator

The introduction of ESUB would be achieved as follows. The user would write the program as if ESUB were an extra machine instruction. Before the program was assembled, it would be passed through ML/I with ESUB defined as a macro name with the above three instructions as its replacement text. ML/I would replace each occurrence of ESUB by its expanded form, and the resultant output could then be assembled normally. Each piece of text to be replaced is called a macro call, and the text corresponding to X above is called the argument of the call (within the replacement text of ESUB it is necessary to specify that the argument of the call should be inserted immediately after ADD. This is done by a constituent of the environment called an insert, which will be described later).

This example serves as a simple illustration of the primary use of ML/I, namely to serve as a preprocessor to an existing piece of software to allow users to introduce new statements of their own design into the existing language. Each new statement must be expandable in terms of the existing language.

Macros may have any number of arguments. Arguments are separated by predefined atoms (or sequences of atoms) called delimiters. When defining a macro, the user specifies what the delimiters are. The macro name is regarded as a delimiter, and is called the name delimiter to distinguish it from the remaining delimiters, which are called secondary delimiters. The delimiter following the last argument of a call is called the closing delimiter. The general form of a macro call can, therefore, be represented as:

   {name delimiter} [{argument} {secondary delimiter} *?]
   

Arguments may be null, but delimiters must consist of at least one atom.

Every time ML/I encounters in the scanned text an atom or series of atoms that has been defined as a macro name, it searches for the secondary delimiters (if any) and then replaces the entire macro call by the value of the replacement text for the macro. More details of the way macro calls are scanned are given in The method of searching for delimiters, and in Exclusive delimiters.


Node:Examples of macros, Next:, Up:Macros and delimiters

2.4.1 Examples of macros

It may be instructive at this stage to consider a few more examples of macros. These examples, which are listed below, are all of simple macros with fixed delimiters. Macros with more elaborate patterns of delimiters will be considered later. Note that ML/I could be used to add these macros to any desired programming language, whether high or low level.

Example 1

A macro to generate a loop, which has form:
      DO {arg A} TIMES {arg B} REPEAT
      

Here the delimiters are DO, TIMES and REPEAT. DO is the name delimiter, and TIMES and REPEAT are secondary delimiters. REPEAT is the closing delimiter. ML/I does not require that macro calls be written on a single line, and calls of this macro would tend, in practice, to span several lines of text.

Example 2

A macro of form:
      MOVE FROM {arg A} TO {arg B};
      

The name of this macro consists of the two atoms MOVE FROM.

Example 3

A macro to interchange two variables, which has form:
      INTERCHANGE ( {arg A}, {arg B} ) {NL}
      

In this example, both the name and the closing delimiter consist of more than one atom: the name is INTERCHANGE followed by a left parenthesis, and the closing delimiter is a right parenthesis followed by a newline. Note that ML/I does not, like some software, truncate long names such as INTERCHANGE.

Example 4

Assume that within a program two different names, COUNT and CONT, have inadvertently been used for the same variable. This error could be corrected using ML/I, with CONT defined as a macro with COUNT as its replacement text. Here the name delimiter, CONT, is also the closing delimiter.

The reader should, at this stage, appreciate why ML/I considers text as a sequence of atoms rather than a sequence of individual characters. If the latter were the case, ML/I would be liable to take names such as DOG and RANDOM as calls of the above macro DO, since each name contains the letters DO. As the situation stands, however, the letters DO would only be taken as a macro call if they were surrounded by punctuation characters.


Node:Delimiter structures, Next:, Previous:Examples of macros, Up:Macros and delimiters

2.4.2 Delimiter structures

The macros considered so far have had fixed delimiters. However, it is possible to have macros with any number of alternative patterns of delimiters. As a very simple example of this, consider the ESUB macro. In X123 Assembly Language, statements are terminated with either a tab or a newline, and so it would be desirable to have both of these as alternatives for the closing delimiter of ESUB.

In order to specify the pattern of possible delimiters of a macro, the user specifies a delimiter structure. Each macro has its own delimiter structure, and other constituents of the environment also have delimiter structures. A delimiter structure is a set of delimiter specifications, each of which is a sequence of one or more atoms. These sequences of atoms need not be distinct. One or more of these delimiter specifications are designated as names of the structure. The remainder are secondary delimiters. With each delimiter specification is associated a specification of its successor(s). This may be:

Successors specify what to search for next when scanning. A delimiter with a null successor is a closing delimiter. As an illustration of the use of a delimiter structure, consider the scanning of a macro call. During this scanning, each time a delimiter is found, the delimiter structure of the macro being called is referenced to find the successor(s) of the current delimiter, and subsequent text is then scanned to try to find this successor. This process continues until a closing delimiter is found.

As an example of a delimiter structure, the delimiter structure of the ESUB macro would contain three delimiter specifications with the following information about them:

a) ESUB {name} with b) or c) as its successor.
b) {TAB} secondary delimiter with no successor.
c) {NL} secondary delimiter with no successor.

The rules for setting up delimiter structures (see Specification of delimiter structures) ensure that they have certain properties. Among these properties are the following:


Node:Optional/repeated delimiters, Next:, Previous:Delimiter structures, Up:Macros and delimiters

2.4.3 Optional and repeated delimiters

It is possible, by designing a suitable delimiter structure, to have a macro with a variable number of arguments; in particular, a macro with optional arguments and/or with an indefinitely long list of arguments. For instance, suppose it is desired to implement a macro with alternative forms:

   IF {argument} THEN {argument}
   END
   

and

   IF {argument} THEN {argument}
   ELSE {argument}
   END
   

This is done by specifying that either ELSE or END is the successor of THEN. END is a closing delimiter, and ELSE has successor END. As a second example, consider a macro of form:

   SUM {argument} [ (+) {argument} *?];
                    (-)
   

This macro has an indefinite number of arguments, separated by plus or minus signs. Its delimiter structure has four members as follows:

a) SUM name with b), c) or d) as successor.
b) + secondary delimiter with b), c) or d) as its successor.
c) - secondary delimiter with b), c) or d) as its successor.
d) ; secondary delimiter with no successor.


Node:Macro definitions, Next:, Previous:Optional/repeated delimiters, Up:Macros and delimiters

2.4.4 Macro definitions

Now that the basic concepts behind macros have been introduced, it is possible to explain more exactly what makes up a macro definition. Macro definitions are the most important constituents of the environment. A macro definition consists of:

  1. A delimiter structure. The name delimiter(s) of this structure are the macro names.
  2. A piece of replacement text.
  3. An integer, exceeding two, called the capacity. The purpose of this is explained in Macro-time variables.
  4. An on/off option. If this option is on, the macro is called a normal-scan macro; otherwise it is called a straight-scan macro. The effect of this option is explained in Name environment used for examples.

The reader need not for the moment be concerned with (c) and (d), since nearly all macros will be normal-scan and will have a capacity of three.


Node:Macros and subroutines, Next:, Previous:Macro definitions, Up:Macros and delimiters

2.4.5 The difference between macros and subroutines

There is often confusion between the purpose of macros and the purpose of subroutines (or procedures). Macros, however, always generate in-line code, and so this code is inserted as many times as the macro is called. Subroutines use out-of-line code, and there is only one copy of this code for a particular program. Thus, macros are used only when the code to be inserted is short or highly parameterised. It would not be convenient, for instance, to use subroutines to perform the functions of any of the macros used as examples in previous Sections.


Node:Impossible replacements, Previous:Macros and subroutines, Up:Macros and delimiters

2.4.6 Impossible replacements

It is worth noting some of the types of replacement that it is not possible to perform by means of macros. Below are two examples of illegal syntax of macro calls, together with possible correct forms.

  1. Wrong: {arg A} = {arg B};
    since each macro call must start with a macro name.

    Right: SET {arg A} = {arg B};
    Here SET is used as the macro name.

  2. Wrong: $ {character}
    It is not possible to define an argument as the character (or atom) immediately following a given name. Every argument must be followed by some predefined delimiter.

    Right: $ {argument};
    Here a semicolon is used as the closing delimiter.


Node:Macro-time, Next:, Previous:Macros and delimiters, Up:Chapter 2

2.5 Introduction to macro-time variables and statements

The form of the value of a call of such macros as the IF and SUM macros used earlier as examples would have to depend on the particular patterns of delimiters that were used in the call. For instance:

   SUM ALPHA+BETA;
   

must generate an entirely different set of instructions from:

   SUM ALPHA-BETA-GAMMA+X+Y-Z;
   

and, in the case of IF, the value text must depend upon whether ELSE was present. Macros such as these, therefore, are more complicated than the ESUB case, where a fixed skeleton of code consisting of three machine instructions is substituted for each call. The only variable element in the ESUB case is the form of its argument. In the more complicated cases, where the delimiters provide a second variable element, the user has to write a little program which is executed by ML/I and tests the form of the delimiters used and generates code accordingly. In the case of SUM, which has an indefinitely long list of arguments and delimiters, this program would involve a simple repetitive loop to iterate through the list. Hence, ML/I contains an elementary programming language of its own. This language contains an assignment statement, a conditional `goto' statement, labels, and integer and character string variables. All of these are called macro-time entities to distinguish them from the corresponding execution-time entities, and the reader must be careful not to confuse the two. The difference is illustrated thus: the DO macro described earlier (see Examples of macros) would generate a loop which was performed at execution time and controlled by an execution-time variable; on the other hand the value text for the SUM macro would be generated by a macro-time loop controlled by a macro-time variable.

Macro variables and macro labels are considered in the next Section. Macro-time statements are considered in detail in Operation macros and their use.


Node:Inserts, Next:, Previous:Macro-time, Up:Chapter 2

2.6 Inserts

This Section describes how quantities can be inserted into text. In particular, it describes how arguments of macro calls are inserted into replacement text. However, first it is necessary to consider some of the quantities, in addition to arguments, that may be inserted into text.


Node:Variables, Next:, Up:Inserts

2.6.1 Macro-time variables

Macro variables are integer or character variables available to the user at macro-time. ML/I contains facilities for performing arithmetic on these variables (where appropriate), testing their values, and inserting their values into the text. They are useful as switches and for counting (e.g. in processing macros with a variable number of arguments), as well as for storing information which may be needed later on in a process.

There are four kinds of macro variable, namely:

  1. permanent variables, referred to as P1, P2, ...
  2. system variables, referred to as S1, S2, ...
  3. temporary variables, referred to as T1, T2, ...
  4. character variables, referred to as C1, C2, ...

Permanent, temporary and system variables are used to store integers. Character variables are used to store character strings.

Permanent, system and character variables have global scope; this means they can be referred to anywhere. An implementation-defined number of each is allocated at the start of each process, and these remain in existence throughout. The user may allocate extra permanent variables and character variables (but not system variables) if desired, see MCPVAR, and MCCVAR. The difference between permanent/character and system variables is that the former have no fixed meanings and are free for users to use as they wish, but the latter have fixed implementation-defined meanings associated with controlling the operation of ML/I. For example, in a given implementation, system variable S20 might control the listing of the source text; if it was zero no listing would be produced and if it was one there would be a listing. Sections 5 and 7 of each Appendix describe the meanings of system variables (if any) and state the number of permanent and system variables that are initially allocated. System variables 1 to 9 are normally the same in most implementations, and are described in Use of system variables.

Temporary variables, on the other hand, have a more local scope. During the evaluation of the source text there are no temporary variables in existence. However, each time a macro call is made a number of temporary variables is allocated, and these remain in existence while the replacement text of the macro is being evaluated. The number of temporary variables allocated at the call of a macro is given by the capacity of the macro (see Macro definitions). The capacity is usually three. If temporary variable N is referenced during the evaluation of the replacement text of a macro call, this is taken to mean the Nth temporary variable associated with the call. Since, as will be seen later, it is possible to have macro calls within macro calls, it is possible to have several allocations of temporary variables in existence at the same time.


Node:Variable initialisation, Next:, Previous:Variables, Up:Inserts

2.6.2 Initialisation of macro variables

The initial values of system variables, permanent variables and character variables are defined in Section 7 of each Appendix. The first three temporary variables of each allocation are initialised as follows (all other temporary variables have undefined initial values):

T1
the number of arguments of the current macro call.
T2
the number of macro calls so far performed by ML/I during the current process. The importance of this number is that it is unique to the current call.
T3
the current depth of nesting of macro calls (i.e. the number of calls, including the present one, currently being processed; calls of operation macros (see Operation macros) are not counted here, though they do count toward the setting of T2).

It is to be emphasised that these are initial values, and the user is free to change them if desired (in this way, temporary variables are unlike system variables. If the values of system variables--even those without assigned meanings--were changed arbitrarily it might have unwanted effects).


Node:Subscripts/macro expressions, Next:, Previous:Variable initialisation, Up:Inserts

2.6.3 Subscripts and macro expressions

In the previous Sections, macro variables were specified by a letter followed by a number (e.g. P2), but there are other possibilities. The general form of a macro variable is:

   (P)
   (S) {subscript}
   (T)
   (C)
   

where a subscript is an unsigned positive integer, or an integer macro variable (but not a character variable). The value of the subscript specifies the macro variable to be referenced. Thus, if T3 has value 4, then PT3 would specify P4. As a more complicated example, if T1 had value 2 and P2 had value 6, then TPT1 would specify the sixth temporary variable. If character variable 3 contained the string 16, it would be wrong to write PC3 in order to reference permanent variable 16; however, it would be possible to obtain the same effect by using an insert, in which case the user would write P%C3. instead.

Macro variables can be combined into macro expressions, which are used when it is desired to perform arithmetic calculations during macro generation. Examples of macro expressions are:

   1, -6, 3-S1, -TT1-145/P2+P3+6
   

Multiplication is represented by an asterisk, and division by a slash. Bitwise logical operations are also supported; ampersand (&) is used for logical "and", and vertical bar (|) for logical "or". The general form of a macro expression is:

   {primary} [ (+) {primary} *?]
               (-)
               (*)
               (/)
               (&)
               (|)
   

where a primary has the form:

   [ (+) *?] {operand}
   

and an operand is an unsigned integer or an integer macro variable. Redundant spaces can occur anywhere in macro expressions except within operands.

The result of a macro expression is the integer derived from calculating the expression by the ordinary rules of arithmetic. Unary operators are performed first, followed by the binary operators from left to right, with the proviso that multiplication and division take precedence over addition and subtraction. Division is truncated to the greatest integer that does not exceed the exact result. Division by zero is detected as an error. Examples of the results of macro expressions are:

1 + 2 * 3 has result 7
3 * 7/8 has result 2
7/8 * 3 has result 0
- 5/4 has result -2
5/-4 also has result -2
- 4/3 * -6 has result -6


Node:Character variables, Next:, Previous:Subscripts/macro expressions, Up:Inserts

2.6.4 Character variables

Strictly speaking, character variables should be called character string variables, or just string variables, but since their names begin with the flag character C, rather than S (which is already taken for system variables), we shall persist with the original term.

Character variables can store character strings of any length, up to a maximum known as the range. For a given ML/I process, all character variables have the same range, chosen by the user when initially allocating the first character variable. When the value of a character variable is inserted, the length of the inserted text will be the length of the string last stored in the variable, rather than the range (i.e. no trailing spaces are included unless originally stored as such).

Character variables are particularly useful as an efficient solution to the problem of `remembering' pieces of text which are to be recalled at some later point in the ML/I process. An alternative solution would be to use the MCFOR macro described in Macro-time loop.


Node:Integer overflow, Next:, Previous:Character variables, Up:Inserts

2.6.5 Integer overflow

Each implementation has a maximum absolute value which must not be exceeded by any integer derived during the calculation of a macro expression or subscript. The effect of exceeding this value is implementation-defined. See Section 5 of the relevant Appendix for details.


Node:Macro labels, Next:, Previous:Integer overflow, Up:Inserts

2.6.6 Macro labels

Since there is a facility for a macro-time `goto', there is also a facility for placing macro-time labels. These are called macro labels. Each macro label is designated by a unique positive integer.


Node:Macro elements, Next:, Previous:Macro labels, Up:Inserts

2.6.7 Macro elements

Macro variables, macro labels, arguments and delimiters are collectively called macro elements. It is convenient to regard macro elements as part of the environment. The full details of how macro elements are added to the environment are explained later; see Dynamic aspects of the environment. In essence, the rule is that every time a macro is called its arguments and delimiters, plus a set of temporary variables, are automatically added to the environment, and this supplemented environment is used to evaluate the replacement text of the call. Similarly, when a macro label is encountered, its position is `remembered' by adding it to the environment.


Node:Insert definitions, Next:, Previous:Macro elements, Up:Inserts

2.6.8 Insert definitions

It is now possible to define the constituent of the environment, called an insert definition, which is used for such purposes as to tell ML/I to insert a particular argument of a macro at some point in its replacement text. An insert definition consists of:

  1. A delimiter structure. Since all inserts have fixed delimiters and exactly one argument, this delimiter structure will be a simple one. It will consist of a name with a single successor, this successor being a closing delimiter.
  2. An on/off option. If this option is on, an insert is called protected; otherwise it is called unprotected. The use of this option, which need not be of much concern to the average reader, is described later; see Protected and unprotected inserts.

At each point where the user wishes something to be inserted, they should write the following construction, called an insert:

   {insert name} {argument} {delimiter}
   

In the rest of this manual, for the purpose of examples, it will be assumed that the atom % is an insert name, with the atom . as its closing delimiter. With this assumption, the following are examples of inserts (the exact meaning of these will become apparent later):

   %A6.  %P1.  %LT2.  %WA P9-16*T3.
   

On encountering an insert, ML/I evaluates the argument of the insert (in case it contains macro calls, etc.) and the resulting value text acts as a specification of what to insert. The value text must consist of a flag followed by a macro expression. In the first above example, the flag is A and the macro expression is 6. The flag may be null, or it may be any of the following: A, B, D, L, WA, WB or WD. Any number of redundant spaces is allowed before, after or within a flag.

The meaning of the various flags is explained below. In each explanation, `N' is used to represent the value of the macro expression following the flag. More examples are given in the next Section. An attempt to insert something which does not exist (e.g. the third argument of a macro with only two arguments) results in an error. The meanings of the flags are:

  1. A. This flag is used within the replacement text of a macro to evaluate and insert the Nth argument of a call of the macro. Any spaces at the beginning or end of the argument are deleted before it is evaluated. In the case of this flag, and in cases b) and c) below, the piece of text that is evaluated and inserted is called the inserted text.
  2. B. As case a), except that spaces are not deleted.
  3. D. As case b), except that the Nth delimiter, rather than the Nth argument, is inserted. The name of a macro is considered as delimiter zero, and the Nth delimiter is thus the delimiter following the Nth argument.
  4. WA, WB, WD. As cases a), b) and c) respectively, except that the inserted text is not evaluated but is inserted literally, exactly as written (W stands for `written'). The difference between this and the previous cases arises if the inserted text itself involves macro calls, inserts, etc. In the previous cases these are evaluated; in this case they are not.
  5. Null. The numerical value of N, represented as a character string, is inserted. This character string contains no redundant leading zeros. It is preceded by a minus sign if N is negative; otherwise no sign is present.
  6. L. This is used to place a macro label, and is rather different from the above cases in that nothing is inserted (i.e. the value of the insert is null). The label N is, if acceptable, added to the current environment and may be the subject of a macro-time `goto'. A macro label is acceptable if it is inserted within a piece of replacement text or inserted text and has not already been defined within that text. It is legal to insert a label in the source text, but since, as will be seen later, it is not possible to have a backward `goto' within the source text, such labels are not added to the environment (i.e. they are `forgotten'). Macro labels are local to the piece of text in which they occur, and there is no harm in using the same label numbers within different pieces of text. Label numbers can be chosen arbitrarily, except that they must be positive.


Node:Insert examples, Previous:Insert definitions, Up:Inserts

2.6.9 Examples of inserts

The following examples illustrate the use of inserts:


Node:Skips, Next:, Previous:Inserts, Up:Chapter 2

2.7 Skips

The description so far has implied that every occurrence of a macro name in the scanned text is taken as the start of a macro call. This would mean that the user had no easy means of getting macro names or, for that matter, insert names into the value text. Moreover, if he or she were unfortunate enough to use a macro name within any comments, then ML/I would take this as a macro call and would start searching for delimiters. To get round these difficulties the user places skip definitions in the environment, and by this means can cause ML/I to ignore comments and to take certain strings as literals.

A skip definition consists of:

  1. A delimiter structure. The names of this structure are called skip names.
  2. Three on/off options. These options are: the text option, the delimiter option and the matched option.

The action of ML/I on finding a skip name is similar to the action on finding a macro name. In both cases a search for delimiters is made until a closing delimiter is found. The text from the skip name to its closing delimiter is called a skip. A skip, therefore, has form:

   {skip name} [{argument} {secondary delimiter} *?]
   

In most practical applications of skips, there will be exactly one argument. The arguments of skips are treated as literals, exactly as if all macro definitions, insert definitions and warning markers (see later) had been temporarily removed from the environment during the scanning of the skip. There is no replacement text associated with a skip; instead the value of a skip is defined simply by the setting of two of its options. These options, which are independent of one another, have the following effect:

As an example of the use of a skip, assume the source text contains comments that begin with the word COMMENT and end with a semicolon. In order to skip these comments, the user would define COMMENT as a skip name with semicolon as its closing delimiter. In this case, if the following comment occurred:

   COMMENT THIS DO LOOP ZEROISES ARRAY X;
   

then its value (i.e. the piece of text copied over to the value text) would be one of the following:

  1. If both options were on, its value would be:
          COMMENT THIS DO LOOP ZEROISES ARRAY X;
          
  2. If neither option was on, its value would be null.
  3. If only the delimiter option was on, its value would be:
          COMMENT;
          
  4. If only the text option was on, its value would be:
          THIS DO LOOP ZEROISES ARRAY X
          

If COMMENT was not defined as a skip at all, then comments would normally be copied over to the value text as in case a). However, if in the above example DO was a macro name, then ML/I would try to find the delimiters of DO and replace the call of DO by its replacement text. This is clearly undesirable. The chances are that the entire source text would be scanned without finding the required delimiters. Hence the use of skips to inhibit the recognition of macro names within certain contexts.

It will be assumed in the rest of this manual that COMMENT is a skip name, with a semicolon as its closing delimiter.


Node:Matched/straight skips, Next:, Up:Skips

2.7.1 Matched skips and straight skips

Assume the user has written the comment:

   COMMENT THIS COMMENT MARKS THE HALF-WAY STAGE;
   

In this case, the skip name COMMENT appears within an argument of the skip COMMENT. However, it is clearly undesirable that ML/I should treat the second COMMENT as a nested skip and try to match it with a semicolon. To prevent this happening, COMMENT would be defined as a skip with the matched option off. This is called a straight skip.

However, there are applications of skips where it is desirable for nested skips to be recognised, and such skips have the matched option on. They are called matched skips. Literal brackets, which are described in Literal brackets, are an example of the application of a matched skip. If ML/I encounters any skip name during the scanning of a matched skip, it matches the nested skip with its delimiters before matching the containing skip with its delimiters. The scanning process is described in more detail in The method of searching for delimiters. In a nest of skips, the value is entirely controlled by the options associated with the outermost skip.


Node:Literal brackets, Next:, Previous:Matched/straight skips, Up:Skips

2.7.2 Literal brackets

It is usual to have in each environment a skip definition consisting of a name and a closing delimiter with the options set in such a way that at every occurrence of the skip the argument is copied and the delimiters deleted. Such skips are called literal brackets. It will be assumed in the rest of this manual that the name < with closing delimiter > have been defined as a pair of literal brackets. If it was required to copy a piece of text literally over to the value text, ignoring all macro calls and inserts, then the text would be written:

   < {text} >
   
The process of evaluation would consist simply of removing the literal brackets. Literal brackets always have the matched option on. The reason for this will become apparent in Use of literal brackets for surrounding operation macro arguments.


Node:Matched skip example, Next:, Previous:Literal brackets, Up:Skips

2.7.3 Example of a matched skip

The following example, which is rather more complicated than any situation likely to arise in practice, illustrates the full implications of the rules for the matching of skips.

In the text:

   < AAA < BBB COMMENT < ; CCC > DDD >
   

the initial < is matched with the last >. (The occurrence of < after COMMENT is not recognised as a skip name, since COMMENT is a straight skip). The value of this text is:

   AAA < BBB COMMENT < ; CCC > DDD
   

This value is independent of how the delimiter and text options for COMMENT are set.


Node:Warning markers, Next:, Previous:Matched skip example, Up:Skips

2.7.4 Warning markers

Up to now, ML/I has been described as if every occurrence of a macro name not within a skip is taken as the start of a macro call. In fact, this is only true if the environment is in free mode.

If desired, the user may place the environment in warning mode by defining one or more warning markers. Any atom or series of atoms may be defined as a warning marker. In warning mode, each macro call must commence with a warning marker. Optional spaces are allowed between the warning marker and the macro name which follows it; this means that in warning mode it is not possible to have a macro name that begins with a space. Thus, if CALL were a warning marker, the ESUB macro would be called by writing:

   CALL ESUB X {NL}
   

In warning mode, each occurrence of a warning marker must be followed by a macro name; failure to do so will result in an error message. The message can be suppressed by setting system variable S3 (see Use of S1 to S9) to one. This is useful if macro calls in the source text are only to be recognised in certain positions, e.g. following a tab or at the start of a line. In such examples the characters `tab' or `startline' could be defined as warning markers, and, assuming that not all occurrences need to be followed by macro calls, S3 could be set to one to suppress the message.

Note that, if a warning marker is not followed by a macro name, it is treated as if it were not a construction name at all and is thus normally copied over to the value text. This applies irrespective of whether S3 is being used to suppress the error message.

The essential difference between warning mode and free mode is that in the first case all macro calls have to be specially marked by preceding them with warning markers, whereas in the second case all macro names that are not to be taken as macro calls have to be specially marked by enclosing them in skips.

Note that warning markers only apply to macro calls, and must not be used to precede inserts or skips. These latter are always recognised, irrespective of the mode of the scan.


Node:Stop markers, Previous:Warning markers, Up:Skips

2.7.5 Stop markers

Normally, if a delimiter of a macro call in the source text is accidentally omitted or wrongly specified, then the remainder of the source text might be scanned over in searching for the missing delimiter.

Thus, there is a construction called a stop marker. Stop markers are only recognised when searching for a delimiter of a construction in the source text. Outside of this context, stop markers are not part of the environment. If it encounters a stop marker, ML/I gives a message to signal that the current construction(s) are unmatched. The text from the construction name up to (but not including) the stop marker is ignored, and scanning is resumed at the stop marker itself. For example, if the source text read:

   MCDEF IF THEN NL
   AS <. . .>
   

and newline were then declared as a stop marker, and further source text included:

   IF X = Y THIN GO TO Z
   

then ML/I would take the final newline as a stop marker and would give the error message:

   Delimiter THEN of macro IF in line . . . not found
   

Stop markers obey the normal rules for name clashes, See Ambiguous use of names. Hence if, in the above example, THIN were replaced by THEN, then the final newline would be treated as a delimiter of IF rather than as a stop marker, and there would be no error message. An implication of this is that if the following definition were added to the above text:

   MCSKIP DT, COMMENT N1 OPT NL N1 OR ; ALL
   

then

   COMMENT XXX
   YYY
   ZZZ;
   

would not cause an error since all newlines would be treated as delimiters, not stop markers. In general, therefore, it is possible (though tortuous in all but the simplest cases) to define constructions that may be arbitrarily long even if stop markers have been defined.

Note that stop markers override the normal scope rules in that they are recognised within skips and within straight-scan macros. They are treated as local constructions.

Stop markers will stop forward searches for labels in the source text, as well as the scan for unmatched constructions.


Node:Environment summary, Next:, Previous:Skips, Up:Chapter 2

2.8 Summary of the environment

All the constituents of the environment have now been defined. To recap, these are:

  1. Macro definitions.
  2. Insert definitions.
  3. Skip definitions.
  4. Warning marker definitions.
  5. Stop marker definitions.
  6. Permanent variables.
  7. Character variables.
  8. System variables.
  9. Temporary variables.
  10. Arguments.
  11. Delimiters.
  12. Macro labels.
The term construction is used as a collective name for skips, inserts and macro names, and the term name environment is used as a collective name for constituents a), b), c), d) and e) above, since the names of these constituents are used to recognise constructions in the scanned text.


Node:Macro scanning, Next:, Previous:Environment summary, Up:Chapter 2

2.9 Normal-scan macros and straight-scan macros *

This Section explains the difference between normal-scan macros and straight-scan macros. However, straight-scan macros have only limited uses and the reader may choose to skip this Section and assume that all macros are normal-scan.

The difference between the two types of macro arises in the scanning of macro calls. In the case of a normal-scan macro, constructions nested within the call are recognised; in the case of a straight-scan macro, the effect is as if the name environment were temporarily removed during the scanning of the call. As an example of the use of a straight-scan macro, consider a language where comments are commenced with the word NOTE and ended with a semicolon. Assume it is desired to use ML/I to map this language into a language where comments are enclosed between the atoms [ and ]. It is not possible to achieve this transformation by the use of skips, since the options on skips do not permit the insertion of extra characters; moreover normal-scan macros are inadequate since it is not desired to recognise macro names within comments. Hence NOTE would be defined as a straight-scan macro. Its replacement text would be:

   [%WA1.]
   

The replacement text of a straight-scan macro is evaluated in exactly the same way as that of a normal-scan macro.

The reader will no doubt have noticed that there is an analogy between the two types of macro and the two types of skip. In fact, any straight skip can be represented as a straight-scan macro. However, straight skips are preferable, where possible, since they are slightly easier to define and much faster in execution. The analogy between normal-scan macros and matched skips is not so close. Normal-scan macros permit any constructions to be nested within calls of them, whereas matched skips only allow further skips to be nested within them.

The straight-scan option can only apply to user-defined macros; it cannot apply to inserts or to operation macros (see Operation macros).


Node:Example name environment, Previous:Macro scanning, Up:Chapter 2

2.10 Name environment used for examples

To avoid unnecessary repetition, a fixed name environment will be assumed in all subsequent examples. This environment consists of:

All the macros above are taken to be normal-scan.


Node:Chapter 3, Next:, Previous:Chapter 2, Up:Top

3 Text scanning and evaluation


Node:Nesting and recursion, Next:, Up:Chapter 3

3.1 Nesting and recursion

Constructions may be nested to any desired depth, and may appear within replacement text. Furthermore, recursive macro calls are allowed. In other words, any construction is allowed with any piece of replacement text or inserted text, and a macro may be called while evaluating its own replacement text. However, constructions must be properly nested. This means that each construction must lie entirely within a single piece of replacement text, entirely within a single piece of inserted text or entirely within the source text. Apart from this obvious restriction, ML/I contains no restrictions on nesting and recursion.

As a result of nesting and recursion, the process of text evaluation is normally a recursive one. At the beginning of a process, ML/I starts evaluating the source text. During this evaluation, it will in general encounter a macro call. This will cause it temporarily to suspend the evaluation of the source text and start evaluating the replacement text of the call. While evaluating this replacement text, ML/I may encounter an insert, and this will cause it to suspend the evaluation of the replacement text and start evaluating some inserted text. Alternatively, it may encounter a nested macro call. Thus at any one time several pieces of text may be in the process of evaluation.

This situation is liable to lead to ambiguities in terminology, so it is necessary to clarify some of the terms that will be used. The terms scanned text, current environment and current point of scan will always refer to the text actually being evaluated, not to any piece of text whose evaluation has been temporarily suspended. ML/I is said to be evaluating inserted text if the scanned text is inserted text, and a similar definition applies to evaluating replacement text. ML/I is said to be evaluating the source text if it is not within the evaluation of any macro calls or inserts.


Node:Call by name, Next:, Previous:Nesting and recursion, Up:Chapter 3

3.2 Call by name

Arguments and delimiters are evaluated each time they are inserted, rather than when the call in which they occur is scanned. In other words, they are `called by name' rather than `called by value'. In most cases, of course, this choice of approach makes no difference to the final result, but it does have an effect if the environment changes between the time an argument is scanned and the time it is inserted.


Node:Scanning process, Next:, Previous:Call by name, Up:Chapter 3

3.3 Details of the scanning process

When text is evaluated, it is scanned atom by atom until the end is reached. All text, whether the source text, replacement text or inserted text, is scanned and evaluated in the same way. In general, each atom of the scanned text is compared with all the names in the environment to see if a match can be found. However, as was seen in the previous Chapter, some types of name are not recognised under certain circumstances. The complete list of such circumstances is as follows:

  1. No names are recognised within a straight skip or a straight-scan macro call.
  2. Apart from skip names, no names are recognised within a matched skip.
  3. In warning mode, macro names are not recognised except after warning markers. Immediately after a warning marker, no names except macro names and no secondary delimiters are recognised unless an error occurs (see Illegal macro name).

When a construction name is found, a search is made for its closing delimiter. This process is described in The method of searching for delimiters.

Some names in the environment may consist of more than one atom. In this case, when an atom of the scanned text is found to match the first atom of the name, the scanning process looks ahead to see if the remaining atoms of the name follow this atom (this look-ahead is abandoned if the end of the current text is reached). If a match is found, scanning is resumed beyond the last atom of the name. The user can specify, for each pair of atoms of a multi-atom name, whether spaces between the atoms are to be ignored by the scan. Multi-atom secondary delimiters are matched in exactly the same way as multi-atom names.

Apart from these cases of multi-atom delimiters, the scan always proceeds atom by atom. Each atom not within a construction is copied over to the value text. Atoms within skips may or may not be copied according to the option settings. Atoms within macro calls or inserts are never copied over to the value text since the very purpose of these constructions is to perform a replacement.


Node:Searching for delimiters, Next:, Previous:Scanning process, Up:Chapter 3

3.4 The method of searching for delimiters

When ML/I encounters a construction name, it searches for each of the secondary delimiters until the closing delimiter is found (except in the case where the construction name is its own closing delimiter, when no searching is required). In general, an error message (see Unmatched construction) is given if the end of the current piece of text is reached before the closing delimiter has been found. In this case the construction is said to be unmatched. Exclusive delimiters, however, provide a slight exception to this rule (see Exclusive delimiters). If, during the search for the delimiters of a construction, a nested construction is encountered, then the search for the delimiters of the outer construction is suspended until the closing delimiter of the nested construction has been found. Nested constructions can only arise within inserts, matched skips and normal-scan macros. Since arguments are called by name rather than by value, nested constructions are not evaluated when scanned over during the search for delimiters of a containing construction. Evaluation occurs only when the argument containing the nested construction is inserted.

The process of searching for closing delimiters is illustrated by the following rather pathological example (remember that the name environment of Name environment used for examples, applies to this and all subsequent examples).

   DO 3 TIMES < REPEAT DO >
        ESUB REPEAT
        DO REPEAT TIMES
        REPEAT
   REPEAT
   

In this example the first DO is matched with the last REPEAT, since the search for the REPEAT for this first DO is suspended during the scanning of the nested constructions <, ESUB and DO. Furthermore, the occurrence of DO within the literal brackets is not recognised as a macro name.

In general, a single closing delimiter cannot terminate two separate constructions. Thus, two successive REPEATs are needed in the above example to close both the DO macros. However, exclusive delimiters again provide an exception to the rule.

As a further example, if the user were foolish enough to write:

   MOVE FROM TO TO PIG;
   

then the first TO would be taken as the delimiter of MOVE FROM. What should be written to make the second TO the delimiter is:

   MOVE FROM <TO> TO PIG;
   

However, there is nothing wrong with writing:

   MOVE FROM PIG TO TO;
   

In practice, if delimiter names are chosen sensibly, problems such as the above rarely arise.


Node:Exclusive delimiters, Next:, Previous:Searching for delimiters, Up:Chapter 3

3.5 Exclusive delimiters *

It is highly recommended that this Section be skipped on a first reading, as it describes a rather complicated feature which is only occasionally needed.

In the normal way, after a construction has been scanned over and replaced by its value, scanning is resumed with the atom following the closing delimiter of the construction. Hence the closing delimiter is taken as part of the construction. In a few cases, however, it is more convenient to regard the closing delimiter as external to the construction. Such a delimiter is called an exclusive delimiter. Only macros and skips may have exclusive delimiters, and exclusive delimiters are always closing delimiters. After a construction with an exclusive delimiter has been dealt with, scanning is resumed at the exclusive delimiter rather than beyond it.

Exclusive delimiters are useful when it is desired to use a single delimiter as a closing delimiter of several nested constructions. For example, an IF macro might have form:

   IF {condition} THEN {nested macro call} {NL}
   

where the nested macro call is terminated, like IF, by the closing newline. In this case, it would be necessary to define newline as an exclusive delimiter of any macro that could be nested within the IF macro. Then, when the scan had used the newline to close the nested macro call, it would re-scan it and use it again to close the IF macro.

A difficulty arises in the above example when, within the replacement text of IF, the second argument is inserted. The problem is that the nested macro call is unmatched within this argument, since its closing delimiter, the newline, lies beyond the end of the argument. ML/I resolves this problem by using the following rule; if, when inserting the Nth argument of a macro call, a construction is unmatched then the Nth delimiter is examined and if this delimiter (or a series of atoms at the start of it) is an exclusive delimiter which closes the apparently unmatched construction then this construction is considered as matched and processing proceeds normally. If there is a nest of unmatched constructions then this rule is successively applied to all the constructions in turn (in fact, this rule is such a natural one that the user might not realise that there is any logical problem at all).

Note that it is quite legal to insert an exclusive delimiter in the replacement text of the macro to which it belongs. It is even legal to define a name delimiter as an exclusive delimiter (though this is almost certain to lead to an endless loop). Furthermore it is quite legal to have both exclusive delimiters and ordinary closing delimiters within the same delimiter structure.

If a skip ends with an exclusive delimiter, this closing delimiter is not taken as part of the skip and hence it is not affected by the delimiter option associated with the skip.

Exclusive delimiters are sometimes useful in simple applications where no nesting is involved. For instance it is often desirable for a skip to delete up to, but not including, the next newline.

As a more complicated example, consider a language in which macro calls were one to a line with the macro name coming first. In this case it might be convenient to give newline a double use: firstly, as an exclusive delimiter of the macro on the previous line and secondly as a warning marker to precede the macro name on the next line. This is, however, a little tricky; it is usually easier to use the startline facility (see Startlines).

The way exclusive delimiters are defined is described at the end of Introduction to more complicated cases.


Node:Startlines, Next:, Previous:Exclusive delimiters, Up:Chapter 3

3.6 Startlines *

It is often useful, when processing text where a line is a logical entity (e.g. as in most assembly languages and some high-level languages), to define newline as a macro name. This causes subsidiary problems because

  1. The first and last line of the text need to be treated specially.
  2. As well as being a macro name, newline may also be a closing delimiter.

To remedy this, ML/I contains an option whereby an invisible layout character called startline may be inserted at the start of each line of input text. The option is controlled by the system variable S1: if S1 is one, startline characters are inserted; if S1 is not one, they are not. Initially S1 is zero. ML/I treats startline like any other layout character. Its layout keyword is SL.

Startlines are ignored in the output text from ML/I. However, they are not ignored in value text, and users are recommended to set S1 after their macros have been read in. One reason for this is illustrated by the following example:

   MCDEF TEST OPT ; OR NL ALL
   AS <MCGO L1 IF %WD1.=<
   >
   . . .
   

If S1 was one while this macro was being read in, then a startline would appear before the > character. In this case the test after the IF, which should test if delimiter one is a newline, would in fact test if delimiter one was a newline followed by a startline. The test would therefore always fail. If, as is very often the case, startline on its own is a construction name, the above recommendation is virtually imperative.

Example

The following macros would list all labelled statements in an assembly language program. It is assumed the assembler is such that statements are one to a line, and a line is taken to be labelled if the first character is not a space.
      MCSKIP SL WITH SPACE NL
      MCDEF SL NL
      AS<%WA1.
      >
      MCSET S1 = 1
      


Node:Dynamic constructions, Previous:Startlines, Up:Chapter 3

3.7 Dynamically generated constructions *

The method of scanning, with the requirement that calls be properly nested, means that all the delimiters of a construction must be in the same piece of text. This rule, which is very desirable since it leads to the early detection of genuine errors, should be borne in mind by the user who wishes to generate constructions dynamically, for example to combine at macro-time separate pieces of text to build up a macro call. The rule prohibits a construction like:

   CHOOSENAME A TO B;
   

where CHOOSENAME is a macro with replacement text MOVE FROM, since the call of MOVE FROM is not properly nested within the call of CHOOSENAME. It is similarly not correct to use the construction:

   DO A %A1. B REPEAT
   

where %A1. has value TIMES. It is however quite easy to achieve the object of these examples, namely to generate a delimiter dynamically, and the reader who is interested in doing this should refer to the example in Dynamically constructed calls.


Node:Chapter 4, Next:, Previous:Chapter 3, Up:Top

4 Operation macros and their use


Node:Operation macros, Next:, Up:Chapter 4

4.1 Operation macros

The macros considered so far have been strictly concerned with making replacements of pieces of text. In fact, strictly speaking, they should have been called substitution macros. There is a second type of macro called an operation macro. A call of an operation macro causes a predefined system action to take place, for example the setting up of a new construction. Operation macros are an integral part of ML/I and are not, like substitution macros, defined by the user. They are, however, part of the name environment and are called in the same way as substitution macros. Examples of operation macros are MCSET (which performs macro-time arithmetic), MCDEF (which defines a macro) and MCGO (which is a macro-time conditional `goto' statement). Examples of their calls are:

   MCSET P1 = P2+1
   MCDEF LNG AS Length
   MCGO L6 IF %A1. = ACC
   

Complete descriptions of all the operation macros may be found in Operation macros--specifications. The names of all operation macros begin with MC to minimise confusion with substitution macros (users are not forbidden to start their own macro names with MC, but it is probably less confusing not to do so). Note that the names of all operation macros, like all other constructions built into ML/I, are written in capital letters.

The arguments of all operation macros are evaluated before being processed. Thus, if tempno were a macro with replacement text P1, then the following would be equivalent to the previous example of MCSET:

   MCSET tempno = P2+1
   

In most cases, a call of an operation macro does not cause any value text to be generated. No value text would be generated, for instance, in any of the examples above. However, there are two operation macros, MCSUB and MCLENG, which do cause value text to be generated. These two macros are called system functions. MCSUB is used for generating substrings of longer pieces of text, and MCLENG is used to calculate the length of a piece of text.

There are no general restrictions on the use of operation macros. They may be called from within any type of text, even from within arguments to other operation macro calls.


Node:Literal brackets for arguments, Next:, Previous:Operation macros, Up:Chapter 4

4.2 Use of literal brackets for surrounding operation macro arguments

The fact that arguments of operation macros are evaluated before being processed has several advantages, but it also has its dangers, and in many cases the user will wish to inhibit this argument evaluation. Consider as an example the last argument of MCDEF, which specifies the replacement text of the macro being defined. A definition might be written:

   MCDEF . . . AS < . . . %A1. . . . >
   

If the above literal brackets (the characters < and >) had been omitted, ML/I would have tried to insert the value of argument one at the time the macro was defined (called definition time) rather than when the macro was called, and an error would probably result. Occasionally, however, a user might want to do this, in particular when one macro is defined within another and the arguments of the outer one figure in the definition. Apart from cases like this, it is a good plan to use literal brackets whenever specifying the replacement text of a macro.

Another reason for the usage of literal brackets arises when the replacement text involves one or more newlines, e.g.:

   MCDEF . . . AS <LINE 1
   LINE 2
   >
   

In this case, since newline is also the closing delimiter of MCDEF, the newlines within the replacement text need to be prevented from closing the MCDEF. The literal brackets, being a construction nested within the call of MCDEF, achieve this.

It is now possible to see why literal brackets must be defined as matched skips rather than straight skips. Consider the following example, where a piece of replacement text itself contains a call of MCDEF:

   MCDEF MAC1 AS < . . .
           MCDEF MAC2 AS < . . .
           . . . COMMENT > ;
   >
   

It is vital that the first < be matched with the last >, and not with the occurrence of > in a comment nor with its occurrence in the nested MCDEF. The definition of literal brackets as a matched skip accomplishes this.


Node:NEC macros, Next:, Previous:Literal brackets for arguments, Up:Chapter 4

4.3 NEC macros

Many of the operation macros have the effect of adding to or deleting from the name environment. These macros are called NEC (name environment changing) macros. The name environment is set up dynamically by calls of NEC macros during text evaluation. The initial state of the name environment is implementation-defined (see Section 2 of the relevant Appendix) but it will usually contain just the operation macros. Changes in the environment affect subsequent text evaluation, but have no effect on value text already generated. Constructions may be defined as either global or local. Global constructions apply to all subsequent text evaluation, whereas local constructions apply only to the text in which they are defined, together with any macros called from within this text (for exact details see Dynamic aspects of the environment). A local definition occurring in the source text usually has the same effect as a global definition, with the proviso that only the former will be affected by the MCNO... operation macros defined in MCNOWARN MCNOINS MCNOSKIP MCNODEF.

To start with, most users will probably not be very interested in defining new macros in the middle of text evaluation, In this case, the entire name environment can be set up by a series of NEC macro calls at the start of the source text, and all the rest of the text can be evaluated using this name environment. Local definition should be used in preference to global ones since the setting up of global definitions involves more work for ML/I (normally, global definitions are only necessary when it is desired to use one macro to set up the definition of another). Readers who are not interested in changing the name environment dynamically can skip Dynamic aspects of the environment, and Protected and unprotected inserts. They can, in fact, totally ignore global definitions, and they need not worry about the difference between protected and unprotected inserts.


Node:Dynamic aspects, Next:, Previous:NEC macros, Up:Chapter 4

4.4 Dynamic aspects of the environment *

The value of a piece of text depends on the state of the environment when its evaluation is started. The purpose of this Section is to define the initial state of the environment when replacement text or inserted text is evaluated, and to explain the effect of dynamic changes in the name environment.

It is convenient to divide the name environment into two parts:

If a substitution macro is called, or if an argument or delimiter is inserted, this cannot change the local name environment of the containing text. However, any change in the global name environment applies to the subsequent evaluation of the containing text. In other words, there is a single global name environment but each piece of text in the process of evaluation has its own particular local name environment.

When a substitution macro is called, the replacement text is evaluated under the following initial environment:

When an operation macro is called, no special environment is set up and no temporary variables are allocated. The arguments of the operation macro are evaluated under the environment in force when the call was scanned. The same applies to the argument of an insert.

Before considering the initial environment for the evaluation of inserted text, it is instructive to consider an example that will illustrate the reasons behind the rules. This example involves passing arguments down from one macro to another: Assume that within the replacement text of a macro XYZ it is desired to call the MOVE FROM macro to move the second argument of XYZ into a place called Temp. This call of MOVE FROM would be written:

   MOVE FROM %A2. TO Temp;
   

This call would cause the replacement text of the MOVE FROM macro to be evaluated, and during this evaluation it would be necessary to insert the first argument of MOVE FROM. In order to do so, the insert %A2. must be performed. Now, in this case ML/I takes A2 to mean the second argument of XYZ, not the second argument of MOVE FROM. The initial state of the environment for the evaluation of inserted text is set to make this so. This initial environment consists of:

  1. the current global name environment.
  2. a local name environment. This depends on whether the insert is protected or unprotected. See Protected and unprotected inserts.
  3. the permanent, character and system variables.
  4. the arguments and delimiters that were in the environment when the call containing the text to be inserted was encountered.
  5. the temporary variables that were in the environment when the call containing the text to be inserted was encountered.
  6. no macro labels.
The reader may have noticed that no initial environment contains any macro labels. This is because it is not possible to use the MCGO macro to jump from one piece of text to another. Thus each piece of text has its own macro labels, and macro labels are not carried down from one piece of text to another.


Node:Insert protection, Next:, Previous:Dynamic aspects, Up:Chapter 4

4.5 Protected and unprotected inserts *

The difference between protected and unprotected inserts is best illustrated by an example. Consider a macro ABC whose replacement text starts as follows:

   MCDEF Temp AS LMN
   %A1.
   

Assume ABC is called with Temp as its first argument. Then if % has been defined as a protected insert, the value of %A1. is Temp. If it has been defined as an unprotected insert, the value is LMN (note that MCDEF defines a local macro). If MCDEFG, which defines a global macro, has been used in place of MCDEF then the value of %A1. would always be LMN. Hence the purpose of a protected insert is to protect the insertion of a macro's arguments or delimiters from any changes in the local environment of the macro's replacement text. It is often useful, for instance, to switch into warning mode when entering the replacement text of a macro but still to evaluate its arguments in free mode. In some applications the user may wish to define two insert names, one protected and the other unprotected. In most applications, however, it will be entirely immaterial which sort of insert is defined.

To complete the definition of the previous Section, the initial local name environment when inserted text is evaluated is as follows:


Node:Ambiguous names, Next:, Previous:Insert protection, Up:Chapter 4

4.6 Ambiguous use of names *

When defining new constructions the user should be careful to avoid certain clashes of name. It would obviously be foolish, for instance, to choose the name MCDEF for a new construction. ML/I has a fixed set of priority rules for dealing with multiply-defined names, and these are listed below. However, for the reader who is not interested in these complications the following simple rule for defining new constructions is sufficient to avoid difficulty: choose the delimiters to be different from all other environmental names (i.e. the names of macros, inserts, skips, warning markers and stop markers in the current environment). It is quite acceptable, of course, to choose the same representation for the secondary delimiters of different constructions. For example, all macros could have a newline as their closing delimiter. Furthermore it is perfectly in order to have several different names all beginning with the same atom(s); for example three separate macros could have names RETURN, RETURN TO and RETURN IF. ML/I always tries to find the longest name it can, so in this example it would only call the RETURN macro if RETURN was not followed by TO or IF. The reader who is prepared to adopt the simple rule above can skip the rest of this Section.

A name clash is considered to occur if an atom or series of atoms of the scanned text can be interpreted in more than one way. Note that some environmental names are ignored within certain contexts (for a complete list, see The method of searching for delimiters); thus a name can sometimes be multiply-defined without a clash occurring. For example, in warning mode it is unambiguous to have a macro name the same as an insert name since each is recognised in a different context.

When a name clash does occur, the following rules are applied in order until all ambiguity is removed:

  1. Exclusive delimiters take precedence over everything else.
  2. A longer delimiter takes precedence over a shorter one (as illustrated by the above RETURN example).
  3. Secondary delimiters take precedence over environmental names.
  4. Local environmental names take precedence over global ones.
  5. The most recently defined environmental name takes precedence.


Node:Name clashes, Previous:Ambiguous names, Up:Chapter 4

4.7 Implications of rules for name clashes *

Some implications of the rules are:


Node:Chapter 5, Next:, Previous:Chapter 4, Up:Top

5 Specification of individual operation macros

This Chapter contains descriptions of the operation macros which should be present in every implementation. In addition, each implementation may have its own particular operation macros (see Section 1 of relevant Appendix).

Arguments of operation macr