Article about Herb Schildt accepted at comp.risks

B

Ben Bacarisse

Seebs said:
None outside of example programs.

gcc does unless Willem's question was trap. It uses a switch to map
operators to precedence values (rather than an array) but I still call
that a "table of precedence".
This is why I don't think describing parentheses as "increasing precedence"
is accurate.

"Not accurate" is a very strong criticism of the idea but for the sanity
of the group it's probably best to let this pass. There does not seem
to be much to be gained from going round the loop again.
 
S

Seebs

gcc does unless Willem's question was trap. It uses a switch to map
operators to precedence values (rather than an array) but I still call
that a "table of precedence".

Well, shows what I know -- I haven't looked that closely at gcc's source.
(Or at least that part of it.)

But this raises an interesting question: Given that it does, in fact,
map operators to precedence values, does it then implement parentheses by
increasing the precedence of operators? If so, I would be obliged to concede
that the description is in fact accurate. If not, then we have a clear
example of something which really does use precedence, but in which
parentheses do not result in higher precedence.

Looking at it, it looks to be done in YACC, and what it does is:

'(' expr ')'

which is to say, it parses a sub-expression between ( and ), and does not
change the parsing of that expression in any way -- nothing has its precedence
changed, everything continues to have the same precedence.

That fits my expectation of how it would be done. You can't split a (...)
up partway through, so "precedence" is not a good explanation of why
operators inside () are treated like an atom from the point of view of
the containing expression. It's just that (...) is a primary expression,
like an identifier or a constant.
"Not accurate" is a very strong criticism of the idea but for the sanity
of the group it's probably best to let this pass. There does not seem
to be much to be gained from going round the loop again.

At least it's more *topical* than the usual run of pointless arguments. :)

I'm actually being fascinated by this. At this point, I'd say it's pretty
clear that my way of thinking about C expressions is not particularly typical
among the posters here, which leads me to suspect that I should perhaps
think about revising that criticism. I'd been under the impression that
most people who had a good grasp of C would view (...) as a primary
expression, and the question of "precedence" between that and other things
it was in an expression with as irrelevant. Apparently this is not so.

Okay, next question:

foo(1 + 2) * bar(2 + 3)

is the function call "operator" (using the term loosely) raising the
precedence of +, or are the function arguments separate expressions which
don't even participate in a comparison of precedence with the *?

-s
 
B

Ben Bacarisse

Seebs said:
Hmm. Thinking about it, I think it's just the (...) matching -- you
couldn't possibly split a () around anything else without ending up with
mismatched ()s, so obviously they're self-contained, and thus precedence
isn't at issue.

I am often worried by things that are obvious. It is certainly the way
we learn to view ()s but *must* they be treated as indivisible units? I
give an example below of how they might not be.
With something like
a + b * c + d
you COULD split the expression in any of several places -- using "precedence"
to describe how you decide helps, but it doesn't matter; the expression
wouldn't be *incoherent* if you just swapped the precedence around, it'd
just change its value.
Right.

But with
a + (b * c) + d
it would make no sense at all to split this into
a + (b
*
c) + d

Who's suggesting that? This expression has one parse regardless of
which view of parentheses we take.

But there is no mathematical rule that says that expressions must be as
limited as the ones we've grown up with. If you take a deep breath and
embrace the idea that ()s are just about precedence and not about
indivisible units one can image expressions like:

a ((+)) (b * c) ((+)) d

Here the outer ((+)) operators are so "strong" they pull apart the inner
(b * c) expression. Using the parser I posted:

$ ./shunt <<< "a ((+)) (b * c) ((+)) d"
ab+cd+*

and this is not the oddest kind of expression one can imagine.

I am not suggesting such monstrosities be added to C, but it does
illustrate how changing perspective can open up new possibilities.
every now and then these new possibilities do turn out to be useful.
 
W

Willem

