So by 6.3.1.3 ISO would prohibit:
?- X = (- -).
X = - (-).
and
?- X = (- * -).
X = (-)*(-).
If so, would you really want to enforce it?
I see only two practical alternatives to the expr
grammar rule; either (as written):
expr = PrefixOp " " (&PrefixOp expr / !InfixOp expr)
/ term " " ( InfixOp " " expr " " / PostfixOp " " )*
This appears to exploit 6.3.1.3 to a degree since it says an InfixOp
cannot be an operand of a PrefixOp
. So this fails (as does SWIP):
?- string_termList("- * .",[T]).
% pPEG Error: Prolog.expr failed, expected Prolog.expr at line 1.5:
% 1 | - * .
% ^
Alternatively:
expr = PrefixOp " " expr
/ term " " ( InfixOp " " expr " " / PostfixOp " " )*
and this fails:
?- string_termList("- * - .",[T]).
% pPEG Error: Prolog.expr failed, expected Prolog.expr at line 1.7:
% 1 | - * - .
% ^
You have suggested a third alternative with a !PrefixOp
guard, but then this fails:
% /Users/rworkman/Documents/PrologDev/SWI_Prolog/pPEG/SWIP-grammar/pl_grammar compiled into pl_grammar 0.02 sec, 0 clauses
?- string_termList("- .",[T]).
% pPEG Error: Prolog.expr failed, expected Prolog.expr at line 1.3:
% 1 | - .
% ^
which seems even more restrictive than ISO, so it wouldn’t make my short list.
Scryer seems to take 6.3.1.3 literally. That seems too restrictive to me and, it appears, most Prolog implementations agree. For what it’s worth, here’s what Eclipse has to say on the matter (at least they say something):
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.
Ref: Formal definition of clause syntax
Note: Eclipse supports a binary prefix operator which is outside the scope of this discussion so the last paragraph can be ignored.