> >> > One strategy that came to mind is that you can treat all of the
> > > > commands that take complicated arguments (statement lists or
> > > > expression lists) the same: set a flag that indicates what command is
> > > > currently being processed. When a particular construction is
> > > > encountered, it can check the flag to see if it is valid. If not, it
> > > > can give an error (and a better one than is currently produced).
> > > >
> > > > For example,
> > > > \shape = 2.5 \in 2.5 \in 3.5\in 3.5\in;
>
> the syntax of \shape sucks. It should probably have been
>
> shape = "2.5 2.5 3.5";
>
> Or something like this.
Hmmm. I'm not sure that's an improvement. The syntax
\shape 2.5\in 2.5\in 3.5\in;
(with no '=') is consistent with other commands. Having a special
string that defines the shape seems less consistent. (How would
dimensions be specified in the string?)
> > > > independent, since you can parse everything regardless of context.
> > > > You then decide what to do, or what errors to issue, based on context.
> > >
> > >
> > > Yes, but it wouldn't simplify using LilyPond, because this simple
> > > grammar doesn't explain why \shape can't be done at toplevel. What
> > > you are proposing is more or less analogous to going from compile-time
> > > errors to run-time errors in a programming language: the language
> > > becomes simpler, but you don't necessarily make less errors.
> >
> > Well, the current implementation doesn't explain why \shape can't be
> > done at top level. It doesn't even explain why using \shape in that
> > situation is a parse error. It doesn't even explain that the parse
> > error resulted from saying "\shape". For all the confused user knows,
> > it was supposed to be "\shape { ... }" instead of "\shape = ... ;".
> > You have to go read parser.yy to find out that the problem is that
> > \shape is only legal inside \paper.
>
> I am kind of flabbergasted as to how you would implement this in a
> simple manner. Yes, I can imagine it being done by adding a real
> type-checking/inference system to LilyPond, but I think that is way
> over the top.
Well, as I have mentioned before, I don't know much about parsers,
lexers, or bison. That's why I keep questioning the feasibility of my
suggestions.
One thing I do know is that the error messages are often very
unfriendly. Maybe this can't be fixed. But if it can be, it should
be. If your program is successful, it will have users who are not
even programmers. They will not be able to learn how to use the
program by reading parser.yy.
> > > How would you concisely and unambiguously explain what kinds of
> > > expressions can be nested in what other kind of expression?
> >
> > I'm not sure if this is a problem or not. First, I'll note that it
> > appears that every command has only one context in which it can
> > appear. The \shape command appears exclusively in \paper. Anywhere
> > else it is a "parse error". Furthermore, it seems that only the last
> > layer of context matters. If only the last layer of context is
> > important, then you just need a flag that indicates the current
> > context. Each command can have a list of the contexts where it is
> > permitted (generally there is only one).
> >
> > I can see what you mean about compile-time vs. run-time errors. It's
> > true that it doesn't change the number of errors. But if it enables
> > the enigmatic "parse error" to be replaced with a message that
> > actually carries some information, it would be a valuable change. On
> > the other hand, maybe there's some other way to achieve this result.
>
> Yes, and I think that the problem is not in mudela, but in yacc/bison;
> this stuff is something that would require intimate knowledge of the
> grammar at hand. It can only be done well if Bison were modified.
>
> > Basically I think it would be good if anytime a keyword appears in the
> > wrong context, a message is generated saying: "this keyword is in the
> > wrong context. It can only be used in context(s) X (Y, and Z)". That
> > way, the user knows immediately what is wrong, rather than spending 10
> > minutes puzzling over the obscure "parse error", and then having to
> > consult the manual to figure out where the command is supposed to go.
>
> This won't work. I think (but my knowledge of parsing is quite
> limited. I will change that soon) that the number of 'contexts' is
> quite large in practice. (because of transformations bison makes.
> Run bison -v for fun some time.)
I was not using "context" to refer to the states of the parsing
machine. If \shape appears in some totally bizarre place, then "parse
error" seems more reasonable. It's when \shape appears at the top
level, or in the \midi block, for example, that I think there should
be a reasonable message. When \shape appears in the wrong block the
input LOOKS syntactically correct. Assuming the \shape command is a
correct one, then it is parsable.
I'm not totally convinced that this is impossible. It might be tricky
or a bit complicated, though. I think that doing it the way I
proposed involves a mid-action rule which the manual says can be
troublesome.
Let me give a simple example of what I was thinking. The \shape
command is permitted only within \paper. It can appear absolutely
nowhere else, as far as I can tell. So
\paper{ \KEYWORD { \shape ...}}
is illegal because the shape isn't right inside the \paper.
So this can be implemented using the flag as I mentioned something
like this:
PAPER '{' {pushflag(); flag=INPAPER;} statement '}'
{ do_default_paper_action();
popflag();
}
OTHERKEYWORD '{' {pushflag(); flag = SOMETHINGELSE; statement '}'
...
etc
Every keyword that changes the context stores the old value of the
flag on a stack and sets a new value.
Then there is a rule for statement that looks like
statement: SHAPE dimarray ';'
{ if (flag==INPAPER) { do_normal_shape_handling();}
else { produce_error("\\shape only allowed in \\paper\n"); }
}
There might also be
NOTENAMES '{' {pushflag(); flag=INNOTENAMES;} statement '}'
{ do_default_notename_action();
popflag(); }
statement: CLEAR
{ if (flag==INNOTENAMES) { clear_notenames(); }
else {produce_error("\\clear only allowed in \\notenames\n");}
I read bits of the Bison manual last night so I learned a little bit
about this stuff. The complication is that it might be hard to
correctly reset "flag" during error recovery.
> > fact, I think in the ideal situation, the abstract grammar would be
> > written before you write one line of code.
>
> No. That implies that the problem you're solving is
> well-defined. (which it isn't, in this case)
I did say "ideal". In the ideal situation the problem would be
well-defined. I know that real world and ideal can be far apart.
But it seems like enough work has been done, and enough thought has
already been put into designing the real grammar that the time has,
perhaps, been reached to write an abstract grammar. You know
something about the problem you're trying to solve. You can always
rewrite the abstract grammar later if you realize (as a result of
better understanding of the problem) that it has deficiencies.
The other option is to continually extend your real grammar in an
ad-hoc fashion. Is that really preferable?