Seebs wrote:
) I'm actually being fascinated by this. At this point, I'd say it's pretty
) clear that my way of thinking about C expressions is not particularly typical
) among the posters here, which leads me to suspect that I should perhaps
) think about revising that criticism. I'd been under the impression that
) most people who had a good grasp of C would view (...) as a primary
) expression, and the question of "precedence" between that and other things
) it was in an expression with as irrelevant. Apparently this is not so.

Perhaps you should entertain the possibility that most people see (...) as
a primary expression, just like you do, but are also able to shift their
view and see it as increasing precedence.

You're arguing that 'parentheses increase precedence' is *necessarily*
wrong. Those arguing against you think it has validity as a viewpoint,
not that it is the One True Way.

) Okay, next question:
)
) foo(1 + 2) * bar(2 + 3)
)
) is the function call "operator" (using the term loosely) raising the
) precedence of +, or are the function arguments separate expressions which
) don't even participate in a comparison of precedence with the *?

Both.

Although it's more of a mental leap to see it as increasing precedence:

If you view foo(argument) as equivalent
to 'foo <apply> (argument)', then that becomes:

foo <apply> (1 + 2) * bar <apply> (2 + 3)

And you're back to the previous way of thinking.

NB: the <apply> operator has the highest precedence in this case.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
S

Seebs

Who's suggesting that? This expression has one parse regardless of
which view of parentheses we take.

But precedence is how you determine the binding of operators -- meaning it
is only conceptually relevant when there is a choice of bindings available.
I am not suggesting such monstrosities be added to C, but it does
illustrate how changing perspective can open up new possibilities.
every now and then these new possibilities do turn out to be useful.

Interesting. So, imagining that we had the () around an operator increase
its precedence... Okay, so imagine that:

a (+) b * c
is the same as (existing notation)
(a + b) * c

What, then, happens with:
a (+) b (*) c
?

It seems that's equivalent to
a + (b * c)
but I'm not sure how you'd model it; you have to sort of push the ()s out,
but you have to do it to higher-precedence operators first. Or really model
it as a whole new tier of precedence...

I dunno. This just seems more complicated to me. I am fine with granting
that thinking about () in terms of precedence is interesting, I just don't
think it seems like a good description of what happens. I'm still not quite
sure whether I think it's wrong or just a confusing but apparently equivalent
explanation. It's in the same category, to me, as talking about "the stack";
it can be a good way to explain things, offered as a way of thinking about
things, with the understanding that this is not necessarily the underlying
mechanism.

-s
 
S

Seebs

Perhaps you should entertain the possibility that most people see (...) as
a primary expression, just like you do, but are also able to shift their
view and see it as increasing precedence.

Huh. That's a possibility, I guess. I haven't been able to make sense
of the "increasing precedence" model yet -- I mean, I can do the paperwork
to show that it appears to yield equivalent results, but it doesn't look
like a thing which would happen to me.

I can do the math to show that viewing the solar system as revolving around
the earth, with planets doing epicycles, is a consistent model and produces
the same results as the heliocentric model, but it doesn't seem to me to be
a good model, even if it produces the same results, because it doesn't seem
that it's a good description of what really happens.
You're arguing that 'parentheses increase precedence' is *necessarily*
wrong. Those arguing against you think it has validity as a viewpoint,
not that it is the One True Way.

Fair enough.
) Okay, next question:
)
) foo(1 + 2) * bar(2 + 3)
)
) is the function call "operator" (using the term loosely) raising the
) precedence of +, or are the function arguments separate expressions which
) don't even participate in a comparison of precedence with the *?

Hmm. Interesting.
Although it's more of a mental leap to see it as increasing precedence:
If you view foo(argument) as equivalent
to 'foo <apply> (argument)', then that becomes:
foo <apply> (1 + 2) * bar <apply> (2 + 3)
And you're back to the previous way of thinking.

True. It gets weirder if you add multi-argument functions, though,
because those aren't the same commas that are in the comma operator...

Actually, there I have an actual concrete distinction to draw: Parentheses
really do something that is NOT the same as increasing precedence.

printf("%d\n", (1, 2));

