3 ms·
This is mostly an issue with C++ specifically. If you implement the lexer hack[1], C can be parsed using an otherwise context-free grammar. C++ suffers from re
by trealira 3y ago
This is mostly an issue with C++ specifically. If you implement the lexer hack[1], C can be parsed using an otherwise context-free grammar.
C++ suffers from requiring arbitrary tokens of lookahead before being able to determine whether something is a declaration or an expression statement, which is a consequence of the combination of C-style declarations, function-like casts, and function-like constructors.
For example, here, the parser cannot know whether the variables x, y, and z are being redeclared in the same scope, or if they're being evaluated and discarded, until it reaches the "new int" part. Last time I tested it, clang++ parsed it correctly, but not g++.
int x, *y, *z;
{
int(x), *y, z, new int;
}
In C++, "int(x)" is equivalent to "(int) x" (and this doesn't exist in C), but as a holdover from C, it also allows redundant parentheses in declarations, so one could also just redeclare x in a new scope like this (in both C and C++):
double x;
{
int(x); /* x is an int now */
x = 5;
}
I think this is a variant of the most vexing parse[2], which your lock guard example also sounds like an example of.
You probably already know about this, but I was surprised by that example even knowing that C++ requires arbitrary tokens of lookahead to parse correctly, because I had only seen the Timekeeper example from Wikipedia.
There's also the problem that it can't parse something like this unless it knows whether it's supposed to be a template instantiation or an expression statement, but I think that's just an extension of the typename/variable problem that it inherited from C.
a < b, c > d;
[1]: https://en.wikipedia.org/wiki/Lexer_hack https://en.wikipedia.org/wiki/Lexer_hack
[2]: https://en.wikipedia.org/wiki/Most_vexing_parse https://en.wikipedia.org/wiki/Most_vexing_parse