odeinput language formally specified
The following is a formal specification of the grammar for
input language, in Backus–Naur form. Nonterminal symbols in the
grammar are enclosed in angle brackets. Terminal tokens are in all
capitals. Bare words and symbols stand for themselves.
<program> ::= ... empty ... | <program> <statement> <statement> ::= SEP | IDENTIFIER = <const> SEP | IDENTIFIER ' = <expression> SEP | print <printlist> <optevery> <optfrom> SEP | step <const> , <const> , <const> SEP | step <const> , <const> SEP | examine IDENTIFIER SEP <printlist> ::= <printitem> | <printlist> , <printitem> <printitem> ::= IDENTIFIER | IDENTIFIER ' | IDENTIFIER ? | IDENTIFIER ! | IDENTIFIER ~ <optevery> ::= ... empty ... | every <const> <optfrom> ::= ... empty ... | from <const> <const> ::= <expression> <expression> ::= ( <expression> ) | <expression> + <expression> | <expression> - <expression> | <expression> * <expression> | <expression> / <expression> | <expression> ^ <expression> | FUNCTION ( <expression> ) | - <expression> | NUMBER | IDENTIFIER
Since this grammar is ambiguous, the following table summarizes the precedences and associativities of operators within expressions. Precedences decrease from top to bottom.
Class Operators Associativity Exponential ^ right Multiplicative * / left Additive + - left
As noted in the grammar, there are six types of nontrivial statement. We now explain the effects (the `semantics') of each type, in turn.
This defines a first-order differential equation. The derivative of IDENTIFIER is specified by <expression>. If a dynamic variable does not appear on the left side of a statement of this form, its derivative is assumed to be zero. That is, it is a symbolic constant.
This sets the value of IDENTIFIER to the current value of <expression>. Dynamic variables that have not been initialized in this way are set to zero.
A ‘step’ statement causes the numerical scheme to be executed. The first <const> is the initial value of the independent variable. The second is its final value. The third is a stepsize; if given, it overrides any stepsize that may be specified on the command line. Usually the stepsize is not specified, and it varies adaptively as the computation proceeds.
A ‘print’ statement controls the content and frequency of the numerical output. <printlist> is a comma-separated list of IDENTIFIERs, where each IDENTIFIER may be followed by ‘'’, denoting the derivative, or ‘?’, denoting the relative single-step error, or ‘!’, denoting the absolute single-step error, or ‘~’, denoting the accumulated error (not currently implemented). The specified values are printed in the order they are found. Both the ‘every’ clause and the ‘from’ clause are optional. If the ‘every’ clause is present, a printing occurs every <const> iterations of the numerical algorithm. The default is to print on every iteration (i.e. ‘every 1’). The first and last values are always printed. If the ‘from’ clause is present, it means to begin printing when the independent variable reaches or exceeds <const>. The default is to begin printing immediately.
If no ‘print’ statement has been supplied, then the independent variable and all dependent variables which have differential equations associated with them are printed. The independent variable is printed first; the dependent variables follow in the order their equations were given.
An ‘examine’ statement, when executed, causes a table of interesting information about the named variable to be printed on the standard output. For example, if the statement ‘examine y’ were encountered after execution of the `ode to Euler' example discussed elsewhere, the output would be:
"y" is a dynamic variable value:2.718282 prime:2.718282 sserr:1.121662e-09 aberr:3.245638e-09 acerr:0 code: push "y"
The phrase `dynamic variable' means that there is a differential equation describing the behavior of y. The numeric items in the table are:
The ‘code’ section of the table lists the stack operations required to compute the derivative of y (somewhat reminiscent of a reverse Polish calculator). This information may be useful in discovering whether the precedences in the differential equation statement were interpreted correctly, or in determining the time or space expense of a particular calculation. ‘push "y"’ means to load y's value on the stack, which is all that is required to compute its derivative in this case.
The grammar for the
ode input language contains four types of
terminal token: FUNCTION, IDENTIFIER, NUMBER, and SEP. They have the following meanings.
One of the words: abs, sqrt, exp, log, ln,
log10, sin, cos, tan, asin, acos, atan,
sinh, cosh, tanh, asinh, acosh, atanh,
floor, ceil, besj0, besj1, besy0, besy1,
erf, erfc, inverf, lgamma, gamma, norm,
invnorm, ibeta, igamma. These are defined to have the same
meaning as in the plotting program
gnuplot. All functions take a
single argument, except for ibeta, which takes three, and
igamma, which takes two. For trigonometric functions, all arguments
are expressed in radians. The atan function is defined to give a
value between −PI/2 and PI/2 (inclusive).
A sequence of alphanumeric characters starting with an alphabetic character. The first 32 characters are significant. Upper and lower-case letters are distinct. In identifiers, the underscore character is considered alphabetic. Function names and keywords may not be used as identifiers, nor may ‘PI’.
A non-empty sequence of digits possibly containing a decimal point and possibly followed by an exponent. An exponent is ‘e’ or ‘E’, followed by an (optionally signed) one, two, or three-digit number. All numbers and all parts of numbers are radix 10. A number may not contain any white space. The special word ‘PI’ is a number.
A separator: a semicolon or a (non-escaped) newline.
ode input language, upper and lower-case letters are
distinct. Comments begin with the character ‘#’ and continue to
the end of the line. Long lines may be continued onto a second line by
ending the first line with a backslash (‘\’). That is because
the combination backslash-newline is equivalent to a space.
Spaces or tabs are required in the input whenever they are needed to separate identifiers, numbers, and keywords from one another. Except as separators, they are ignored.