that's not "increasing the precedence" of the comma operator -- without the
(), there ISN'T a comma operator.

So they are doing something that's actually different from just increasing
precedence, and which I can't figure out a way to express within the
increasing-precedence description. They introduce a whole new, separate,
expression context, and until the matching ), nothing can break that
expression, not because of precedence, but because it's a separate parse
of "an expression", and the components of that sub-expression simply aren't
participating in the context of the surrounding expression.

-s
 
B

Ben Bacarisse

Seebs said:
Well, shows what I know -- I haven't looked that closely at gcc's source.
(Or at least that part of it.)

But this raises an interesting question: Given that it does, in fact,
map operators to precedence values, does it then implement parentheses by
increasing the precedence of operators?

Gcc does not do this. I would not have kept that back if it did!
If so, I would be obliged to concede
that the description is in fact accurate. If not, then we have a clear
example of something which really does use precedence, but in which
parentheses do not result in higher precedence.

One among many I would guess. I don't think anyone is arguing that this
idea is common place or widely used in practise; merely that it is an
interesting way to think about expressions.
Looking at it, it looks to be done in YACC, and what it does is:

'(' expr ')'

which is to say, it parses a sub-expression between ( and ), and does not
change the parsing of that expression in any way -- nothing has its precedence
changed, everything continues to have the same precedence.

The source I looked at[1] does not use YACC -- it had a hand-rolled parser.
It seems to be the main trunk (modified a few hours ago) but my CVS foo
is weak.
That fits my expectation of how it would be done. You can't split a (...)
up partway through, so "precedence" is not a good explanation of why
operators inside () are treated like an atom from the point of view of
the containing expression. It's just that (...) is a primary expression,
like an identifier or a constant.

This seems rather circular. Any explanation of parentheses that does
not treat ()s as making an atom is bound to seem like a bad explanation
of why ()s behave like an atom.

But I can see why you are worried. In another post I explain how this
idea of atomic sub-expressions is not set in stone: (...) can be split
apart by surrounding operators, though it needs a more general
expression syntax than is commonly used. It takes some reasoning to be
sure that the usual syntax holds no surprises when interpreted using
alternative view of parentheses.

<snip>
Willem has commented on your last two points in exactly the way I
would have liked to had I his facility with words.

[1] http://gcc.gnu.org/viewcvs/trunk/gcc/c-parser.c?revision=159442&view=markup
 
B

Ben Bacarisse

Seebs said:
But precedence is how you determine the binding of operators -- meaning it
is only conceptually relevant when there is a choice of bindings
available.

Sorry, I don't follow this.

[Big unmarked snip here. Without the example the following reads oddly.]
Interesting. So, imagining that we had the () around an operator increase
its precedence... Okay, so imagine that:

a (+) b * c
is the same as (existing notation)
(a + b) * c

Yes. I gave some other examples in the post where I posted a parser.
What, then, happens with:
a (+) b (*) c
?

It seems that's equivalent to
a + (b * c)

Yup. Other interesting example might be

