Mostly documentation update but some code clarification too.
[pspp] / doc / flow-control.texi
index b396e1f3b183ba5e98fcea215f0e58c9e5c67fd2..20644747dbf4dc0d6f2db40b69f1e0c90c473470 100644 (file)
@@ -1,3 +1,13 @@
+@c PSPP - a program for statistical analysis.
+@c Copyright (C) 2017, 2020 Free Software Foundation, Inc.
+@c Permission is granted to copy, distribute and/or modify this document
+@c under the terms of the GNU Free Documentation License, Version 1.3
+@c or any later version published by the Free Software Foundation;
+@c with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+@c A copy of the license is included in the section entitled "GNU
+@c Free Documentation License".
+@c
+
 @node Conditionals and Looping
 @chapter Conditional and Looping Constructs
 @cindex conditionals
 @cindex flow of control
 @cindex control flow
 
-This chapter documents PSPP commands used for conditional execution,
+This chapter documents @pspp{} commands used for conditional execution,
 looping, and flow of control.
 
 @menu
 * BREAK::                       Exit a loop.
+* DEFINE::                      Define a macro.
 * DO IF::                       Conditionally execute a block of code.
 * DO REPEAT::                   Textually repeat a code block.
 * LOOP::                        Repeat a block of code.
@@ -29,6 +40,676 @@ BREAK.
 @cmd{BREAK} is allowed only inside @cmd{LOOP}@dots{}@cmd{END LOOP}.
 @xref{LOOP}, for more details.
 
