Mostly documentation update but some code clarification too.
[pspp] / doc / flow-control.texi
index f0bf4fe10b77400ed999dd56672f9c1b84f93460..20644747dbf4dc0d6f2db40b69f1e0c90c473470 100644 (file)
@@ -71,6 +71,18 @@ The following functions may be used within the body:
   !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
@@ -87,15 +99,6 @@ 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.
 
-@menu
-* Macro Basics::
-* Macro Arguments::
-* Controlling Macro Expansion::
-* Macro Functions::
-* Macro Settings::
-* Macro Notes::
-@end menu
-
 @node Macro Basics
 @subsection Macro Basics
 
@@ -165,7 +168,8 @@ 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.
+so on.  In addition, @code{!*} expands to all of the positional
+argument values, separated by a space.
 
 The following example uses a positional argument:
 
@@ -205,15 +209,6 @@ FREQUENCIES /VARIABLES=!vars.
 @end example
 @end itemize
 
-@example
-DEFINE !analyze_kw(vars=!CMDEND)
-DESCRIPTIVES !vars.
-FREQUENCIES /VARIABLES=!vars.
-!ENDDEFINE.
-
-!analyze_kw vars=v1 v2 v3.
-@end example
-
 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.
@@ -243,6 +238,18 @@ 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
@@ -267,12 +274,24 @@ FREQUENCIES /VARIABLES=!vars.
 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.
+expansion.  @xref{Controlling Macro Expansion}, for details.
 
 @node Controlling Macro Expansion
 @subsection Controlling Macro Expansion
@@ -351,7 +370,8 @@ results visible.
 @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.
+@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:
@@ -361,6 +381,29 @@ concatenation, each quoted string argument is unquoted, as if
 !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)
@@ -514,6 +557,118 @@ to uppercase.
 @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
 
@@ -535,7 +690,9 @@ 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.
+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
 
@@ -552,6 +709,7 @@ Macros in comments.
 
 Macros in titles.
 
+Define ``unquote.''
 @node DO IF
 @section DO IF
 @vindex DO IF