a (+ b) * c
and
a + b )*( c
but I'm not sure how you'd model it; you have to sort of push the ()s out,
but you have to do it to higher-precedence operators first. Or really model
it as a whole new tier of precedence...

It's a whole new tier. There are all sorts of ways to model this. One
way is to attach to each operator the nesting level and the (normal)
precedence as a pair (n, p) and use this pair as the actual precedence
for the purposes of parsing: the comparison being lexicographical. My
little parser just formed n*100 + p because p was always < 100.

E.g. in 'a (+) b * c' the operators have precedence (1, 1) and (0, 2).
In 'a + b )*( c' they are (0, 1) and (-1, 2).
I dunno. This just seems more complicated to me. I am fine with granting
that thinking about () in terms of precedence is interesting, I just don't
think it seems like a good description of what happens.

What does happen? If the parser uses YACC, the description of "what
happens" takes many pages. If the parse uses another mechanism,
something else happens. I don't think there is one privileged view
of expressions backed up by "what happens".
I'm still not quite
sure whether I think it's wrong or just a confusing but apparently equivalent
explanation. It's in the same category, to me, as talking about "the stack";
it can be a good way to explain things, offered as a way of thinking about
things, with the understanding that this is not necessarily the underlying
mechanism.

I have no argument with that despite disagreeing (for example I don't
find it either wrong or confusing).
 
B

Ben Bacarisse

Seebs said:
True. It gets weirder if you add multi-argument functions, though,
because those aren't the same commas that are in the comma operator...

Actually, there I have an actual concrete distinction to draw: Parentheses
really do something that is NOT the same as increasing precedence.

printf("%d\n", (1, 2));

that's not "increasing the precedence" of the comma operator -- without the
(), there ISN'T a comma operator.

You've extended the claim. No one has said that parentheses *only*
increase the precedence of enclosed operators. They can also alter the
parse of an argument list -- making an expression where there would
otherwise be two arguments.

Imagine your reaction if I cited printf("%d\n", 1, 2) as a counter
example to your view that (...) turns the contents into a primary
expression. Some brackets do, but not all.

<snip>
 
S

Seebs

Sorry, I don't follow this.

Okay, consider:
a + b;
c * d;
Precedence has no involvement in how we determine the values of these two
expressions, because there's no possible choice-of-bindings. Each expression
is self-contained.

But in:
a + b * c;
we see that precedence *does* matter, because it's a way of explaining how
we resolve ambiguity.

In
(a + b) * c;
there is no precedence at issue; there is no ambiguity about how the operators
would bind, and no point at which you have a choice of which of two operators
to handle.
[Big unmarked snip here. Without the example the following reads oddly.]

Sorry, bad habit -- I tend to snip to enough context that you can see
what was going on if you read the previous post, probably.
What does happen? If the parser uses YACC, the description of "what
happens" takes many pages. If the parse uses another mechanism,
something else happens. I don't think there is one privileged view
of expressions backed up by "what happens".

I don't think it takes many pages. What happens is the parser looks
for an "expr" and a following ). That's it; it starts a whole new
expression-parser, and the whole expression thus parsed becomes the
value of the atom.
I have no argument with that despite disagreeing (for example I don't
find it either wrong or confusing).

I'm suspecting that, if I weren't confused by it, I might no longer think
it was wrong, but I've been unable to get it to map correctly onto how C
expressions work yet.

-s
 
S

Seebs

You've extended the claim. No one has said that parentheses *only*
increase the precedence of enclosed operators. They can also alter the
parse of an argument list -- making an expression where there would
otherwise be two arguments.

Ah-hah!

I think that may be where the divergence happened.

I understood the claim in question to be a *definition* of parentheses,
not merely a statement about their effect.
Imagine your reaction if I cited printf("%d\n", 1, 2) as a counter
example to your view that (...) turns the contents into a primary
expression. Some brackets do, but not all.

Ahh, I see. I view fn() as different ()s than (expr). I'm just looking
at () as the thing which (in one way of describing it) groups expressions.
I understood Schildt to be offering a *definition* of (), that it "increases
the precedence of operators". But that definition doesn't explain what
()s do in a context like function argument lists.

I feel somewhat justified in that interpretation. That sentence is the
ENTIRETY of the explanation given. We see (4e, page 57):

The [ ] and ( ) Operators
Parentheses are operators that increase the precedence
of the operations inside them. Square brackets perform
array indexing [...]

There is no further reference to parentheses in this section.
The next reference I see is (4e, page 61):

Spacing and Parentheses

You can add tabs and spaces to expressions to make them
easier to read. For example, the following two expressions
are the same:
x=10/y~(127/x);
x = 10 / y ~(127/x);
Redundant or additional parentheses do not cause errors
or slow down the execution of an expression. You should
use parentheses to clarify the exact order of evaluation,
both for yourself and for others. For example, which of
the following two expressions is easier to read?
x = y/3-34*temp+127;
x = (y/3) - (34*tmp) + 127;