+@node DEFINE
+@section DEFINE
+@vindex DEFINE
+@cindex macro
+
+@display
+DEFINE macro_name([argument[/argument]@dots{}])
+@dots{}body@dots{}
+!ENDDEFINE.
+
+Each argument takes the following form:
+  @{!arg_name =,!POSITIONAL@} [!DEFAULT(default)] [!NOEXPAND]
+  @{!TOKENS(count),!CHAREND('token'),!ENCLOSE('start','end'),!CMDEND@}
+
+The following directives may be used within the body:
+  !OFFEXPAND
+  !ONEXPAND
+
+The following functions may be used within the body:
+  !BLANKS(count)
+  !CONCAT(arg@dots{})
+  !EVAL(arg)
+  !HEAD(arg)
+  !INDEX(haystack, needle)
+  !LENGTH(arg)
+  !NULL
+  !QUOTE(arg)
+  !SUBSTR(arg, start[, count])
+  !TAIL(arg)
+  !UNQUOTE(arg)
+  !UPCASE(arg)
+
+The body may also include the following constructs:
+
+  !IF (condition) !THEN true-expansion !ENDIF
+  !IF (condition) !THEN true-expansion !ELSE false-expansion !ENDIF
+
+  !DO !var = start !TO end [!BY step]
+    body
+  !DOEND
+  !DO !var !IN (expression)
+    body
+  !DOEND
+@end display
+
+The DEFINE command defines a macro that can later be called any number
+of times within a syntax file.  Each time it is called, the macro's
+body is @dfn{expanded}, that is, substituted, as if the body had been
+written instead of the macro call.  A macro may accept arguments,
+whose values are specified at the point of invocation and expanded in
+the body where they are referenced.  Macro bodies may also use various
+directives and functions, which are also expanded when the macro is
+called.
+
+Many identifiers associated with macros begin with @samp{!}, a
+character not normally allowed in identifiers.  These identifiers are
+reserved only for use with macros, which helps keep them from being
+confused with other kinds of identifiers.
+
+@node Macro Basics
+@subsection Macro Basics
+
+The simplest macros have no arguments.  The following defines a macro
+named @code{!vars} that expands to the variable names @code{v1 v2 v3},
+along with a few example uses.  The macro's name begins with @samp{!},
+which is optional for macro names.  The @code{()} following the macro
+name are required:
+
+@example
+DEFINE !vars()
+v1 v2 v3
+!ENDDEFINE.
+
+DESCRIPTIVES !vars.
+FREQUENCIES /VARIABLES=!vars.
+@end example
+
+Macros can also expand to entire commands.  For example, the following
+example performs the same analyses as the last one:
+
+@example
+DEFINE !commands()
+DESCRIPTIVES v1 v2 v3.
+FREQUENCIES /VARIABLES=v1 v2 v3.
+!ENDDEFINE.
+
+!commands
+@end example
+
+The body of a macro can call another macro.  For example, we could
+combine the two preceding examples, with @code{!commands} calling
+@code{!vars} to obtain the variables to analyze.  The following shows
+one way that could work:
+
+@example
+DEFINE !commands()
+DESCRIPTIVES !vars.
+FREQUENCIES /VARIABLES=!vars.
+!ENDDEFINE.
+
+DEFINE !vars() v1 v2 v3 !ENDDEFINE.
+!commands
+
+* We can redefine the variables macro to analyze different variables:
+DEFINE !vars() v4 v5 !ENDDEFINE.
+!commands
+@end example
+
+The @code{!commands} macro would be easier to use if it took the
+variables to analyze as an argument rather than through another macro.
+The following section shows how to do that.
+
+@node Macro Arguments
+@subsection Macro Arguments
+
+Macros may take any number of arguments, which are specified within
+the parentheses in the DEFINE command.  Arguments come in two
+varieties based on how their values are specified when the macro is
+called:
+
+@itemize @bullet
+@item
+A @dfn{positional} argument has a required value that follows the
+macro's name.  Use the @code{!POSITIONAL} keyword to declare a
+positional argument.
+
+References to a positional argument in a macro body are numbered:
+@code{!1} is the first positional argument, @code{!2} the second, and
+so on.  In addition, @code{!*} expands to all of the positional
+argument values, separated by a space.
+
+The following example uses a positional argument:
+
+@example
+DEFINE !analyze(!POSITIONAL !CMDEND)
+DESCRIPTIVES !1.
+FREQUENCIES /VARIABLES=!1.
+!ENDDEFINE.
+
+!analyze v1 v2 v3.
+!analyze v4 v5.
+@end example
+
+@item
+A @dfn{keyword} argument has a name.  In the macro call, its value is
+specified with the syntax @code{@var{name}=@var{value}}.  Because of
+the names, keyword argument values may take any order in a macro call.
+If one is omitted, then a default value is used: either the value
+specified in @code{!DEFAULT(@var{value})}, or an empty value
+otherwise.
+
+In declaration and calls, a keyword argument's name may not begin with
+@samp{!}, but references to it in the macro body do start with a
+leading @samp{!}.
+
+The following example uses a keyword argument that defaults to ALL if
+the argument is not assigned a value:
+
+@example
+DEFINE !analyze_kw(vars=!DEFAULT(ALL) !CMDEND)
+DESCRIPTIVES !vars.
+FREQUENCIES /VARIABLES=!vars.
+!ENDDEFINE.
+
+!analyze_kw vars=v1 v2 v3.  /* Analyze specified variables.
+!analyze_kw.                /* Analyze all variables.  
+@end example
+@end itemize
+
+If a macro has both positional and keyword arguments, then the
+positional arguments must come first in the DEFINE command, and their
+values also come first in macro calls.
+
+Each argument declaration specifies the form of its value:
+
+@table @code
+@item !TOKENS(@var{count})
+Exactly @var{count} tokens, e.g.@: @code{!TOKENS(1)} for a single
+token.  Each identifier, number, quoted string, operator, or
+punctuator is a token.  @xref{Tokens}, for a complete definition.
+
+The following variant of @code{!analyze_kw} accepts only a single
+variable name (or @code{ALL}) as its argument:
+
+@example
+DEFINE !analyze_one_var(!POSITIONAL !TOKENS(1))
+DESCRIPTIVES !1.
+FREQUENCIES /VARIABLES=!1.
+!ENDDEFINE.
+
+!analyze_one_var v1.
+@end example
+
+@item !CHAREND('@var{token}')
+Any number of tokens up to @var{token}, which should be an operator or
+punctuator token such as @samp{/} or @samp{+}.  The @var{token} does
+not become part of the value.
+
+With the following variant of @code{!analyze_kw}, the variables must
+be following by @samp{/}:
+
+@example
+DEFINE !analyze_parens(vars=!CHARNED('/'))
+DESCRIPTIVES !vars.
+FREQUENCIES /VARIABLES=!vars.
+!ENDDEFINE.
+
+!analyze_parens vars=v1 v2 v3/.
+@end example
+
+@item !ENCLOSE('@var{start}','@var{end}')
+Any number of tokens enclosed between @var{start} and @var{end}, which
+should each be operator or punctuator tokens.  For example, use
+@code{!ENCLOSE('(',')')} for a value enclosed within parentheses.
+(Such a value could never have right parentheses inside it, even
+paired with left parentheses.)  The start and end tokens are not part
+of the value.
+
+With the following variant of @code{!analyze_kw}, the variables must
+be specified within parentheses:
+
+@example
+DEFINE !analyze_parens(vars=!ENCLOSE('(',')'))
+DESCRIPTIVES !vars.
+FREQUENCIES /VARIABLES=!vars.
+!ENDDEFINE.
+
+!analyze_parens vars=(v1 v2 v3).
+@end example
+
+@item !CMDEND
+Any number of tokens up to the end of the command.  This should be
+used only for the last positional parameter, since it consumes all of
+the tokens in the command calling the macro.
+
+The following variant of @code{!analyze_kw} takes all the variable
+names up to the end of the command as its argument:
+
+@example
+DEFINE !analyze_kw(vars=!CMDEND)
+DESCRIPTIVES !vars.
+FREQUENCIES /VARIABLES=!vars.
+!ENDDEFINE.
+
+!analyze_kw vars=v1 v2 v3.
+@end example
+@end table
+
+By default, when an argument's value contains a macro call, the call
+is expanded each time the argument appears in the macro's body.  The
+@code{!NOEXPAND} keyword in an argument declaration suppresses this
+expansion.  @xref{Controlling Macro Expansion}, for details.
+
+@node Controlling Macro Expansion
+@subsection Controlling Macro Expansion
+
+Multiple factors control whether macro calls are expanded in different
+situations.  At the highest level, @code{SET MEXPAND} controls whether
+macro calls are expanded.  By default, it is enabled.  @xref{SET
+MEXPAND}, for details.
+
+A macro body may contain macro calls.  By default, these are expanded.
+If a macro body contains @code{!OFFEXPAND} or @code{!ONEXPAND}
+directives, then @code{!OFFEXPAND} disables expansion of macro calls
+until the following @code{!ONEXPAND}.
+
+A macro argument's value may contain a macro call.  By default, these
+macro calls are expanded.  If the argument was declared with the
+@code{!NOEXPAND} keyword, they are not expanded.
+
+The argument to a macro function is a special context that does not
+expand macro calls.  For example, if @code{!vars} is the name of a
+macro, then @code{!LENGTH(!vars)} expands to 5, as does
+@code{!LENGTH(!1)} if positional argument 1 has value @code{!vars}.
+In these cases, use the @code{!EVAL} macro function to expand macros,
+e.g.@: @code{!LENGTH(!EVAL(!vars))} or @code{!LENGTH(!EVAL(!1))}.
+@xref{Macro Functions}, for details.
+
+These rules apply to macro calls.  Uses of macro functions and macro
+arguments within a macro body are always expanded.
+
+@node Macro Functions
+@subsection Macro Functions
+
+Macro bodies may manipulate syntax using macro functions.  Macro
+functions accept tokens as arguments and expand to sequences of
+characters.
+
+The arguments to macro functions have a restricted form.  They may
+only be a single token (such as an identifier or a string), a macro
+argument, or a call to a macro function.  Thus, @code{x}, @code{5.0},
+@code{x}, @code{!1}, @code{"5 + 6"}, and @code{!CONCAT(x,y)} are valid
+macro arguments, but @code{x y} and @code{5 + 6} are not.
+
+Macro functions expand to sequences of characters.  When these
+character strings are processed further as character strings, e.g.@:
+with @code{!LENGTH}, any character string is valid.  When they are
+interpreted as PSPP syntax, e.g.@: when the expansion becomes part of
+a command, they need to be valid for that purpose.  For example,
+@code{!UNQUOTE("It's")} will yield an error if the expansion
+@code{It's} becomes part of a PSPP command, because it contains
+unbalanced single quotes, but @code{!LENGTH(!UNQUOTE("It's"))} expands
+to 4.
+
+The following macro functions are available.  Each function's
+documentation includes examples in the form @code{@var{call}
+@expansion{} @var{expansion}}.
+
+@deffn {Macro Function} !BLANKS (count)
+Expands to @var{count} unquoted spaces, where @var{count} is a
+nonnegative integer.  Outside quotes, any positive number of spaces
+are equivalent; for a quoted string of spaces, use
+@code{!QUOTE(!BLANKS(@var{count}))}.
+
+In the examples below, @samp{_} stands in for a space to make the
+results visible.
+
+@c Keep these examples in sync with the test for !BLANKS in
+@c tests/language/control/define.at:
+@example
+!BLANKS(0)                  @expansion{} @r{empty}
+!BLANKS(1)                  @expansion{} _
+!BLANKS(2)                  @expansion{} __
+!QUOTE(!BLANKS(5))          @expansion{} '_____'
+@end example
+@end deffn
+
+@deffn {Macro Function} !CONCAT (arg@dots{})
+Expands to the concatenation of all of the arguments.  Before
+concatenation, each quoted string argument is unquoted, as if
+@code{!UNQUOTE} were applied.  This allows for ``token pasting'',
+combining two (or more) tokens into a single one:
+
+@c Keep these examples in sync with the test for !CONCAT in
+@c tests/language/control/define.at:
+@example
+!CONCAT(x, y)                @expansion{} xy
+!CONCAT('x', 'y')            @expansion{} xy
+!CONCAT(12, 34)              @expansion{} 1234
+!CONCAT(!NULL, 123)          @expansion{} 123
+@end example
+
+@code{!CONCAT} is often used for constructing a series of similar
+variable names from a prefix followed by a number and perhaps a
+suffix.  For example:
+
+@c Keep these examples in sync with the test for !CONCAT in
+@c tests/language/control/define.at:
+@example
+!CONCAT(x, 0)                @expansion{} x0
+!CONCAT(x, 0, y)             @expansion{} x0y
+@end example
+
+An identifier token must begin with a letter (or @samp{#} or
+@samp{@@}), which means that attempting to use a number as the first
+part of an identifier will produce a pair of distinct tokens rather
+than a single one.  For example:
+
+@c Keep these examples in sync with the test for !CONCAT in
+@c tests/language/control/define.at:
+@example
+!CONCAT(0, x)                @expansion{} 0 x
+!CONCAT(0, x, y)             @expansion{} 0 xy
+@end example
+@end deffn
+
+@deffn {Macro Function} !EVAL (arg)
+Expands macro calls in @var{arg}.  This is especially useful if
+@var{arg} is the name of a macro or a macro argument that expands to
+one, because arguments to macro functions are not expanded by default.
+
+The following examples assume that @code{!vars} is a macro that
+expands to @code{a b c}:
+
+@example
+!vars                        @expansion{} a b c
+!QUOTE(!vars)                @expansion{} '!vars'
+!EVAL(!vars)                 @expansion{} a b c
+!QUOTE(!EVAL(!vars))         @expansion{} 'a b c'
+@end example
+
+These examples additionally assume that argument @code{!1} has value
+@code{!vars}:
+
+@example
+!1                           @expansion{} a b c
+!QUOTE(!1)                   @expansion{} '!vars'
+!EVAL(!1)                    @expansion{} a b c
+!QUOTE(!EVAL(!1))            @expansion{} 'a b c'
+@end example
+@end deffn
+
+@deffn {Macro Function} !HEAD (arg)
+@deffnx {Macro Function} !TAIL (arg)
+@code{!HEAD} expands to just the first token in an unquoted version of
+@var{arg}, and @code{!TAIL} to all the tokens after the first.
+
+@example
+!HEAD('a b c')               @expansion{} a
+!HEAD('a')                   @expansion{} a
+!HEAD(!NULL)                 @expansion{} @r{empty}
+!HEAD('')                    @expansion{} @r{empty}
+
+!TAIL('a b c')               @expansion{} b c
+!TAIL('a')                   @expansion{} @r{empty}
+!TAIL(!NULL)                 @expansion{} @r{empty}
+!TAIL('')                    @expansion{} @r{empty}
+@end example
+@end deffn
+
+@deffn {Macro Function} !INDEX (haystack, needle)
+Looks for @var{needle} in @var{haystack}.  If it is present, expands
+to the 1-based index of its first occurrence; if not, expands to 0.
+
+@example
+!INDEX(banana, an)           @expansion{} 2
+!INDEX(banana, nan)          @expansion{} 3
+!INDEX(banana, apple)        @expansion{} 0
+!INDEX("banana", nan)        @expansion{} 4
+!INDEX("banana", "nan")      @expansion{} 0
+!INDEX(!UNQUOTE("banana"), !UNQUOTE("nan")) @expansion{} 3
+@end example
+@end deffn
+
+@deffn {Macro Function} !LENGTH (arg)
+Expands to a number token representing the number of characters in
+@var{arg}.
+
+@example
+!LENGTH(123)                 @expansion{} 3
+!LENGTH(123.00)              @expansion{} 6
+!LENGTH( 123 )               @expansion{} 3
+!LENGTH("123")               @expansion{} 5
+!LENGTH(xyzzy)               @expansion{} 5
+!LENGTH("xyzzy")             @expansion{} 7
+!LENGTH("xy""zzy")           @expansion{} 9
+!LENGTH(!UNQUOTE("xyzzy"))   @expansion{} 5
+!LENGTH(!UNQUOTE("xy""zzy")) @expansion{} 6
+!LENGTH(!1)                  @expansion{} 5 @r{if @t{!1} is @t{a b c}}
+!LENGTH(!1)                  @expansion{} 0 @r{if @t{!1} is empty}
+!LENGTH(!NULL)               @expansion{} 0
+@end example
+@end deffn
+
+@deffn {Macro Function} !NULL
+Expands to an empty character sequence.
+
+@example
+!NULL                        @expansion{} @r{empty}
+!QUOTE(!NULL)                @expansion{} ''
+@end example
+@end deffn
+
+@deffn {Macro Function} !QUOTE (arg)
+@deffnx {Macro Function} !UNQUOTE (arg)
+The @code{!QUOTE} function expands to its argument surrounded by
+apostrophes, doubling any apostrophes inside the argument to make sure
+that it is valid PSPP syntax for a string.  If the argument was
+already a quoted string, @code{!QUOTE} expands to it unchanged.
+
+Given a quoted string argument, the @code{!UNQUOTED} function expands
+to the string's contents, with the quotes removed and any doubled
+quote marks reduced to singletons.  If the argument was not a quoted
+string, @code{!UNQUOTE} expands to the argument unchanged.
+
+@example
+!QUOTE(123.0)                @expansion{} '123.0'
+!QUOTE( 123 )                @expansion{} '123'
+!QUOTE('a b c')              @expansion{} 'a b c'
+!QUOTE("a b c")              @expansion{} "a b c"
+!QUOTE(!1)                   @expansion{} 'a ''b'' c' @r{if @t{!1} is @t{a 'b' c}}
+
+!UNQUOTE(123.0)              @expansion{} 123.0
+!UNQUOTE( 123 )              @expansion{} 123
+!UNQUOTE('a b c')            @expansion{} a b c
+!UNQUOTE("a b c")            @expansion{} a b c
+!UNQUOTE(!1)                 @expansion{} a 'b' c @r{if @t{!1} is @t{a 'b' c}}
+
+!QUOTE(!UNQUOTE(123.0))      @expansion{} '123.0'
+!QUOTE(!UNQUOTE( 123 ))      @expansion{} '123'
+!QUOTE(!UNQUOTE('a b c'))    @expansion{} 'a b c'
+!QUOTE(!UNQUOTE("a b c"))    @expansion{} 'a b c'
+!QUOTE(!UNQUOTE(!1))         @expansion{} 'a ''b'' c' @r{if @t{!1} is @t{a 'b' c}}
+@end example
+@end deffn
+
+@deffn {Macro Function} !SUBSTR (arg, start[, count])
+Expands to a substring of @var{arg} starting from 1-based position
+@var{start}.  If @var{count} is given, it limits the number of
+characters in the expansion; if it is omitted, then the expansion
+extends to the end of @var{arg}.
+
+@example
+!SUBSTR(banana, 3)           @expansion{} nana
+!SUBSTR(banana, 3, 3)        @expansion{} nan
+!SUBSTR("banana", 3)         @expansion{} @r{error (@code{anana"} is not a valid token)}
+!SUBSTR(!UNQUOTE("banana"), 3) @expansion{} nana
+!SUBSTR("banana", 3, 3)      @expansion{} ana
+
+!SUBSTR(banana, 3, 0)        @expansion{} @r{empty}
+!SUBSTR(banana, 3, 10)       @expansion{} nana
+!SUBSTR(banana, 10, 3)       @expansion{} @r{empty}
+@end example
+@end deffn
+
+@deffn {Macro Function} !UPCASE (arg)
+Expands to an unquoted version of @var{arg} with all letters converted
+to uppercase.
+
+@example
+!UPCASE(freckle)             @expansion{} FRECKLE
+!UPCASE('freckle')           @expansion{} FRECKLE
+!UPCASE('a b c')             @expansion{} A B C
+!UPCASE('A B C')             @expansion{} A B C
+@end example
+@end deffn
+
+@node Macro Expressions
+@subsection Macro Expressions
+
+Macro expressions are used in conditional expansion and loops, which
+are described in the following sections.  A macro expression may use
+the following operators, listed in descending order of operator
+precedence:
+
+@table @code
+@item ()
+Parentheses override the default operator precedence.
+
+@item !EQ !NE !GT !LT !GE !LE = ~= <> > < >= <=
+Relational operators compare their operands and yield a Boolean
+result, either @samp{0} for false or @samp{1} for true.
+
+These operators always compare their operands as strings.  This can be
+surprising when the strings are numbers because, e.g.,@: @code{1 <
+1.0} and @code{10 < 2} both evaluate to @samp{1} (true).
+
+Comparisons are case sensitive, so that @code{a = A} evaluates to
+@samp{0} (false).
+
+@item !NOT ~
+@itemx !AND &
+@itemx !OR |
+Logical operators interpret their operands as Boolean values, where
+quoted or unquoted @samp{0} is false and anything else is true, and
+yield a Boolean result, either @samp{0} for false or @samp{1} for
+true.
+@end table
+
+Macro expressions do not include any arithmetic operators.
+
+An operand in an expression may be a single token (including a macro
+argument name) or a macro function invocation.  Either way, the
+expression evaluator unquotes the operand, so that @code{1 = '1'} is
+true.
+
+@node Macro Conditional Expansion
+@subsection Macro Conditional Expansion
+
+The @code{!IF} construct may be used inside a macro body to allow for
+conditional expansion.  It takes the following forms:
+
+@example
+!IF (@var{expression}) !THEN @var{true-expansion} !IFEND
+!IF (@var{expression}) !THEN @var{true-expansion} !ELSE @var{false-expansion} !IFEND
+@end example
+
+When @var{expression} evaluates to true, the macro processor expands
+@var{true-expansion}; otherwise, it expands @var{false-expansion}, if
+it is present.  The macro processor considers quoted or unquoted
+@samp{0} to be false, and anything else to be true.
+
+@node Macro Loops
+@subsection Macro Loops
+
+The body of a macro may include two forms of loops: loops over
+numerical ranges and loops over tokens.  Both forms expand a @dfn{loop
+body} multiple times, each time setting a named @dfn{loop variable} to
+a different value.  The loop body typically expands the loop variable
+at least once.
+
+@subsubheading Loops Over Ranges
+
+@example
+!DO @var{!var} = @var{start} !TO @var{end} [!BY @var{step}]
+  @var{body}
+!DOEND
+@end example
+
+A loop over a numerical range has the form shown above.  @var{start},
+@var{end}, and @var{step} (if included) must be expressions with
+numeric values.  The macro processor accepts both integers and real
+numbers.  The macro processor expands @var{body} for each numeric
+value from @var{start} to @var{end}, inclusive.
+
+The default value for @var{step} is 1.  If @var{step} is positive and
+@math{@var{first} > @var{last}}, or if @var{step} is negative and
+@math{@var{first} < @var{last}}, then the macro processor doesn't
+expand the body at all.  @var{step} may not be zero.
+
+@subsubheading Loops Over Tokens
+
+@example
+!DO @var{!var} !IN (@var{expression})
+  @var{body}
+!DOEND
+@end example
+
+A loop over tokens takes the form shown above.  The macro processor
+evaluates @var{expression} and expands @var{body} once per token in
+the result, substituting the token for @var{!var} each time it
+appears.
+
+@node Macro Variable Assignment
+@subsection Macro Variable Assignment
+
+The @code{!LET} construct evaluates an expression and assigns the
+result to a macro variable.  It may create a new macro variable or
+change the value of one created by a previous @code{!LET} or
+@code{!DO}, but it may not change the value of a macro argument.
+@code{!LET} has the following form:
+
+@example
+!LET @var{!var} = @var{expression}
+@end example
+
+If @var{expression} is more than one token, it must be enclosed in
+parentheses.
+
+@node Macro Settings
+@subsection Macro Settings
+
+Some macro behavior is controlled through the SET command
+(@pxref{SET}).  This section describes these settings.
+
+Any SET command that changes these settings within a macro body only
+takes effect following the macro.  This is because PSPP expands a
+macro's entire body at once, so that the SET command inside the body
+only executes afterwards.
+
+The MEXPAND setting (@pxref{SET MEXPAND}) controls whether macros will
+be expanded at all.  By default, macro expansion is on.  To avoid
+expansion of macros called within a macro body, use @code{!OFFEXPAND}
+and @code{!ONEXPAND} (@pxref{Controlling Macro Expansion}).
+
+When MPRINT (@pxref{SET MPRINT}) is turned on, PSPP logs an expansion
+of each macro in the input.  This feature can be useful for debugging
+macro definitions.
+
+MNEST (@pxref{SET MNEST}) limits the depth of expansion of macro
+calls, that is, the nesting level of macro expansion.  The default is
+50.  This is mainly useful to avoid infinite expansion in the case of
+a macro that calls itself.
+
+MITERATE
+
+PRESERVE...RESTORE
+
+SET MEXPAND, etc. doesn't work inside macro bodies.
+
+@node Macro Notes
+@subsection Extra Notes
+
+@code{!*} expands to all the positional arguments.
+
+Macros in comments.
+
+Macros in titles.
+
+Define ``unquote.''
 @node DO IF
 @section DO IF
 @vindex DO IF
@@ -107,49 +788,54 @@ strings, comments, unquoted strings (such as the text on the
 @cmd{TITLE} or @cmd{DOCUMENT} command), or inside @cmd{BEGIN
 DATA}@dots{}@cmd{END DATA}.
 
+Substitution occurs only on whole words, so that, for example, a dummy
+variable PRINT would not be substituted into the word PRINTOUT.
+
 New variable names used as replacements are not automatically created
 as variables, but only if used in the code block in a context that
-would create them, e.g.@: on a @cmd{NUMERIC} or @cmd{STRING} command
+would create them, @i{e.g.}@: on a @cmd{NUMERIC} or @cmd{STRING} command
 or on the left side of a @cmd{COMPUTE} assignment.
 
-Any command may appear within DO REPEAT, including nested DO REPEAT
-commands.  If @cmd{INCLUDE} or @cmd{INSERT} appears within DO REPEAT,
+Any command may appear within @subcmd{DO REPEAT}, including nested @subcmd{DO REPEAT}
+commands.  If @cmd{INCLUDE} or @cmd{INSERT} appears within @subcmd{DO REPEAT},
 the substitutions do not apply to the included file.
 
-If PRINT is specified on @cmd{END REPEAT}, the commands after substitutions
-are made are printed to the listing file, prefixed by a plus sign
-(@samp{+}).
+If @subcmd{PRINT} is specified on @cmd{END REPEAT}, the commands after
+substitutions are made should be printed to the listing file, prefixed
+by a plus sign (@samp{+}).  This feature is not yet implemented.
 
 @node LOOP
 @section LOOP
 @vindex LOOP
 
 @display
-LOOP [index_var=start TO end [BY incr]] [IF condition].
+LOOP [@var{index_var}=@var{start} TO @var{end} [BY @var{incr}]] [IF @var{condition}].
         @dots{}
-END LOOP [IF condition].
+END LOOP [IF @var{condition}].
 @end display
 
 @cmd{LOOP} iterates a group of commands.  A number of
 termination options are offered.
 
 Specify index_var to make that variable count from one value to
-another by a particular increment.  index_var must be a pre-existing
-numeric variable.  start, end, and incr are numeric expressions
-(@pxref{Expressions}.)  
-
-During the first iteration, index_var is set to the value of start.
-During each successive iteration, index_var is increased by the value of
-incr.  If end > start, then the loop terminates when index_var > end;
-otherwise it terminates when index_var < end.  If incr is not specified
+another by a particular increment.  @var{index_var} must be a pre-existing
+numeric variable.  @var{start}, @var{end}, and @var{incr} are numeric expressions
+(@pxref{Expressions}.)
+
+During the first iteration, @var{index_var} is set to the value of @var{start}.
+During each successive iteration, @var{index_var} is increased by the value of
+@var{incr}.  If @var{end} > @var{start}, then the loop terminates
+when @var{index_var} > @var{end};
+otherwise it terminates when @var{index_var} < @var{end}.  If @var{incr} is not specified
 then it defaults to +1 or -1 as appropriate.
 
-If end > start and incr < 0, or if end < start and incr > 0, then the
-loop is never executed.  index_var is nevertheless set to the value of
+If @var{end} > @var{start} and @var{incr} < 0, or if @var{end} < @var{start} and
+ @var{incr} > 0, then the
+loop is never executed.  @var{index_var} is nevertheless set to the value of
 start.
 
-Modifying index_var within the loop is allowed, but it has no effect on
-the value of index_var in the next iteration.
+Modifying @var{index_var} within the loop is allowed, but it has no effect on
+the value of @var{index_var} in the next iteration.
 
 Specify a boolean expression for the condition on @cmd{LOOP} to
 cause the loop to be executed only if the condition is true.  If the
@@ -167,9 +853,11 @@ code block is executed.  The condition is evaluated at the end of the
 loop, not at the beginning, so that the body of a loop with only a
 condition on @cmd{END LOOP} will always execute at least once.
 
-If neither the index clause nor either condition clause is
-present, then the loop is executed MXLOOPS (@pxref{SET}) times.
-The default MXLOOPS is 40.
+If the index clause is not
+present, then the loop is executed at most @var{max_loops} (@pxref{SET}) times
+(but possibly fewer, if a condition clause evaluates to false or if
+@cmd{BREAK} executes).
+The default value of @var{max_loops} is 40.
 
 @cmd{BREAK} also terminates @cmd{LOOP} execution (@pxref{BREAK}).