A Prolog Unparser Error

Shouldn’t two structurally different Prolog terms give a different output?
Was trying this example with SWI-Prolog 8.3.26:

?- op(400,xfy,***).
true.

?- X=(a***b)*c, Y=a***(b*c).
X = a***b*c,
Y = a***b*c.

?- X=(a***b)*c, Y=a***(b*c), X=Y.
false.

GNU Prolog 1.4.5 on the other hand gives me, thanks to its
context == INSIDE_LEFT_ASSOC_OP logic in its Show_Term:

?- X=(a***b)*c, Y=a***(b*c).
X = (a***b)*c
Y = a***b*c

Edit 17.07.2021:
There is a similar problem for the prefix fy yfx combo:

?- op(400,fy,***).
true.

?- X = (***b)*c, Y= ***(b*c).
X = ***b*c,
Y = ***b*c.

I had a serious look into these issues some time ago as a result of porting some SICStus code using zillions of complicated operators. Both SICStus and SWI allow for more than ISO wrt operators. Mostly they agree on the parse, sometimes not and notably SWI-Prolog rejects more than SICStus. I also had some discussion with SICStus about these issues. Despite the fact that they are very keen on ISO compliance they didn’t consider restricting to the ISO operator rules as it would upset too many customers.

I don’t know what ISO says about this case. From a declarative perspective on the operator precedence rules I guess it is ambiguous. Does ISO dictate a resolution? Or is this supposed to be a syntax error? If ISO dictates a solution I may have a look at resolving this. If not, I think I’ll simply stick with the advice to carefully design your operator priorities.

SICStus should do it correctly, you can check yourself(*). The solution is rather trivial, but can be annoying to implement. Whether this has something todo with the ISO core standard, I doubt. The ISO core standard didn’t invent Prolog operator mechanism, it only documented it later.

We only require:

/* re-read what was written */
read(writeq(T)) = T

The solution à la GNU Prolog is to extend a needs parenthesis rule:

% write_rparen(+Stream, +WritePrio, +OperPrio)
write_rparen(S, L, R) :- L < R, !,
   put_code(S, 0')).
write_rparen(_, _, _).

Into a little more complicated needs parenthesis rule:

% write_rparen(+Stream, +OperAssocR, +WritePrio, +OperPrio, +CtxtAssocL)
write_rparen(S, _, L, R, _) :- L < R, !,
   put_code(S, 0')).
write_rparen(S, 0, L, L, F) :- F/\8 =\= 0, !,
   put_code(S, 0')).
write_rparen(_, _, _, _, _).

(*) The closest to what I am testing is possibly Ulrichs #152 and #153. But this tests only
the writing of fy yfx, and not the writing of xfy yfx. I don’t find Ulrich tests for the later.

I think Richard O’Keefe wrote something on this, but is the old Prolog Digest preserved anywhere?

(My vague recollection is that the operators are extracted first, using a greedy algorithm, and left-right/right-left juxtapositions aren’t allowed.)

Anyway, SWI-Prolog doesn’t generate the same structure for both, as write_canonical/1 shows:

?- X = (a***b)*c, Y=a***(b*c), write_canonical([X,Y]),nl.
[*(***(a,b),c),***(a,*(b,c))]
X = a***b*c,
Y = a***b*c.

So, it would seem that the algorithm for outputting isn’t quite right (moar parens!).