Note: Yes, I'm aware that the first example is uncompileable. I'm
guessing that the ~ was supposed to be a minus sign, but the spacing
suggests that, by the time it was revised, it was clearly understood to be
a tilde, because it's spaced as a unary operator rather than a binary.

Given this, it really seems as though the intent is to offer that explanation
as the complete and exhaustive definition of (), at which point I do feel
comfortable stating that it's wrong.

The term "parenthesis" (or parentheses) does not occur in the index. I
can't find anything which indicates, explains, or suggests that there
is any significance to parentheses other than influencing order of
evaluation. (And note that he does say "order of evaluation" here.)

-s
 
B

Ben Bacarisse

Seebs said:
Ah-hah!

I think that may be where the divergence happened.

I understood the claim in question to be a *definition* of parentheses,
not merely a statement about their effect.

Indeed not. How could it be? Parentheses are used for all sorts of
quite different purposes in C: function calls, parameter lists, casts,
compound literals, declarators... even in some statements. All these
can be thought of "other syntax" with nothing to do with grouping in an
expression.

The "merely a statement about their effect" is polemic! For the
grouping parentheses used in expressions, the claim describes their
effect sufficiently well to be used as a definition. I accept it is not
how they are defined, but it could be.

Reading on, I see that you are still concerned about Schildt's
perfunctory definition of brackets. It has not been my intention to
defend it. If one were to define the meaning of grouping parentheses
this way, one would have to say a whole lot more than Schildt does, and
the effect would be unnecessarily complex.
Ahh, I see. I view fn() as different ()s than (expr). I'm just looking
at () as the thing which (in one way of describing it) groups
expressions.

Yes, so was I.
I understood Schildt to be offering a *definition* of (), that it "increases
the precedence of operators". But that definition doesn't explain what
()s do in a context like function argument lists.

Ah, here is where I see my area of divergence. I was not commenting on
Schildt's statement.

My point was simply that there is another way to look at ()s and that it
is (a) adequate to explain how C's "grouping parentheses" and (b) it is
interesting in its own right in that it permits one to imagine new
expression forms that are normally discounted.
I feel somewhat justified in that interpretation. That sentence is the
ENTIRETY of the explanation given. We see (4e, page 57):

The [ ] and ( ) Operators
Parentheses are operators that increase the precedence
of the operations inside them. Square brackets perform
array indexing [...]

Yuck. I would not describe () as an operator except in the context of
function calls and it does not seem to be those ()s that he is talking
about.

I would never advocate using the notion I've been defending as a way to
explain C's "grouping parentheses" in C book. I was simply defending it
against an apparent wholesale rejection of the notion.
There is no further reference to parentheses in this section.
The next reference I see is (4e, page 61):

Spacing and Parentheses

You can add tabs and spaces to expressions to make them
easier to read. For example, the following two expressions
are the same:
x=10/y~(127/x);
x = 10 / y ~(127/x);
Redundant or additional parentheses do not cause errors
or slow down the execution of an expression. You should
use parentheses to clarify the exact order of
evaluation,

[Oh dear]
both for yourself and for others. For example, which of
the following two expressions is easier to read?
x = y/3-34*temp+127;
x = (y/3) - (34*tmp) + 127;

Note: Yes, I'm aware that the first example is uncompileable. I'm
guessing that the ~ was supposed to be a minus sign, but the spacing
suggests that, by the time it was revised, it was clearly understood to be
a tilde, because it's spaced as a unary operator rather than a binary.

Given this, it really seems as though the intent is to offer that explanation
as the complete and exhaustive definition of (), at which point I do feel
comfortable stating that it's wrong.

When you have said "this is wrong" or "this is confusing" I thought you
were talking about something I'd said. Clearly, the above is confusing
and obviously wrong in many respects, but there is a germ of truth in
the statement about ()s and precedence.
The term "parenthesis" (or parentheses) does not occur in the index. I
can't find anything which indicates, explains, or suggests that there
is any significance to parentheses other than influencing order of
evaluation. (And note that he does say "order of evaluation" here.)

