(calc.info)Advanced Syntax Patterns
8.8.8.3 Advanced Syntax Patterns
................................
To match a function with a variable number of arguments, you could write
foo ( # ) := myfunc(#1)
foo ( # , # ) := myfunc(#1,#2)
foo ( # , # , # ) := myfunc(#1,#2,#3)
but this isn't very elegant. To match variable numbers of items, Calc
uses some notations inspired regular expressions and the "extended BNF"
style used by some language designers.
foo ( { # }*, ) := apply(myfunc,#1)
The token `{' introduces a repeated or optional portion. One of the
three tokens `}*', `}+', or `}?' ends the portion. These will match
zero or more, one or more, or zero or one copies of the enclosed
pattern, respectively. In addition, `}*' and `}+' can be followed by a
separator token (with no space in between, as shown above). Thus `{ #
}*,' matches nothing, or one expression, or several expressions
separated by commas.
A complete `{ ... }' item matches as a vector of the items that
matched inside it. For example, the above rule will match `foo(1,2,3)'
to get `apply(myfunc,[1,2,3])'. The Calc `apply' function takes a
function name and a vector of arguments and builds a call to the
function with those arguments, so the net result is the formula
`myfunc(1,2,3)'.
If the body of a `{ ... }' contains several `#'s (or nested `{ ...
}' constructs), then the items will be strung together into the
resulting vector. If the body does not contain anything but literal
tokens, the result will always be an empty vector.
foo ( { # , # }+, ) := bar(#1)
foo ( { { # }*, }*; ) := matrix(#1)
will parse `foo(1,2,3,4)' as `bar([1,2,3,4])', and `foo(1,2;3,4)' as
`matrix([[1,2],[3,4]])'. Also, after some thought it's easy to see how
this pair of rules will parse `foo(1,2,3)' as `matrix([[1,2,3]])',
since the first rule will only match an even number of arguments. The
rule
foo ( # { , # , # }? ) := bar(#1,#2)
will parse `foo(2,3,4)' as `bar(2,[3,4])', and `foo(2)' as `bar(2,[])'.
The notation `{ ... }?.' (note the trailing period) works just the
same as regular `{ ... }?', except that it does not count as an
argument; the following two rules are equivalent:
foo ( # , { also }? # ) := bar(#1,#3)
foo ( # , { also }?. # ) := bar(#1,#2)
Note that in the first case the optional text counts as `#2', which
will always be an empty vector, but in the second case no empty vector
is produced.
Another variant is `{ ... }?$', which means the body is optional
only at the end of the input formula. All built-in syntax rules in
Calc use this for closing delimiters, so that during algebraic entry
you can type `[sqrt(2), sqrt(3 RET', omitting the closing parenthesis
and bracket. Calc does this automatically for trailing `)', `]', and
`>' tokens in syntax rules, but you can use `{ ... }?$' explicitly to
get this effect with any token (such as `"}"' or `end'). Like `{ ...
}?.', this notation does not count as an argument. Conversely, you can
use quotes, as in `")"', to prevent a closing-delimiter token from
being automatically treated as optional.
Calc's parser does not have full backtracking, which means some
patterns will not work as you might expect:
foo ( { # , }? # , # ) := bar(#1,#2,#3)
Here we are trying to make the first argument optional, so that
`foo(2,3)' parses as `bar([],2,3)'. Unfortunately, Calc first tries to
match `2,' against the optional part of the pattern, finds a match, and
so goes ahead to match the rest of the pattern. Later on it will fail
to match the second comma, but it doesn't know how to go back and try
the other alternative at that point. One way to get around this would
be to use two rules:
foo ( # , # , # ) := bar([#1],#2,#3)
foo ( # , # ) := bar([],#1,#2)
More precisely, when Calc wants to match an optional or repeated
part of a pattern, it scans forward attempting to match that part. If
it reaches the end of the optional part without failing, it "finalizes"
its choice and proceeds. If it fails, though, it backs up and tries
the other alternative. Thus Calc has "partial" backtracking. A fully
backtracking parser would go on to make sure the rest of the pattern
matched before finalizing the choice.
automatically generated by info2www version 1.2.2.9