This formal grammar describes expressions. Terminal symbols are in quotes, or described in text. Nonterminals are underlined.

Whenever an expression is required, PCC accepts a sequence. The only exception is the Bind elementary command, which takes or-exprs (because it has assignments := as part of its syntax).

sequence:
    assignment
    sequence ";" assignment

assignment:
    or-expr
    assignment ":=" or-expr

or-expr:
    and-expr
    or-expr "Or" and-expr
    or-expr "Xor" and-expr

and-expr:
    not-expr
    and-expr "And" not-expr

not-expr:
    comparison
    "Not" not-expr

comparison:
    concat-expr
    comparison "=" concat-expr
    comparison "<" concat-expr
    comparison ">" concat-expr
    comparison "<=" concat-expr
    comparison ">=" concat-expr
    comparison "<>" concat-expr

concat-expr:
    add-expr
    concat-expr "#" add-expr
    concat-expr "&" add-expr

add-expr:
    mult-expr
    add-expr "+" mult-expr
    add-expr "-" mult-expr

mult-expr:
    neg-expr
    mult-expr "*" neg-expr
    mult-expr "/" neg-expr
    mult-expr "\" neg-expr
    mult-expr "Mod" neg-expr

neg-expr:
    pow-expr
    "-" neg-expr
    "+" neg-expr
    "Not" neg-expr          % Note 1

pow-expr:
    primary-expr
    primary-expr "^" neg-expr

primary-expr:
    "(" sequence ")"
    string-literal
    integer-literal
    float-literal
    "True"                  % Note 2
    "False"                 % Note 2
    "Pi"                    % Note 3
    identifier invocation*

invocation:
    "(" arguments ")"
    "." identifier          % Note 4
    "->" identifier         % Note 4

arguments:
    nothing
    sequence ("," sequence)*

identifier:
    sequence of letters, "$", "_", digits, ".",
      not starting with a digit or period
      not ending with a period

string-literal:
    "'" (any character except for "'")* "'"
    """ (any character except for """ and "\",
         or "\" followed by any character) """

integer-literal:
    digit digit*
      A value is an integer if it fits into 32 bits.
      Otherwise, it's float.

float-literal:
    integer-literal
    digit digit* "."
    digit* "." digit digit*

Notes:

  • 1: Not a=b is always interpreted as a not-expr, binding as Not (a=b). This grammar rule just allows -Not a=b, which is interpreted as (-(Not a)) = b.
  • 2: these are the boolean literals
  • 3: this is a float literal
  • 4: . and -> have essentially the same meaning. However, because the dot can also be part of names, a.b is always interpreted as a single identifier. To access member b of object a, use a->b.