aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-04-19 07:11:43 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-04-19 07:11:43 -0700
commite59acb76cb274b4fae81f89a5954693c9bd641a8 (patch)
tree6aaa3d389d584d5a25fd9d5640a89197002c1a9d
parent50ca46f1abdd6b8f5a80e1931d92967a4a6de0a1 (diff)
downloadcppawk-e59acb76cb274b4fae81f89a5954693c9bd641a8.tar.gz
cppawk-e59acb76cb274b4fae81f89a5954693c9bd641a8.tar.bz2
cppawk-e59acb76cb274b4fae81f89a5954693c9bd641a8.zip
New man page: cppawk-iter.
-rw-r--r--cppawk-iter.11554
1 files changed, 1554 insertions, 0 deletions
diff --git a/cppawk-iter.1 b/cppawk-iter.1
new file mode 100644
index 0000000..6618a90
--- /dev/null
+++ b/cppawk-iter.1
@@ -0,0 +1,1554 @@
+.\" cppawk: C preprocessor wrapper around awk
+.\" Copyright 2022 Kaz Kylheku <kaz@kylheku.com>
+.\"
+.\" BSD-2 License
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright notice,
+.\" this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright notice,
+.\" this list of conditions and the following disclaimer in the documentation
+.\" and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.de bk
+.IP " "
+.PP
+..
+.TH CPPAWK-ITER 1 "18 April 2022" "cppawk Libraries" "Iteration"
+
+.SH NAME
+iter \- powerful, user-extensible iteration language for Awk
+
+.SH SYNOPSIS
+
+.ft B
+ #include <iter.h>
+
+ \fI// Simple, single-variable iteration\fP
+
+ doarray (\fIkey\fP, \fIvalue\fP, \fIarr\fP) \fI// iterate over Awk assoc array\fP
+ \fIstatement\fP
+
+ dostring (\fIidx\fP, \fIchr\fP, \fIstr\fP) \fI// iterate over string\fP
+ \fIstatement\fP
+
+ dofields (\fIidx\fP, \fIval\fP) \fI// iterate over $1, $2, ..\fP
+ \fIstatement\fP
+
+ \fI// Multi-clause parallel and nested iteration\fP
+
+ loop (\fIclause1\fP, \fIclause2\fP, ...) \fI// Parallel iteration\fP
+ \fIstatement\fP
+
+ loop_nest (\fIclause1\fP, \fI// Nested iteration\fP
+ \fIclause2\fP,
+ parallel (\fIclause3\fP,
+ \fIclause4\fP, ...),
+ ...)
+ \fIstatement\fP
+
+ \fI// Clauses for loop/loop_iter\fP
+
+ \fI// numeric stepping clauses\fP
+ range (\fIidx\fP, \fIfrom\fP, \fIto\fP)
+ range_step (\fIidx\fP, \fIfrom\fP, \fIto\fP, \fIstep\fP)
+ from (\fIidx\fP, \fIfrom\fP)
+ from_step (\fIidx\fP, \fIfrom\fP, \fIstep\fP)
+
+ \fI// general stepping clause\fP
+ first_then (\fIvar\fP, \fIfirst\fP, \fIthen\fP)
+
+ \fI// container traversal\fP
+ str (\fIidx\fP, \fIch\fP, \fIstr\fP)
+ list (\fIiter\fP, \fIvar\fP, \fIlist\fP)
+ fields (\fIvar\fP)
+ keys (\fIkey\fP, \fIarray\fP)
+
+ \fI// collect items into lists\fP
+ collect (\fIvar\fP, \fIexpr\fP)
+ collect_plus (\fIvar\fP, \fIexpr\fP)
+
+ \fI// calculating clauses\fP
+ summing (\fIvar\fP, \fIexpr\fP)
+ maximizing (\fIvar\fP, \fIexpr\fP)
+ minimizing (\fIvar\fP, \fIexpr\fP)
+ argmax (\fImaxvar\fP, \fIargvar\fP, \fIexpr\fP)
+ argmin (\fIminvar\fP, \fIargvar\fP, \fIexpr\fP)
+
+ \fI// termination control clauses\fP
+ while (\fIexpr\fP)
+ until (\fIexpr\fP)
+
+ \fI// parallel grouping combinator\fP
+ \fI// clause1, clause2, ... are parallel even in a loop_nest.\fP
+ parallel (\fIclause1\fP, \fIclause2\fP, ...)
+
+ \fI// conditional combinator:\fP
+ \fI// dependent clause steps/tests only whenever test is true\fP
+ if (\fItest\fP, \fIclause\fP)
+
+.ft R
+
+.SH OVERVIEW
+.bk
+The
+.B <iter.h>
+header provides constructs for expressing iteration. For simple loops that
+occur often \(em iterating over an array, string or the positional
+fields \(em several dedicated constructs are provided:
+.BR doarray ,
+.B dostring
+and
+.BR dofields .
+The separate
+.B <cons.h>
+header also provides simple iteration, for lists.
+
+In addition,
+.B <iter.h>
+provides a powerful general iteration facility which allows multiple
+variables to be iterated in parallel or nested loops, stepping over
+various kinds of spaces, with special clauses for calculation,
+collecting lists, or controlling termination.
+
+Furthermore, a new clauses may easily be defined by the application
+programmer, simply by defining six macros according to easy-to-follow
+rules.
+
+Clauses are susceptible to macro expansion: new clauses can be defined
+by writing macros that expand to existing clauses.
+
+In all of the iteration constructs of
+.B <iter.h>
+the variables which are supplied by the application are subject to assignment;
+the constructs do not bind these variables. It is up to the application to
+control the scope of these variables.
+
+In general, immediately after the termination of these looping constructs,
+the variables explicitly specified by the application code remain visible,
+and continue to hold the values they had immediately prior to loop termination.
+
+.SH SIMPLE ITERATION
+.bk
+.SS Macro \fIdoarray\fP
+.bk
+.B Syntax:
+
+.ft B
+ doarray (\fIkey\fP, \fIvalue\fP, \fIarr\fP)
+ \fIstatement\fP
+.ft R
+
+.B Description:
+
+The
+.B doarray
+macro executes the
+.I statement
+for every element of the associative array
+.IR arr .
+Prior to each iteration, the variables
+.I key
+and
+.I value
+are set to the next key and value to be visited.
+
+Awk associative arrays are not required to maintain order; thus
+.B doarray
+does not traverse
+.I arr
+in any required order.
+
+.B Example:
+
+.ft B
+ \fI// assuming a is prepared like this:\fP
+ split("a:b:c", \fIa\fP, /:/)
+
+ \fI// possible output is\fP
+ \fI// 3 c\fP
+ \fI// 1 a\fP
+ \fI// 2 b\fP
+ doarray (\fIk\fP, \fIv\fP, \fIa\fP)
+ print \fIk\fP, \fIv\fP
+.ft R
+
+.SS Macro \fIdostring\fP
+.bk
+.B Syntax:
+
+.ft B
+ dostring (\fIidx\fP, \fIchr\fP, \fIstr\fP)
+ \fIstatement\fP
+.ft R
+
+.B Description:
+
+The
+.B dostring
+macro evaluates
+.I statement
+for all successive substrings of length 1 of string
+.IR str .
+The variable
+.I idx
+steps from 1 up to the length of
+.IR str ,
+and the
+.I chr
+variable takes on string values of length 1. On the first iteration,
+.I chr
+contains the first character of
+.IR str ,
+then on the second iteration the second character and so forth.
+
+The
+.I str
+expression is evaluated only once.
+
+.B Example:
+
+.ft B
+ \fI// output is:\fP
+ \fI// 1 a\fP
+ \fI// 2 b\fP
+ \fI// 3 c\fP
+ dostring (\fIi\fP, \fIch\fP, "abc")
+ print \fIi\fP, \fIch\fP
+.ft R
+
+.SS Macro \fIdofields\fP
+.bk
+.B Syntax:
+
+.ft B
+ dofields (\fIidx\fP, \fIval\fP)
+ \fIstatement\fP
+.ft R
+
+.B Description:
+
+The
+.B dofields
+macro iterates over the Awk positional fields, executing
+.I statement
+for each iteration. The
+.I idx
+variable is initialized to 1. Before every iteration,
+.I idx
+is compared compared to the current value of
+.BR NR .
+The iteration proceeds if
+.I i
+.B <=
+.B NR
+is true. After the execution of
+.IR statement ,
+.I idx
+is incremented by one.
+
+Before each iteration,
+.I val
+is set to the value of the positional field indicated by
+.IR idx ,
+namely \fB$\fP\fIidx\fP.
+
+.B Example:
+
+.ft B
+ \fI// set fields, assuming default FS\fP
+ $0 = "the quick brown fox"
+
+ \fI// output is:\fP
+ \fI// 1 the\fP
+ \fI// 2 quick\fP
+ \fI// 3 brown\fP
+ \fI// 4 fox\fP
+ dofields (i, v)
+ print \fIi\fP, \fIv\fP
+.ft P
+
+.SH THE LOOP MACRO
+.bk
+.SH Macro \fIloop\fP
+.bk
+.B Syntax:
+
+.ft B
+ loop (\fIclause1\fP, \fIclause2\fP, ...)
+ \fIstatement\fP
+.ft R
+
+.B Description:
+The
+.B loop
+macro repeatedly executes
+.I statement
+under the control of one or more clauses:
+.IR clause1 ,
+.iR clause2 ,
+...
+
+Each clause contributes to the initial loop conditions, termination
+testing, and actions of the loop. Under
+.B loop
+the clauses act in parallel. The same clauses may be combined into
+a nested loop using the
+.B loop_nest
+macro. The term
+.I parallel
+here doesn't refer to concurrent processing with threads or processors,
+but to the lock-step performance of loop iteration steps.
+
+Each clause communicates to
+.B loop the following:
+.IP initialization
+What variable are to be be prepared with what initial values.
+.IP termination
+What conditions will terminate the loop. Prior to each iteration,
+the termination test from every clause is interrogated. The loop
+.I statement
+executes only if all clauses indicate continued execution. If at least
+one clause calls for termination, the loop ends.
+.IP preparation
+Whenever all clauses indicate that the loop continues, each clause
+has the opportunity to make some preparation prior to the execution of
+the loop, such as calculating the values of some variables.
+.IP stepping
+After the execution of each statement, each clause has the opportunity
+to perform some increment step.
+.IP finalization
+When the loop terminates, some clauses execute some special code to
+bring about a needed final state in their variables, or for some
+other reason.
+.PP
+
+The Awk
+.B break
+and
+.B continue
+statements are usable inside
+.B loop
+and behave like they do inside the
+.B for
+construct. The
+.B break
+statement terminates the loop, and
+.B continue
+terminates the
+.I statement
+only, proceeding to the increment step which prepares for the next
+iteration.
+
+.B Example:
+
+.ft B
+ \fI// step variable i from 1 to 5 by 1,\fB
+ \fI// and variable j from 100 to 500 in steps of 100.\fB
+
+ \fI// output is:\fB
+ \fI// 1 100\fB
+ \fI// 2 200\fB
+ \fI// 3 300\fB
+ \fI// 4 400\fB
+ \fI// 5 500\fB
+
+ loop (range (\fIi\fB, 1, 5),
+ range_step (\fIj\fB, 100, 500, 100))
+ {
+ print \fIi\fB, \fIj\fB
+ }
+.ft R
+
+More example are given in the documentation of the clauses.
+
+.SH Macro \fIloop_nest\fP
+.bk
+.B Syntax:
+
+.ft B
+ loop_nest (\fIclause1\fP, \fIclause2\fP, ...)
+ \fIstatement\fP
+.ft R
+
+.B Description:
+The
+.B loop_nest
+macro has a syntax resembling that of
+.BR loop .
+Unlike
+.BR loop ,
+it generates a nested loop: the logic of the clauses is arranged
+into loop nestings. Each clause controls its own loop, in which
+the loops of subsequent clauses are nested. In effect, the
+.B loop_nest
+syntax is a shorthand for writing:
+
+.ft B
+ loop (\fIclause1\fP)
+ loop (\fIclause2\fP)
+ loop (\fIclause3\fP)
+ ...
+ loop (\fIclauseN\fP)
+ \fIstatement\fP
+.ft R
+
+There is a special clause called
+.B parallel
+which is useful inside a
+.BR loop_nest .
+Detailed documentation for it is given in its own section. The
+.B parallel
+clause combines multiple clauses into a single clause, in such a way
+that those clauses are executed in parallel regardless of which loop
+macro is used. Therefore the following equivalence also holds:
+
+Note: consistently with the semantics of
+.B loop_nest
+being that of the above shorthand, the
+.B break
+and
+.B continue
+statements affect only the innermost loop corresponding to the last clause,
+.IR clauseN .
+The
+.B break
+statement only breaks out of that loop, and
+.B continue
+only skips to the iteration part of that loop.
+
+Note: the semantics of all clauses such as termination control clauses and list
+collection clauses must also be understood in terms of the nesting.
+For instance if a collect clause is nested inside another loop which
+repeats three times, then that collection will be repeated three times:
+the collection variable will be initialized three times, collection
+will be performed three times. Only the items collected by the last of
+the three repetitions of the collect loop will be retained. Or, if instead
+of collect, maximize is used to calculate a maximum value, then three
+maxima will be calculated over the three invocations of the maximizing
+loop, only the effect of the last of which will be retained in the
+variable which receives the maximum value.
+
+.ft B
+ loop (\fIclause1\fP, \fIclause2\fP, ..., \fIclause\fP)
+ \fIstatement\fP
+.ft R
+
+may be achieved using
+
+.ft B
+ loop_nest (parallel (\fIclause1\fP, \fIclause2\fP, ..., \fIclauseN\fP))
+ \fIstatement\fP
+.ft R
+
+.B Example:
+
+.ft B
+ #include <iter.h>
+ #include <cons.h>
+
+ BEGIN {
+ loop_nest (list(it, let, list("a", "b", "c")),
+ range(x, 1, 3))
+ print let "-" x
+ }
+
+ Output:
+
+ a-1
+ a-2
+ a-3
+ b-1
+ b-2
+ b-3
+ c-1
+ c-2
+ c-3
+.ft R
+
+.SH LOOP CLAUSES: NUMERIC AND GENERAL STEPPING
+.bk
+.SS Loop clauses \fIrange\fP and \fIrange_step\fP
+.bk
+.B Syntax:
+
+.ft B
+ range (\fIidx\fP, \fIfrom\fP, \fIto\fP)
+ range_step (\fIidx\fP, \fIfrom\fP, \fIto\fP, \fIstep\fP)
+.ft R
+
+.B Description:
+
+The
+.B range
+loop clause initializes the
+.I idx
+variable to the value of the
+.I from
+expression. Prior to each loop iteration, the expression
+.BI idx " <= (to)
+is tested. If it is false, the loop terminates.
+After each execution of
+.IR statement ,
+.I idx
+is incremented by 1.
+The
+.I to
+expression is reevaluated at the beginning of each iteration,
+so its value may change.
+
+The
+.B range_step
+clause is a variation of
+.B range
+which allows the amount added to
+.I idx
+to be specified as the
+.I step
+expression. The
+.I step
+expression is evaluated after each iteration, so its
+value may change. That value is added to
+.I idx .
+
+Note:
+.B loop
+clauses may not have optional arguments; it is not possible
+to write a single loop clause which takes an optional step
+size that defaults to 1.
+
+.SS Loop clauses \fIfrom\fP and \fIfrom_step\fP
+.bk
+.B Syntax:
+
+.ft B
+ from (\fIidx\fP, \fIfrom\fP)
+ from_step (\fIidx\fP, \fIfrom\fP, \fIstep\fP)
+.ft R
+
+.B Description:
+
+The
+.B from
+clause is similar to
+.BI range ,
+except that the
+.I to
+expression is missing. The clause performs no termination test;
+it initializes
+.I idx
+to the
+.I from
+value and then executes indefinitely, forever incrementing
+.B idx
+by one. In order for the loop to terminate, another clause must
+be present which requests termination, or else
+.B break
+must be used to terminate the loop abruptly.
+
+The
+.B from_step
+clause is a variant of
+.B from
+which allows the amount added to
+.I idx
+at the increment step to be determined by the value of the
+.I step
+expression, which is reevaluated each time.
+
+.SH LOOP CLAUSES: CONTAINER TRAVERSAL
+.bk
+.SS Loop clause \fIstr\fP
+.bk
+.B Syntax:
+
+.ft B
+ str (\fIidx\fP, \fIch\fP, \fIstr\fP)
+.ft P
+
+.B Description:
+
+The
+.B str
+loop clause iterates over a string. The
+.I str
+expression is evaluated once to produce a string. The
+.I idx
+variable steps from 1 to up to the length of the string.
+If the string is empty, the loop terminates without
+any iterations taking place.
+Prior to each iteration, the
+.I ch
+variable is set to a one-character-long substring of the
+string starting at the
+.I idx
+position.
+
+.SS Loop clause \fIlist\fP
+.bk
+.B Syntax:
+
+.ft B
+ list (\fIiter\fP, \fIvar\fP, \fIlist\fP)
+.ft R
+
+.B Description:
+
+The
+.B list
+loop clause iterates over the elements of a list.
+Note:
+the inclusion of the
+.B <iter.h>
+header does not make visible list manipulation libraries such as
+.BR <cons.h> ,
+
+The
+.I iter
+variable is initialized to
+.IR list .
+Prior to each iteration,
+.I iter
+is tested for termination as if using the
+.B endp
+function. If
+.I iter
+refers to a nonempty list, and thus iteration may continue, then
+.I var
+is set to the first item in
+.IR iter ,
+.BI car( iter ) \fR,\fP
+prior to the execution of the loop
+.IR statement .
+
+After each iteration,
+.B iter
+is replaced with
+.BI cdr( iter ) \fR.\fP
+
+.SS Loop clause \fIfields\fP
+.bk
+.B Syntax:
+
+.ft B
+ fields (\fIvar\fP)
+.ft R
+
+.B Description:
+
+The
+.B fields
+loop clause iterates over the Awk positional fields. An internal
+counter is initialized to 1. Iteration proceeds if this counter is
+less than or equal to the current value of
+.BR NF .
+The counter is incremented by 1 after each iteration.
+
+Prior to the execution of the loop
+.IR statement ,
+.I var
+is set to the field indicated by the internal counter.
+
+.SS Loop clause \fIkeys\fP
+.bk
+.B Syntax:
+
+.ft B
+ keys (\fIkey\fP, \fIarray\fP)
+.ft R
+
+.B Description:
+
+The
+.B keys
+loop clause iterates over the keys (indices) of an Awk associative
+array named by the
+.I array
+parameter. The
+.I key
+variable is set to each index in turn. The keys are not visited in
+any specific, required order.
+
+.SH LOOP CLAUSES: COLLECTION INTO LISTS
+.bk
+.SS Loop clauses \fIcollect\fP and \fIcollect_plus\fP
+.bk
+.B Syntax:
+
+.ft B
+ collect (\fIvar\fP, \fIexpr\fP)
+ collect_plus (\fIvar\fP, \fIexpr\fP)
+.ft R
+
+.B Description:
+
+The
+.B collect
+clause initializes
+.I var
+to an empty bag object as if by using the
+.B list_init
+macro from
+.BR <cons.h> .
+The clause provides no termination test; if the only clauses in a
+.B loop
+are
+.B collect
+clauses, then it will not terminate. Prior each execution of the
+.IR statement ,
+the
+.B collect
+clause evaluates
+.I expr
+and replaces
+.B var
+with a new bag which contains that value, as if by the expression
+.IB var " = list_add(" var ", " expr ) \fR.\fP
+When the loop terminates,
+.I var
+is replaced with a list formed from the bag which it used to hold,
+as if by
+.IB var " = list_end(" var ) \fR.\fP
+The effect is that
+.I var
+ends up with a list of the values of
+.I expr
+that were sampled before each iteration of the loop.
+
+The
+.B collect_plus
+clause is almost exactly the same as
+.B collect
+except in regard to the final behavior. When the loop terminates,
+.B collect_plus
+collects the value of
+.I expr
+one more time prior to the conversion to list.
+The effect is that
+.I var
+ends up with a list of all the values of
+.I expr
+that were sampled before each iteration of the loop, as well
+as one more sample of
+.I expr
+taken after loop termination.
+
+.SH LOOP CLAUSES: CALCULATION
+.bk
+.SS Loop clause \fIsumming\fP
+.bk
+.B Syntax:
+
+.ft B
+ summing (\fIvar\fP, \fIexpr\fP)
+.ft R
+
+.B Description:
+
+The
+.B summing
+clause calculates the sum of the values of
+.I expr
+over the course of the loop.
+The clause contains no provision for termination; if the only
+clause in a
+.B loop
+is
+.B summing
+then it will not terminate.
+
+The
+.B summing
+clause initializes
+.B var
+to zero. Prior to each execution of the loop's
+.IR statement ,
+.I expr
+is evaluated and its value added to to
+.IR var .
+
+The effect is that after the loop terminates,
+.I var
+ends up with the sum of the samples of the value of
+.I expr
+from before each iteration of the loop.
+
+.SS Loop clauses \fIminimizing\fP and \fImaximizing\fP
+.bk
+.B Syntax:
+
+.ft B
+ maximizing (\fIvar\fP, \fIexpr\fP)
+ minimizing (\fIvar\fP, \fIexpr\fP)
+.ft R
+
+.B Description:
+
+The
+.B minimizing
+and
+.B maximizing
+clauses initialize
+.I var
+to the value
+.IR nil .
+(See the
+.B cppawk-cons
+manual page for
+.BR <cons.h> ).
+
+Prior to each execution of the loop
+.IR statement ,
+.I var
+is updated as follows.
+If
+.I var
+is
+.BR nil ,
+then it receives the value of
+.IR expr ,
+thereby establishing that value as the hitherto calculated minimum or
+maximum. If
+.I var
+is not already
+.BR nil ,
+then
+.B minimize
+updates it with the value of
+.I expr
+if that value is smaller than
+.IR var ,
+and similarly,
+.B maximize
+replaces
+.I var
+with the value of
+.I expr
+if that value is greater than
+.IR var .
+
+Neither
+.B minimize
+nor
+.B maximize
+bring about loop termination.
+
+The effect of these clauses it to calculate the minimum or
+maximum observed of value of
+.I expr
+as sampled before each execution of the loop statement.
+If the loop never executes the
+.IR statement ,
+then
+.I var
+retains the
+.B nil
+value indicating that no minimum or maximum had been found.
+
+.SS Loop clauses \fIargmax\fP and \fIargmin\fP
+.bk
+.B Syntax:
+
+.ft B
+ argmax (\fImaxvar\fP, \fIargvar\fP, \fIexpr\fP)
+ argmin (\fIminvar\fP, \fIargvar\fP, \fIexpr\fP)
+.ft R
+
+.B Description:
+
+The
+.B argmax
+and
+.B argmin
+clauses calculate the value of a variable
+.I argvar
+which maximize or minimizes the value of
+.IR expr .
+
+This maximum or minimum value appears in
+.I maxvar
+or
+.IR minvar
+respectively.
+
+The purpose of the
+.I argvar
+argument is to name the variable that is being maximized
+or minimized. It is expected that the
+.I expr
+expression contains
+.I argvar
+and thus its value is dependent on
+.IR argvar .
+
+Like
+.B minimize
+and
+.BR maximize ,
+these clauses never bring about loop termination.
+
+First,
+.I minvar
+or
+.I maxvar
+is initialized to the
+.B nil
+value.
+(See the
+.B cppawk-cons
+manual page for
+.BR <cons.h> ).
+
+If the loop
+.I statement
+never executes, then these variables retain the
+.B nil
+value to indicate that no argument maximum or minimum was calculated.
+
+Prior to each execution of
+.IR statement ,
+.I expr
+is evaluated. If it is the first iteration, then
+.I maxvar
+or
+.I minvar
+is set to the value of
+.IR argvar .
+If it is the second or subsequent iteration, then
+.B argmax
+sets
+.I maxvar
+to the value of
+.I argvar
+if
+.I expr
+is higher than the previously seen maximum value of
+.IR expr .
+Likewise,
+.B argmin
+sets
+.I minvar
+to the value of
+.I argvar
+if
+.I expr
+is lower than the previously seen minimum value of
+.IR expr .
+
+.B Example:
+
+Find the values of
+.I x
+where the expression
+.BI sin( x ") * cos(" x )
+has a maximum and minimum value, over the
+.I x
+range 0 to 3.14159 examined in
+increments of 0.001.
+
+Note that the variable used as
+.IR argvar ,
+namely
+.I x
+is made to vary by the use of a
+.I range_step
+clause. For
+.B argmax
+and
+.B argmin
+to be useful, the argument variable has to vary from one iteration
+to the next, and the
+.I expr
+has to be a function of that variable.
+
+.ft B
+ #include <iter.h>
+
+ BEGIN {
+ loop (range_step (\fIx\fP, 0, 3.14159, 0.001),
+ argmax (\fImx\fP, \fIx\fP, sin(\fIx\fP) * cos(\fIx\fP)),
+ argmin (\fImi\fP, \fIx\fP, sin(\fIx\fP) * cos(\fIx\fP)))
+ ; // empty
+
+ print "max x =", \fImx\fP
+ print "min x =", \fImi\fP
+ }
+.ft R
+
+Output:
+
+.ft B
+ max x = 0.785
+ min x = 2.356
+.ft R
+
+.SH LOOP CLAUSES: TERMINATION CONTROL
+.bk
+.SS Loop clauses \fIwhile\fP and \fIuntil\fP
+.bk
+.B Syntax:
+
+.ft B
+ while (\fIexpr\fP)
+ until (\fIexpr\fP)
+.ft R
+
+.B Description:
+
+The
+.B while
+and
+.B until
+clauses provide a termination test to the loop.
+
+Prior to each iteration,
+.I expr
+is evaluated.
+
+Under the
+.B while
+clause, if
+.I expr
+is false. the loop terminates.
+
+Under the
+.B until
+clause, if
+.I expr
+is true, the loop terminates.
+
+Loop terminations are short circuited among parallel clauses.
+So that is to say, if an earlier clause indicates loop
+termination, then the termination tests of later clauses are not performed.
+Moreover, the preparation actions of
+.B no
+clause are performed when the loop terminates; only if it has
+been confirmed that the
+.I statement
+is going to be executed, due to the termination tests from all
+clauses reporting false, are the preparation actions executed.
+Therefore, in any iteration, later termination tests can rely on earlier
+termination tests having executed. For instance, if the success of an earlier
+termination test implies that a certain variable is safe to use in certain way,
+then a later termination test may use it in that way. Likewise, loop
+preparations may rely on all termination tests having executed.
+
+All tests in loop, including
+.B while
+and
+.B until
+are top-of-loop tests: tests carried out before every iteration,
+including the first. A bottom-of-loop test is one which is carried out after
+each iteration, which is logically equivalent to a top-of-loop test which is
+unconditionally true before the first iteration, and then turns into a
+.I "bona fide"
+test. A bottom-of-loop testing version of
+.B while
+or
+.B until
+isn't provided in
+.B <iter.h>
+but can be developed as an application-defined clause. It may also
+be simulated with the help of the first_then clause, according
+to this pattern:
+
+.ft B
+ loop_for (first_then (\fIfirst_iter\fP, 1, 0),
+ while (\fIfirst_iter\fP || \fIother_condition\fP))
+ statement
+.ft R
+
+Here, the
+.B first_iter
+flag is initialized to 1, and then after the first iteration steps to 0.
+Therefore the
+.B while
+clause's test is always true before the first iteration, and
+.I other_condition
+isn't tested.
+
+.SH LOOP CLAUSES: COMBINATORS
+.bk
+.SS Loop clause \fIparallel\fP
+.bk
+.B Syntax:
+
+.ft B
+ parallel (\fIclause1\fP, \fIclause2\fP, ...)
+.ft R
+
+.B Description:
+
+The
+.B parallel
+construct may be used in the
+.B loop_nest
+macro, to indicate groups of clauses that should not be nested
+but treated in parallel.
+
+The
+.B parallel
+clause takes one or more arguments which are loop clauses.
+It arranges for the argument clauses to be performed
+in parallel, just like the way clauses are treated by the
+.B loop
+construct.
+
+For instance, the structure:
+
+.ft B
+ loop_nest (\fIclause1\fP,
+ parallel (\fIclause2\fP, \fIclause3\fP),
+ \fIclause4\fP)
+ \fIstatement\fP
+.ft R
+
+may be understood as equivalent to:
+
+.ft B
+ loop (\fIclause1\fP)
+ loop (\fIclause2\fP, \fIclause3\fP)
+ loop (\fIclause4\fP)
+ \fIstatement\fP
+.ft R
+
+.S Loop clause \fIif\fP
+.bk
+.B Syntax:
+
+.ft B
+ if (\fItest\fP, \fIclause\fP)
+.ft R
+
+.B Description:
+
+The
+.B if
+clause activates or deactivates the contained
+.I clause
+based on the value of the
+.I test
+expression.
+
+Firstly, the initializations of
+.I clause
+are performed unconditionally, as if it were not embedded in
+.BR if .
+
+Prior to every iteration, if the
+.I test
+expression is false, then
+.IR clause 's
+tests are not performed, and are assumed to be true. Thus while
+.I test
+is true,
+.I clause
+is prevented from being able to terminate the loop.
+
+Secondly, prior to the execution of the loop
+.IR statement ,
+.I test
+is evaluated again. If the expression is false, then the
+preparation actions of
+.I clause
+are skipped.
+
+Lastly, prior to the execution of the iteration step actions.
+expression is false, then the step actions of
+.I clause
+are skipped.
+
+Effectively, the
+.I clause
+is suspended while the
+.I test
+expression is false.
+
+.B Example:
+
+Print a row number before the first element of every row. While
+this specific program can be coded much more succinctly, the goal
+is to demonstrate how the
+.B first_then
+clause is activated by the the condition
+.IB i " % 10 =="
+.BR 1 .
+
+.ft B
+ #include <iter.h>
+
+ function row(\fIpg\fP)
+ {
+ if (\fIpg\fP > 1)
+ print
+ printf "r%03d", \fIpg\fP
+ return \fIpg\fP
+ }
+
+ BEGIN {
+ loop (range(\fIi\fP, 1, 100),
+ if (\fIi\fP % 10 == 1, first_then(\fIpg\fP, row(1), row(\fIpg\fP + 1))))
+ printf " %3d", \fIi\fP
+ }
+.ft R
+
+.B Output:
+
+.ft B
+ r001 1 2 3 4 5 6 7 8 9 10
+ r002 11 12 13 14 15 16 17 18 19 20
+ r003 21 22 23 24 25 26 27 28 29 30
+ r004 31 32 33 34 35 36 37 38 39 40
+ r005 41 42 43 44 45 46 47 48 49 50
+ r006 51 52 53 54 55 56 57 58 59 60
+ r007 61 62 63 64 65 66 67 68 69 70
+ r008 71 72 73 74 75 76 77 78 79 80
+ r009 81 82 83 84 85 86 87 88 89 90
+ r010 91 92 93 94 95 96 97 98 99 100
+.ft R
+
+.SH USER-DEFINED CLAUSES
+.bk
+It is possible to define new clauses for the
+.B loop
+macro, in application code.
+
+.SS Definition via Macro
+
+One method by which a user defined
+.B loop
+clause is possible is by writing it as a macro.
+This is because clauses look like macro invocations
+and are susceptible to expansion.
+
+.B Example:
+
+Introduce a
+.BI repeat( n )
+clause that repeats
+.I n
+times, where
+.I n
+is an expression.
+
+.ft B
+ #define repeat(n) range(repeat_counter_ ## __LINE__, 1, (n))
+.ft R
+
+.SS Primary Definition
+
+An entirely new loop clause is developed by writing six macros,
+one of which is required only if the
+.I egawk
+(Enhanced GNU Awk) implementation of Awk is being used.
+The macros have names which are derived from the name of the clause.
+
+For example, to implement a clause called
+.BR myclause ,
+the following macros must be written:
+.BR __temp_myclause ,
+.BR __init_myclause ,
+.BR __test_myclause ,
+.BR __prep_myclause ,
+.B __fini_myclause
+and
+.BR __step_myclause .
+The
+.BR __temp_myclause
+macro is not used unless the Awk implementation is
+.I egawk .
+
+All six macros must accept exactly the same arguments, and those
+will be the arguments that the clause will accept. They are described
+next:
+
+.IP \fB__temp_\fP
+The
+.I temp
+macro must expand to a comma-terminated list of temporary variable names which
+are needed by the clause. If the clause needs no hidden temporary variables,
+then this must expand to a terminating comma. Under the
+.I egawk
+implementation, these variables will be accumulated into a
+.B @let
+construct which precedes the loop, so that they are introduced as lexical
+variables visible only inside the loop.
+
+.IP \fB__init_\fP
+The
+.I init
+macro must expand to an expression which performs variable initializations.
+If the clause requires no initializations, its expansion must be the
+numeric token
+.BR 1 .
+
+.IP \fB__test_\fP
+The
+.I test
+macro must expand to an expression whose value is true if, and only if, the
+clause wishes the loop to terminate. If the clause does not terminate the
+loop, the expansion of this macro must be the numeric token
+.BR 1 .
+
+.IP \fB__prep_\fP
+The
+.I prep
+macro must expand to an expression that the clause needs to evaluate
+prior to the execution of the loop's iteration statement. This is evaluated
+only if all clauses have indicated that the loop isn't terminating,
+and hence the statement is going to be executed.
+
+.IP \fB__fini_\fP
+The
+.I fini
+macro must expand to an expression that the clause needs to evaluate
+in the situation when the loop terminates. If any termination test from
+any clause of a
+.B loop
+indicates that the loop must terminate, then the loop
+.I statement
+will not be executed any more; instead, the
+.I fini
+expressions of all the clauses will be evaluated, and then the loop
+ends. If a clause does not have any
+.I fini
+action, then this macro must expand to the token
+.BR 1 .
+
+.IP \fB__step_\fP
+The
+.I step
+macro must expand to an expression which is evaluated after every
+execution of the loop
+.I statement ,
+in order to prepare new values of loop variables for the next iteration.
+Here is where numeric step variables are incremented and so forth.
+If the clause doesn't step, then this must expand to
+.BR 1 .
+
+.SS Example: \fBnull\fP clause
+
+Suppose we wish to define a clause called
+.B null
+which takes no arguments and does nothing. A loop which contains
+only this clause iterates forever. If the clause is added to any
+.BR loop ,
+the semantics remains unchanged. The entire implementation is
+this:
+
+.ft B
+ #include <iter.h>
+
+ #define __temp_null ,
+ #define __init_null 1
+ #define __test_null 1
+ #define __prep_null 1
+ #define __fini_null 1
+ #define __step_null 1
+
+ BEGIN {
+ loop (range (i, 1, 5),
+ null) // does nothing
+ print i
+ }
+.ft R
+
+.SS Example: alpha-numeric stepping.
+.bk
+Suppose we have a function
+.BI nxstr( s ", " u )
+which behaves as follows, on these example inputs:
+
+.ft B
+ nxstr("000", "999") -> "001"
+ nxstr("007", "777") -> "010"
+ nxstr("abc", "zzz") -> "abd"
+ nxstr("xxx", "yyy") -> "xxy"
+ nxstr("xxy", "yyy") -> "xya"
+ nxstr("yyx", "yyy") -> "yyy"
+ nxstr("yyy", "yyy") -> 0
+.ft R
+
+The function
+.BI nxstr
+implements a relation that could could be called "alpha-numeric step",
+where the second argument indicates limiting characters.
+
+A precise specification follows.
+Firstly, both
+.I s
+and
+.I u
+are alphanumeric strings of equal length, consisting of nothing but
+digits or the 26 letters of the English alphabet, in either upper or lower
+case. Furthermore, for every character in
+.IR s ,
+the corresponding character in
+.I u
+is in the same category: digit, lower case or upper case, and
+that corresponding character has a rank at least as high.
+For instance, where
+.I s
+has the character
+.B p ,
+.I u
+may have the characters
+.BR p ,
+.BR q ,
+.BR r ...
+but not
+.B o
+because
+.B o
+has a lower rank, and not
+.B X
+or
+.B 7
+because they are in a different category.
+
+The
+.I u
+argument gives an upper limit. If
+.I s
+is identical to
+.I u
+then
+.B nxstr
+returns 0. Otherwise
+.B nxstr
+returns the next alphanumeric string derived from
+.I s
+as follows: if the last character is equal to the corresponding one in
+.I s
+then it is reset to the leading element of the category, otherwise
+it is replaced by its successor. In the case when the character is reset, the
+procedure is repeated with the character to the left, to increment the next
+digit. If that one is reset, then again, to the left and so forth.
+
+We would like to implement a loop clause which steps a variable
+.I s
+through a range of strings, as in
+.BI alpha_range( s ", \(dqaa0\(dq, \(dqcc9\(dq" )
+to step through the strings "aa0", "aa1", ... "aa9", "ab0", ... "ab9", ... "cc0", ... "cc9".
+
+.ft B
+ #include <iter.h>
+
+ \fI// ... implementation of nxstr goes here ...\fP
+
+ #define __temp_alpha_range(\fIs\fP, \fIfrom\fP, \fIto\fP) 1
+ #define __init_alpha_range(\fIs\fP, \fIfrom\fP, \fIto\fP) \fIs\fP = \fIfrom\fP
+ #define __test_alpha_range(\fIs\fP, \fIfrom\fP, \fIto\fP) \fIs\fP
+ #define __prep_alpha_range(\fIs\fP, \fIfrom\fP, \fIto\fP) 1
+ #define __fini_alpha_range(\fIs\fP, \fIfrom\fP, \fIto\fP) 1
+ #define __step_alpha_range(\fIs\fP, \fIfrom\fP, \fIto\fP) \fIs\fP = nxstr(\fIs\fP, \fIto\fP)
+
+ BEGIN {
+ loop (alpha_range (\fIx\fP, "aa0", "cc9"))
+ print \fIx\fP
+ }
+.ft R
+
+A working implementation of
+.B nxstr
+follows:
+
+.ft B
+ // "register nextchar"
+ function rn(x, y,
+ c)
+ {
+ nextchar[x] = y
+ if (y in nextchar) {
+ resetchar[x] = y
+ for (c = y; nextchar[c] != y; c = nextchar[c])
+ resetchar[c] = y
+ }
+ }
+
+ BEGIN {
+ rn("0", "1"); rn("1", "2"); rn("2", "3"); rn("3", "4");
+ rn("4", "5"); rn("5", "6"); rn("6", "7"); rn("7", "8");
+ rn("8", "9"); rn("9", "0");
+
+ rn("a", "b"); rn("b", "c"); rn("c", "d"); rn("d", "e");
+ rn("e", "f"); rn("f", "g"); rn("g", "h"); rn("h", "i");
+ rn("i", "j"); rn("j", "k"); rn("k", "l"); rn("l", "m");
+ rn("m", "n"); rn("n", "o"); rn("o", "p"); rn("p", "q");
+ rn("q", "r"); rn("r", "s"); rn("s", "t"); rn("t", "u");
+ rn("u", "v"); rn("v", "w"); rn("w", "x"); rn("x", "y");
+ rn("y", "z"); rn("z", "a");
+
+ rn("A", "B"); rn("B", "C"); rn("C", "D"); rn("D", "E");
+ rn("E", "F"); rn("F", "G"); rn("G", "H"); rn("H", "I");
+ rn("I", "J"); rn("J", "K"); rn("K", "L"); rn("L", "M");
+ rn("M", "N"); rn("N", "O"); rn("O", "P"); rn("P", "Q");
+ rn("Q", "R"); rn("R", "S"); rn("S", "T"); rn("T", "U");
+ rn("U", "V"); rn("V", "W"); rn("W", "X"); rn("X", "Y");
+ rn("Y", "Z"); rn("Z", "A");
+ }
+
+ function nxstr(str, upto,
+ l, sdig, udig, nxdig)
+ {
+ if (str == upto)
+ return 0
+
+ len = length(str)
+
+ for (; len > 0; --len) {
+ sdig = substr(str, len, 1)
+ udig = substr(upto, len, 1)
+
+ if (sdig == udig)
+ nxdig = resetchar[sdig]
+ else
+ nxdig = nextchar[sdig]
+
+ str = substr(str, 1, len - 1) nxdig substr(str, len + 1)
+
+ if (sdig != udig)
+ break
+ }
+
+ return str
+ }
+.ft R
+
+.SH "SEE ALSO"
+
+cppawk(1)
+
+.SH BUGS
+
+The
+.B parallel
+clause cannot be used in
+.BR loop ,
+which prevents it from being useful in macro implementations of
+clauses. This is because it relies on a macro that is also being used
+in the expansion of
+.B loop .
+This issue is discussed in the BUGS section of the main
+.B cppawk
+man page.
+
+.SH AUTHOR
+Kaz Kylheku <kaz@kylheku.com>
+
+.SH COPYRIGHT
+Copyright 2022, BSD2 License.