I was deeply motivated by TMG. The good news is that
you could say what
you wanted and it just did it. The bad news was the error handling.
Because it was recursive if you made a syntax error the program
backtracked and tried again. And again. And again. And eventually was
back at the first character of the input with nowhere to go. So it
issued one of its two messages -- "Syntax Error".
This is somewhat of a caricature. If one's compilation strategy were
to build an abstract syntax tree of the whole source program before
emitting any object code, then things would go as Steve describes.
In reality, TMG wasn't used this way. For one thing, ASTs needed
too much memory.
In TMG one could emit code while parsing. Typically code
was generated on a statement-by-statement basis. This limited
the backtracking, so even a naive "syntax error" diagnostic could
be localized to the statement level. Long-distance connections, such
as the branch labels in a nest of if statements, could nevertheless
be realized recursively.
Thus, in actual use, a TMG "grammar" was partly a parsing program
and partly abstract specification. The balance of viewpoints was
left to the discretion of the grammar's author. Yacc swung the
pendulum toward the abstract.
Doug