C
Charlie Gordon
Keith Thompson said:[...]Charlie Gordon said:Of course, I'm not proposing ** to be a token, but x * *y to be
reinterpreted as fexp(x, y) if y is a numeric type. This trick can be
played on the parse tree if you have one, at code generation time, or on
the
fly if you generate code directly. The programmer would be more inclined
to
write x ** y or x**y, but it is parsed as x * *y. This trick would be
more
difficult to play in an interpreter with dynamic typing, but still
possible,
by sticking the appropriate behaviour to fexp(x, y) for y pointer type.
My gut reaction to this idea is: Ick.
I was expecting this. It was my first reaction too.
If I were designing a new language with a "**" operator, I'd just make
"**" a token. If "*" is also a unary operator, then "x * *y" would
require a space. The kind of special-case treatment you suggest is,
in my opinion, just too convoluted.
It is required for the sake of compatibility with current semantics of
binary * and unary *.
I like the way tokenization and analysis are separated in C. It makes
the language easier to implement and, more importantly, easier to
describe. A more complicated definition might allow "x+++++y" to be
legal, but at the cost of creating odd corner cases that couldn't be
resolved without detailed analysis of the standard.
I like the way tokenization works too. But extending the grammar without
clashes with the current semantics sometimes requires "contorted" ways.
There already are uncanny side effects with the unary * operator: `` x/*p''
does not parse like ''x / *p'' ;-). Javascript extended its C-like syntax
roots to include support for regular expression literals: support for the
/regex/ syntax requires feedback from the grammar into the lexer, but the
programmers need not be aware of this.
And if you're adding extensions to the language, it's not unlikely
that you'd eventually want to add operator overloading. How do you
overload "**" if it' a composite of "*" and "*", and how do you
interpret "x**y" if either interpretation could be correct?
Operator overloading in C++ does not allow redefining operations on scalar
types. It would be acceptable to restrain ** to operate only on types for
which x * (*p) does not have a meaning already.
What would be more surprising and make this idea unworkable is the bizarre
precedence it gives the fake ** operator: ``a*b**c'' would parse and
evaluate as ``(a * b) * (*c)'' effectively making ** less binding than *
(counter-intuitive), but ``a**b*c'' would parse and evaluate as ``(a * (*b))
* c'' making ** more binding than * in this case.
A more consistent proposal is to allow creating new custom operators and
tokens, with specified precedence and associativity, but no built-in
support. This way you keep compatibility with existing code that does not
make use of these 'extended' operators, and give proper support for
extending the syntax and grammar in a consistent and intuitive way. You
need a specific syntax for defining the new operators, preferably at the
preprocessing level:
#operator ** binary left 2.5 /* new token **, binary operator, left
associative, binds more than * / % */
double operator ** (double x, double y) { return fexp(x, y); }