From: Juliusz Chroboczek
Subject: Re: Help with cl-yacc
Date: 
Message-ID: <7iu0baaj92.fsf@lanthane.pps.jussieu.fr>
"Joel Reymont" <······@gmail.com> writes:

> This is the actual grammar. Does not work if I uncomment statement.

> (yacc:define-parser parser
    [...]
>   (sections
>    (sections section)
>    section)
    [...]
>   (section
>    declarations-list
>    ;;statements
     [...]
>   (declarations-list
>    (declaration-list declarations |;|)
>    (declarations |;|))

Your grammar does compile fine, but it generates warnings about
conflicts.  (Note that SBCL has a bug where it breaks on warnings by
default; sorry, I'm not going to work around SBCL's brain-damage in
CL-Yacc.)

The problem is that the grammar is /ambiguous/, meaning that a given
string can be parsed in multiple manners.  This is the one notion that
you really need to understand before you start writing a grammar.

Consider for example the following string of tokens:

  :id1 |;| :id1 |;|

This can parse as

                    
                 sections
              section  section
           statements  statements
            statement  statement

or as

                 sections
                 section
                statements
           statement statement

You need to fix the grammar in order to make it non-ambiguous.  Unless
I'm missing something, you don't actually need to have sections, and
it should be enough to write something like

    (declaration-statement-list ()
                                (declaration-statement-list declaration)
                                (declaration-statement-list statement)

and perhaps decompose the result into ``sections'' in a later pass (in
Lisp code).  You could also do the work in the parser, and do
something like:

    (section-list ()
                  (section-list section))

    (section (declaration-list statement-list))

    (declaration-list ()
                      (declaration-list declaration))

    (statement-list ()
                    (statement-list statement))

                                        Juliusz

From: Christophe Rhodes
Subject: Warnings, compilation failures (was Re: Help with cl-yacc)
Date: 
Message-ID: <sqr76e3fwp.fsf_-_@cam.ac.uk>
Juliusz Chroboczek <···@pps.jussieu.fr> writes:

> Your grammar does compile fine, but it generates warnings about
> conflicts.  (Note that SBCL has a bug where it breaks on warnings by
> default; sorry, I'm not going to work around SBCL's brain-damage in
> CL-Yacc.)

This paragraph sounds like it's confused.  (Well, I would say that,
wouldn't I?).  However, I think that some clarity might, well, clarify
what's actually happening.

* SBCL obeys the ANSI standard definition for COMPILE-FILE: if a
  condition of type (AND WARNING (NOT STYLE-WARNING)) is unmuffled
  during the dynamic extent of a call to COMPILE-FILE, the third
  return value, called FAILURE-P in the standard, will be true.

* SBCL's default value for *BREAK-ON-SIGNALS* is the ANSI-mandated
  default value, NIL, meaning that SBCL does not break on warnings by
  default.

* ASDF's default behaviour for compilation of systems, under SBCL
  only, is to treat a true third return value from COMPILE-FILE as a
  failure, and offer accept and retry restarts.  (I suspect this is
  what Juliusz means when he says "SBCL has a bug".)

So, why?  Well, ANSI offers very little discussion about what a
WARNING means (other than that COMPILE-FILE should treat it as a
failure); it does offer something more about STYLE-WARNINGs, when it
says that
  An implementation might signal such a condition if it encounters
  code that uses deprecated features or that appears unaesthetic or
  inefficient.
and
  The intent is that whenever such a facility wishes to complain about
  code on such subjective grounds, it should use this condition type
  so that any clients who wish to redirect or muffle superfluous
  warnings can do so without risking that they will be redirecting or
  muffling other, more serious warnings.
so I claim that it's relatively clear that the condition type for poor
but functional code is intended to be a STYLE-WARNING rather than a
full WARNING, which means instead that the code has been detected to
be ill-defined or otherwise non-functional.

As for why the ASDF developers chose the SBCL-specific behaviour,
partly this is because of the history of the two projects: this
interpretation of the FAILURE-P return value and the meaning of the
WARNING condition type being accepted among developers of SBCL, it was
reasonable to propagate this to the ASDF user proactively, to assist
in tracking down non-functional code; since other implementations have
not historically respected this distinction between STYLE-WARNINGs and
full WARNINGs in their own code, it would be counterproductive to
bother the user with the spurious failures that would result.

(Note also that the behaviour of ASDF on FAILURE-P is customizeable on
a per-component basis in ASDF, using the documented protocols, should
Juliusz continue to consider this reasoning as brain-damage.)

Christophe
From: Juliusz Chroboczek
Subject: Re: Warnings, compilation failures
Date: 
Message-ID: <7iirrqafpe.fsf@lanthane.pps.jussieu.fr>
Christophe Rhodes <·····@cam.ac.uk> writes:

> * SBCL's default value for *BREAK-ON-SIGNALS* is the ANSI-mandated
>   default value, NIL

[...]

> * ASDF's default behaviour for compilation of systems, under SBCL
>   only, is to treat a true third return value from COMPILE-FILE as a
>   failure, and offer accept and retry restarts.  (I suspect this is
>   what Juliusz means when he says "SBCL has a bug".)

Thanks for the explanation, Christophe.  So it looks like it's not an
SBCL bug after all.

> a full WARNING [...] means [...] that the code has been detected to
> be ill-defined or otherwise non-functional.

I happen to disagree with that.

> (Note also that the behaviour of ASDF on FAILURE-P is customizeable on
> a per-component basis in ASDF, using the documented protocols, should
> Juliusz continue to consider this reasoning as brain-damage.)

I do consider the fact that SBCL's version of ASDF has different
behaviour than the portable version as an unfortunate mis-feature.

                                        Juliusz
From: Juliusz Chroboczek
Subject: Re: Warnings, compilation failures
Date: 
Message-ID: <7ifymtbqdi.fsf@lanthane.pps.jussieu.fr>
Christophe Rhodes <·····@cam.ac.uk> writes:

>> (Note also that the behaviour of ASDF on FAILURE-P is customizeable on
>> a per-component basis in ASDF, using the documented protocols, should
>> Juliusz continue to consider this reasoning as brain-damage.)

I've thought about this carefully and, 24 hours later, I'm pretty
certain that I do indeed consider the behaviour of SBCL's version of
ASDF as being broken.

Unlike typical exception systems, the Common Lisp condition system is
designed to separate the class of a signal from the default handling
strategy.  You specify the default handling strategy by using a
specific signalling function (WARN, CERROR or ERROR), and the class of
the object being signalled is not relevant.

In other words, when CL-Yacc says

    (unless muffle-conflicts
      (warn (make-condition 'conflict-warning
                            ...)))

it is explicitly saying ``signal a condition of class CONFLICT-WARNING,
and DO NOT BREAK by default''.

By tying the class of the condition with the default handling strategy,
SBCL's version of ASDF is trying to coerce Common Lisp's condition
system into the more primitive framework of traditional exception
systems (such as the one in Java or Caml).  This is definitely not
something that I'm going to work around in CL-Yacc.

                                        Juliusz
From: Christophe Rhodes
Subject: Re: Warnings, compilation failures
Date: 
Message-ID: <sqhd79hab2.fsf@cam.ac.uk>
Juliusz Chroboczek <···@pps.jussieu.fr> writes:

> Christophe Rhodes <·····@cam.ac.uk> writes:
>
>>> (Note also that the behaviour of ASDF on FAILURE-P is customizeable on
>>> a per-component basis in ASDF, using the documented protocols, should
>>> Juliusz continue to consider this reasoning as brain-damage.)
>
> I've thought about this carefully and, 24 hours later, I'm pretty
> certain that I do indeed consider the behaviour of SBCL's version of
> ASDF as being broken.

Thank you for considering it for so long.  I continue to disagree, but
notwithstanding my relatively instant response I shall attempt to
continue to ponder; I'm replying so soon because there are some
missing things from your reasoning that I consider relevant, and I'm
not sure if you don't consider them relevant or if you've glossed over
them.

> Unlike typical exception systems, the Common Lisp condition system is
> designed to separate the class of a signal from the default handling
> strategy.  You specify the default handling strategy by using a
> specific signalling function (WARN, CERROR or ERROR), and the class of
> the object being signalled is not relevant.

I don't think the second sentence is true.

Firstly, the type of the condition for WARN is in fact tied to the
signalling function; you are not allowed to signal non-WARNINGs from
WARN.  (It is true that this is not an issue for CERROR and ERROR.)  I
think that WARN, CERROR and ERROR are simply convenience functions for
certain typical uses of conditions, and that the basic operators are
(as I think you imply) the orthogonal operators SIGNAL, HANDLER-BIND
and RESTART-BIND.  WARN is simply, schematically,

(defun warn (designator &rest args)
  (let ((c (ensure-condition-of-type 'warning designator args)))
    (restart-case
         (progn
           (signal c)
           (format *error-output* "~&WARNING:~_~A~%" c))
      (muffle-warning () nil))))

Secondly, though I agree that the identity of the class of the
signalled object is largely orthogonal to the default recovery
strategy from a technical point of view, I think that there are
conventions to be observed: for a more concrete example than the one
we're discussing here, see the description of SERIOUS-CONDITION; I
think I would consider a program which signalled an instance of
SERIOUS-CONDITION without the debugger being the result of the
condition being unhandled to be dubious at best.  My inference for the
meaning of the condition type (AND WARNING (NOT STYLE-WARNING)) is
made from less explicit statements in the spec, but I believe it is a
solid inference.

> In other words, when CL-Yacc says
>
>     (unless muffle-conflicts
>       (warn (make-condition 'conflict-warning
>                             ...)))
>
> it is explicitly saying ``signal a condition of class CONFLICT-WARNING,
> and DO NOT BREAK by default''.

I think this is true but incomplete.  I think it says

* install a MUFFLE-WARNING restart;

* signal a condition of class of CONFLICT-WARNING;

* if the MUFFLE-WARNING restart (or any other restart) is not
  activated, print an informative message to *ERROR-OUTPUT*;

* if we are running under COMPILE-FILE and the MUFFLE-WARNING restart
  (or any other restart) is not activated, arrange that the second
  return value (warningsp) will be true, and also that the third
  return value (failurep) will be true if CONFLICT-WARNING is not a
  STYLE-WARNING.  Do not abort the compilation at this stage.

That is, cl-yacc has a choice to make with the class CONFLICT-WARNING
_in addition_ to your explicit statement; is it:
  "signal a condition of class CONFLICT-WARNING, DO NOT BREAK by
   default, and if under COMPILE-FILE make warningsp be true"
or
  "signal a condition of class CONFLICT-WARNING, DO NOT BREAK by
   default, and if under COMPILE-FILE make warningsp AND failurep be
   true"
?

> By tying the class of the condition with the default handling strategy,
> SBCL's version of ASDF is trying to coerce Common Lisp's condition
> system into the more primitive framework of traditional exception
> systems (such as the one in Java or Caml).  This is definitely not
> something that I'm going to work around in CL-Yacc.

The tying of the condition class to the signalling of an error is not
direct: it is an indirect relationship, through the semantics of the
return values of COMPILE-FILE.  I don't think that this is a mistake,
though; I think that the semantics of the return values can provide
valuable information to the caller of COMPILE-FILE, in this case ASDF.

To implement compile-file, an implementor must do something like

  (defun compile-file (pathname)
    (let (warningsp failurep)
      (handler-bind
          ((style-warning 
            (lambda (c) 
              (setf warningsp t)
              (format *error-output* "caught STYLE-WARNING: ~A" c)
              (muffle-warning c)))
           (warning
            (lambda (c) 
              (setf warningsp t failurep t)
              (format *error-output* "caught WARNING: ~A" c)
              (muffle-warning c))))
        (let ((output (real-compile-file pathname)))
          (values output warningsp failurep)))))

and here there _must_ be a distinction between the identities of the
classes of conditions signalled.  (I further believe that this
distinction in the meanings of STYLE-WARNING warnings and
non-STYLE-WARNING warnings can be useful to users of software.)

For what it's worth, this is not something that I consider you should
be working around in cl-yacc; I consider this a (minor) bug in
cl-yacc.

Christophe
From: Juliusz Chroboczek
Subject: Re: Warnings, compilation failures
Date: 
Message-ID: <7ihd79bj7z.fsf@lanthane.pps.jussieu.fr>
Christophe Rhodes <·····@cam.ac.uk> writes:

> For what it's worth, this is not something that I consider you should
> be working around in cl-yacc; I consider this a (minor) bug in
> cl-yacc.

Christophe has since clarified that this last point refers to the fact
that YACC:CONFLICT-WARNING is a direct subclass of WARNING rather than
a STYLE-WARNING.

                                        Juliusz