Formal definition of clause syntax

## A.3 Formal definition of clause syntax

- Comments
- Operators
- Operator Ambiguities

What follows is the specification of the syntax. The terminal symbols are written in UPPER CASE or as the character sequence they consist of.

    program                 ::=     clause EOCL
                             |      clause EOCL program

    clause                  ::=     head
                             |      head rulech goals
                             |      rulech goals

    head                    ::=     term_h

    goals                   ::=     term_g
                             |      goals , goals
                             |      goals ; goals
                             |      goals -> goals
                             |      goals -> goals ; goals

    term_h                  ::=     term_h(0)
                             |      term(1200)

    term_g                  ::=     term_g(0)
                             |      term(1200)

    term(0)                 ::=      VAR            /* not a term_h */
                             |       attr_var       /* not a term_h */
                             |       ATOM
                             |       structure
                             |       structure_with_fields
                             |       subscript
                             |       list
                             |       STRING         /* not a term_h nor a term_g */
                             |       number         /* not a term_h nor a term_g */
                             |       bterm

    term(N)                 ::=     term(0)
                             |      prefix_expression(N)
                             |      infix_expression(N)
                             |      postfix_expression(N)

    prefix_expression(N)    ::=     fx(N)   term(N-1)
                             |      fy(N)   term(N)
                             |      fxx(N)  term(N-1)  term(N-1)
                             |      fxy(N)  term(N-1)  term(N)

    infix_expression(N)     ::=     term(N-1)  xfx(N)  term(N-1)
                             |      term(N)    yfx(N)  term(N-1)
                             |      term(N-1)  xfy(N)  term(N)

    postfix_expression(N)   ::=     term(N-1)  xf(N)
                             |      term(N)    yf(N)

    attr_var                ::=     VAR { attributes }
                                    /* Note: no space before { */

    attributes              ::=     attribute
                             |      attribute , attributes

    attribute               ::=     qualified_attribute
                             |      nonqualified_attribute

    qualified_attribute     ::=     ATOM : nonqualified_attribute

    nonqualified_attribute  ::=     term_a

    structure               ::=     functor ( termlist )
                                    /* Note: no space before ( */

    structure_with_fields   ::=     functor { termlist }
                             |      functor { }
                                    /* Note: no space before { */

    subscript               ::=     structure list
                             |      VAR list
                                    /* Note: no space before list */

    termlist                ::=      term_a
                             |       term_a , termlist

    list                    ::=     [ listexpr ]
                             |      .(term_a, term_a)

    listexpr                ::=     term_a
                             |      term_a | term_a
                             |      term_a , listexpr

    term_a                  ::=     term(1200)
                                    /* Note: it depends on syntax_options */

    number                  ::=     INT
                             |      INTBAS
                             |      INTCHAR
                             |      RAT
                             |      FLOAT
                             |      BREAL

    bterm                   ::=     ( clause )
                             |      { clause }

    functor                 ::=     ATOM                    /* arity > 0 */

    rulech                  ::=     :-
                             |      ?-

### A.3.1 Comments

There are two types of comments: bracketed comments, which are enclosed by CM1-CM2 and CM2-CM1, and the end-of-line comment, which is enclosed by CM and NL. Both types of comment behave as separators. When the syntax option nested_comments is on (the default is off), bracketed comments can be nested.

### A.3.2 Operators

In Prolog, the user is able to modify the syntax dynamically by explicitly declaring new operators. The built-in op/3 performs this task. As in Edinburgh Prolog, a lower precedence value means that the operator binds more strongly (1 strongest, 1200 weakest).

Any atom (whether symbolic, alphanumeric, or quoted) can be declared as an operator. Once an operator has been declared, the parser will accept the corresponding operator notation, and certain output built-ins will produce the operator notation if possible. There are three classes of operators: prefix, infix and postfix.

- When f is declared as a prefix unary operator (fx or fy), then the term f(X) can alternatively be written as f X.
- When f is declared as a prefix binary operator (fxx or fxy), then the term f(X,Y) can alternatively be written as f X Y.
- When f is declared as a postfix operator (xf or yf), then the term f(X) can alternatively be written as X f.
- When f is declared an an infix operator (xfx, xfy or yfx), then the term f(X,Y) can alternatively be written as X f Y.

An operator can belong to more than one class, e.g., the plus sign is both a prefix and an infix operator at the same time.

In the associativity specification of an operator (e.g., fx, yfx), x represents an argument whose precedence must be lower than that of the operator. y represents an argument whose precedence must be lower or equal to that of the operator. y should be used if one wants to allow chaining of operators (i.e., if one wants them to be associative). The position of the y will determine the grouping within a chain of operators. For example:

>     Example declaration        will allow          to stand for
>     ---------------------------------------------------------------
>     :- op(500,xfx,in).         A in B              in(A,B)
>     :- op(500,xfy,in).         A in B in C         in(A,in(B,C))
>     :- op(500,yfx,in).         A in B in C         in(in(A,B),C)
>     :- op(500,fx ,pre).        pre A               pre(A)
>     :- op(500,fy ,pre).        pre pre A           pre(pre(A))
>     :- op(500, xf,post).       A post              post(A)
>     :- op(500, yf,post).       A post post         post(post(A))
>     :- op(500,fxx,bin).        bin A B             bin(A,B)
>     :- op(500,fxy,bin).        bin A bin B C       bin(A,bin(B,C))

Operator declarations are usually local to a module, but they can be exported and imported. The operator visible in a module is either the local one (if any), an imported one, or a predefined one. Some operators are pre-defined (see Appendix B on page ??). They may be locally redefined if desired.

Note that parentheses are used to build expressions with precedence zero and thus to override operator declarations.1

### A.3.3 Operator Ambiguities

Unlike the canonical syntax, operator syntax can lead to ambiguities.

- For instance, when a prefix operator is followed by an infix or postfix operator, the prefix is often not meant to be a prefix operator, but simply the left hand side argument of the following infix or postfix. In order to decide whether that is the case, ECLiPSe uses the operator’s relative precedences and their associativities, and, if necessary, a two-token lookahead. If this rules out the prefix-interpretation, then the prefix is treated as a simple atom. In the rare case where this limited lookahead is not enough to disambigute, the prefix must be explicitly enclosed in parentheses.
- Another source of ambiguity are operators which have been declared both infix and postfix. In this case, ECLiPSe uses a one-token lookahead to check whether the infix-interpretation can be ruled out. If yes, the operator is interpreted as postfix, otherwise as infix. Again, in rare cases parentheses may be necessary to enforce the interpretation as postfix.
- When a binary prefix operator is followed by an infix operator, then either of them could be the main functor. Faced with the ambiguity, the system will prefer the infix interpretation. To force the binary prefix to be recognised, the infix must be enclosed in parentheses.

1
  Quotes, on the other hand, are used to build atoms from characters with different or mixed character classes; they do not change the precedence of operators.