Go to the first, previous, next, last section, table of contents.

The ode input language formally specified

The following is a formal specification of the grammar for ode's 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.

  1. IDENTIFIER ' = <expression> 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.
  2. IDENTIFIER = <const> 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.
  3. step <const> , <const>
  4. step <const> , <const> , <const> 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.
  5. print <printlist> [ every <const> ] [ from <const> ] 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.
  6. examine IDENTIFIER 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
     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:
    Current value of the variable.
    Current derivative of the variable.
    Relative single-step error for the last step taken.
    Absolute single-step error for the last step taken.
    Total error accumulated during the most recent `step' statement. Not currently implemented.
    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.

  1. FUNCTION 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).
  2. IDENTIFIER 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'.
  3. NUMBER 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.
  4. SEP A separator: a semicolon or a (non-escaped) newline.

In the 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.

Go to the first, previous, next, last section, table of contents.