Yes, I saw that.

I had forgotten that this all started because of a statement in C:TCR.
That might explain the strength of your opposition to what I thought of
as an uncontentious observation: that ()s can be seen as syntax whose
role is to alter the precedence relationship between operators rather
than as syntax to group sub-expressions. I saw this exchange as
off-topic because I was not talking about any application of the idea to
understanding or parsing C expressions (specifically) whereas I think
you may have been thinking of it as an extended commentary on Schildt's
remark.
 
B

Ben Bacarisse

Seebs said:
Okay, consider:
a + b;
c * d;
Precedence has no involvement in how we determine the values of these two
expressions, because there's no possible choice-of-bindings. Each expression
is self-contained.

But in:
a + b * c;
we see that precedence *does* matter, because it's a way of explaining how
we resolve ambiguity.

In
(a + b) * c;
there is no precedence at issue; there is no ambiguity about how the operators
would bind, and no point at which you have a choice of which of two operators
to handle.

OK, I see what you mean. In all sane interpretations of what can be a
valid expression, I agree. But also like to consider insane
interpretations, and there is an entirely logical view of what an
expression means in which a operator can have binding so strong it
breaks into neighbouring parentheses. Hence my example of

(a + b) ((*)) c.


I don't think I explained myself very well here so I'll snip and address
this point again.

I was not suggesting it was a good description of what happens. But what
happens during a parse is not obviously the best way to explain
something like ()s. And if a parser did it this peculiar way, that
would not necessarily be a reason to use it as an explanation. In other
words I am not keen on an appeal to "what happens" either way.

I am fine with granting that it's not the first explanation I'd reach
for. I might use it as an alternative if someone seemed to be having
trouble, but that's unlikely. Almost everyone will be so familiar with
()s from basic arithmetic that the only explanation needed will be one
about binding vs. order of evaluation so as to unlearn the idea that
higher precedence operators and grouped expressions "happen first".

I'm suspecting that, if I weren't confused by it, I might no longer think
it was wrong, but I've been unable to get it to map correctly onto how C
expressions work yet.

Would your last sentence still be true if you deleted the words "how"
and "work"? In other words, is your problem with it primarily due to
what you know about how one or more C compilers parse expression, or it
with the meaning it gives to expressions independently of how they are
parsed?
 
S

Seebs

Indeed not. How could it be? Parentheses are used for all sorts of
quite different purposes in C: function calls, parameter lists, casts,
compound literals, declarators... even in some statements. All these
can be thought of "other syntax" with nothing to do with grouping in an
expression.

Yes, I just meant the () "operator".
My point was simply that there is another way to look at ()s and that it
is (a) adequate to explain how C's "grouping parentheses" and (b) it is
interesting in its own right in that it permits one to imagine new
expression forms that are normally discounted.

Hmm. I think it's not quite adequate to explain the grouping parentheses,
because there are cases in which it has effects beyond merely changing
grouping, but I can see it as a viable approximation.

Which brings me back to: The single-sentence description by Schildt is,
IMHO, "incorrect" -- it is not an accurate description. As a part of a
longer explanation, offered as a description of the net effect, I can see
how it would be useful.
I would never advocate using the notion I've been defending as a way to
explain C's "grouping parentheses" in C book. I was simply defending it
against an apparent wholesale rejection of the notion.

Ahh, I see.
When you have said "this is wrong" or "this is confusing" I thought you
were talking about something I'd said. Clearly, the above is confusing
and obviously wrong in many respects, but there is a germ of truth in
the statement about ()s and precedence.

Ahhh!

Okay, yeah. I was just arguing that Schildt's explanation is "wrong" -- as
in, if you read that explanation, you do not come away from it with an
accurate understanding of how grouping () work in expressions.

So, to summarize... False:
Parentheses are an operator which increase the precedence of
the operations within them.

