> An unpaired brace can simply be flagged and then ignored during parsing.
I don't see what that'd generally buy vs. simply trying the parse until it fails, though.
> The other thing is that you know exactly where your brace constructions end, so you don't need to parse beyond them.
That's automatically handled simply by adding the closing braces to the operator table, and terminating when the right type is reached, or when a symbol is hit that is not valid within the context. E.g. the example parser I linked to will automatically terminate that way if you invoke it the right way.
> Likewise, if you have parsed all that you can inside the brace area and still haven't reached the end, you can just flag the remaining tokens as unexpected junk and move on to the end of the brace, recovering very gracefully.
That's a line or two to catch the exceptions the example code throws and the read tokens until the specified closing brace/bracket type.
> Finally, to if you type ( inside (....) to get (...(...), you can use the fact that the outer parens to were previously matched to flag that the inner paren just typed is the one unmatched, not the outer ones.
That sounds specific to an IDE, and not really something I've looked at, and does sound like it might be useful. The other ones don't really convince me, but I guess for an interactive parser this one could be. Of course it's trivial to combine that with a precedence parser too, and still handle it in the parser.
> That is basically a check, I'm not really versed in Ruby's grammar, in many languages the grammars are quite complicated and BNF-style enforcements is very necessary...you also need to consider construction of your AST for type checking and execution (which you might not need for your case).
It's a check that is inherent to the precedence parser. The entire point of the parser is "shunt" tokens onto an operand and operator stack effective sort them into reverse polish notation. You can't do that without knowing if the operator is prefix, postfix or infix and what arity the operator has (though most preced check if the token stream matches the rules in the operator table, and if so output expressions.
ence parsers will just assume an arity of 1 for prefix/postfix and 2 for infix, that's easy to overcome).
The operator table is a specification of the grammar according to those rules. If you get a malformed tree, either the parser in question doesn't support your grammar, or your grammar specification in the form of the operator table is malformed.
> BNF-style enforcements is very necessary..
There are certainly subsets that are awkward or requires you to augment a precedence parser. E.g. as I described elsewhere, in a past experiment where I did parse a whole Pascal-like language this way, I had to add a bunch of extra operator types, but really it just boils down to specifying minimum and maximum arity to the left and right of the operator, and you can handle very complex structures, but certainly not all.
You probably could extend a precedence parser to handle most languages in their entirety with a relatively small set of rules, but we agree it's probably not worth it. My point is not to try to parse every construct with a precedence parser, but that I've yet to see a grammar that doesn't have the typical highly recursive expression subset of the grammar that a precedence parser is a great fit for, but also that even surrounding that, a precedence parser is often easy enough to extend to a fairly large additional subset of the grammar.
E.g. my Ruby parser handles 26 productions outside the precedence parser and 50 operators (some "synthetic" to handle special parser rules) in the precedence parser.. It'd be easy enough to handle most of the 26 in the precedence parser too, and in fact I've moved more things into the precedence parser than the other way, but some constructs like "class", "if/else/elsif/else/end", "case/when" etc. will probably never get added to it.
> you also need to consider construction of your AST for type checking and execution (which you might not need for your case).
The precedence parser itself does not need to put any limits on the AST construction. In fact, the example I posted explicitly decouple tree construction from the parsing, so you can pass it a builder class that can apply whatever additional constraints you want on the construction of the trees. I don't think the tree construction there would end up typically being any more complex than in a typical recursive descent parser.