True:
Parentheses can be used to group an expression, preventing the
normal precedence and associativity rules from changing the
interpretation of that expression when it is used in conjunction
with other operators. For instance, normally in C, the expression
"1 + 2 * 3" evaluates to 7, because the multiplication expression
is understood to be an operand to the addition operator; one way
to describe this is that multiplication has "higher precedence" than
addition. By contrast, "(1 + 2) * 3" evaluates to 9 because the
parentheses ensure that 3 is multiplied by the result of adding 1
and 2. In effect, parentheses raise the precedence of the operators
within them, so that the operands within the parentheses always
bind to those operators, rather than to operators outside the
parentheses.

(... true, I think, but badly phrased. Maybe I should try again
after breakfast.)
I had forgotten that this all started because of a statement in C:TCR.
That might explain the strength of your opposition to what I thought of
as an uncontentious observation: that ()s can be seen as syntax whose
role is to alter the precedence relationship between operators rather
than as syntax to group sub-expressions. I saw this exchange as
off-topic because I was not talking about any application of the idea to
understanding or parsing C expressions (specifically) whereas I think
you may have been thinking of it as an extended commentary on Schildt's
remark.

Yes, that would do it. I was thinking of it as a discussion, not of the
general habit of using () to group things in expressions, but specifically
of the expression-grouping () in C.

Thanks for sticking with this, I was pretty concerned because usually if
I disagree with you, it implies that I'm missing something significant.
It turns out, I think, to have been context.

-s
 
S

Seebs

Would your last sentence still be true if you deleted the words "how"
and "work"? In other words, is your problem with it primarily due to
what you know about how one or more C compilers parse expression, or it
with the meaning it gives to expressions independently of how they are
parsed?

I think the latter. It seems very significant to me to note that grouping
() really do introduce a whole new expression context, which is in some
ways different from merely changing precedence. (e.g., the ability to use
comma operators in function arguments -- not that I think that should come
up much). I think it may be a fair description of all the cases in which
the expression has otherwise the same set of operators and operands --
so, say, not including cases like , in function call argument lists. I'm
not sure, though, and it just feels like it's missing the point.

But then, to me, "separate expression" is easier to understand than precedence
to begin with. So I may just be having a hard time mapping things to
precedence.

-s
 
B

Ben Bacarisse

Seebs said:
I think the latter. It seems very significant to me to note that grouping
() really do introduce a whole new expression context, which is in some
ways different from merely changing precedence. (e.g., the ability to use
comma operators in function arguments -- not that I think that should come
up much). I think it may be a fair description of all the cases in which
the expression has otherwise the same set of operators and operands --
so, say, not including cases like , in function call argument lists. I'm
not sure, though, and it just feels like it's missing the point.

I am pretty sure the function argument case is a red herring: because C
has (at least) 2 meanings for ',' you are forced to use a mechanism
designed for one purpose to achieve another.

That case does, perhaps, point to an area of difference that might clear
things up. The "()s alter the precedence" idea is intended (at least be
me) as an alternate view of the meaning of an expression. It is not
intended to describe or replace the syntax of the language. In other
words, '1,2' is an expression in some cases and not in others, and these
cases must be decided by something else -- the parser. Having decided
that we have an expression, its meaning can be explained in several ways
-- one of which you don't much like!

I think the reason you don't like it is that it only does half the job.
The grammar of C induces, on any syntactically correct text, a parse
tree that describes both what is and is not an expression *and* what
the operands of every operator are (i.e. their binding). In that sense
there is no competition, but then I was not putting one up against the
other.

<snip>
 
S

spinoza1111

Sorry, I don't follow this.

Okay, consider:
        a + b;
        c * d;
Precedence has no involvement in how we determine the values of these two
expressions, because there's no possible choice-of-bindings.  Each expression
is self-contained.

But in:
        a + b * c;
we see that precedence *does* matter, because it's a way of explaining how
we resolve ambiguity.

In
        (a + b) * c;
there is no precedence at issue; there is no ambiguity about how the operators
would bind, and no point at which you have a choice of which of two operators
to handle.
[Big unmarked snip here.  Without the example the following reads oddly.]

Sorry, bad habit -- I tend to snip to enough context that you can see
what was going on if you read the previous post, probably.
What does happen?  If the parser uses YACC, the description of "what
happens" takes many pages.  If the parse uses another mechanism,
something else happens.  I don't think there is one privileged view
of expressions backed up by "what happens".

I don't think it takes many pages.  What happens is the parser looks
for an "expr" and a following ).  That's it; it starts a whole new
expression-parser, and the whole expression thus parsed becomes the
value of the atom.
I have no argument with that despite disagreeing (for example I don't
find it either wrong or confusing).

I'm suspecting that, if I weren't confused by it, I might no longer think
it was wrong, but I've been unable to get it to map correctly onto how C
expressions work yet.

You were completely unqualified to comment on Schildt because, unlike
him, you had neither taken a computer science class nor written even a
simple parser, and this is why you waste our time in metaphysical
speculation.

How does the parser "look for an expression followed by a )". You do
not know.

Hint: a bottom up parser would look at longer and longer strings to
see if they are expressions and lookahead to find a right parenthesis.
A simple recursive descent (top down) parser would look ahead to find
a balanced right parenthesis and pass the string between the LP and RP
to a "new" parser (a recursive call of the parser routine that looks
for an expression.

This is because when what you call an "atom" is defined in a formal
grammar one of its definitions is "an expression in parentheses".

You waste our time with babbling. Why don't you just go and take a
compiler design class at the undergraduate level at your local
university? They will probably allow you in since you have experience
even though you might have some trouble.

Being able to write a small interpretive compiler separates the men
from the boys. Herb did so in 1989: you have not. But you have the
utter nerve to dismiss his compiler because it was an interpreter and
to describe problems as "first level computer science" when you, by
your own admission, haven't taken any comp sci classes at the
university level.

Write a CALCULATOR. Parse simple mathematical expressions. It will
clear up your confusion as to why Herb uses the notion of "stack" as a
given.
 
D

David Thompson

On Mon, 10 May 2010 11:56:29 -0700 (PDT), John Bode
There is an agreed-upon definition of how the language is *supposed*
to work; that is the language standard. Most implementations conform
closely to this standard, some moreso than others. There is some slop
around the edges due to limitations in the implementation environment
or mistakes on the part of the implementor, but on the whole a
conforming compiler *should* accept a conforming program and reject a
non-conforming program.
Not quite. First, a nit: the term 'conforming program' is defined by
the standard in a way that is useless, knowingly so, and 'strictly
conforming' is almost as bad. We've had several tries seeking a term
for the (useful!) category of programs that portably work correctly,
and the least bad IMO was 'clc-compliant'.

More substantively: modulo bugs a conforming implementation should
accept *and correctly execute* a clc-compliant program *unless it's
too big* -- and then as Quality of Implementation it should give an
appropriate diagnostic, although the standard doesn't require it.

On the other side, it must diagnose any program with a syntax error or
constraint violation, but it is permitted to try to 'fix' such program
into a valid and if lucky desired one. And it can have extensions that
users intend and want, but mandate diagnosis in conforming mode.
And it *may* diagnose other errors, but in general there are many
errors that are not practical to detect and thus cannot be rejected.

IOW I agree with 'accept' mostly but 'reject' mostly not

<snip rest>
 
D

David Thompson

the standard doesn't describe [grouping] parentheses as operators.
But it could have done so, with no real change in meaning.
(Think of them as "unary outfix", if that's a word.)
The traditional term for such is or at least was 'matchfix'.
 
B

Bruce C. Baker

[snip usual festering effluvium]

'Round and 'round and 'round he goes
Backing Schildt is all he knows
Bye bye Nilges

Spewing insults snide and vile
Interlaced with Marxist bile
Bye bye Nilges

No one here attends to what you're saying
They just hear a small sad jackass braying
Can't get past your hate for C
Poor pathetic wannabe
Nilges, bye bye
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,085
Messages
2,570,597
Members
47,218
Latest member
GracieDebo

Latest Threads

Top