What kind of operator is ( ), [ ] ? unary or binary ?

A

Anoob

Can we consider () unary operator when calling a function, in exps eq.
f(), ( 1 + 2). But when we call function f( 10 ) it is a binary
operator. Even if we pass f( 10, 20) as we are using , operator there
one operand will be there for ()?

And Unary operators like !, +, -, ~, ... are said to be having
associativity right to left which means that we can write, (but not
allowed)
1. 2!
2. !2
As an explanation can we say. in the first case as ! is not having a
left operand it will take right operand and will be associated with
that. where as in the second case it will be assosiated with left
itself.

But the case 1. is not allowed. Then what is the neccessity for saying
the associativiy from right to left it is always associated with right
?
if wrong can anyone explain what exactly does associativity means?
 
C

CBFalconer

Anoob said:
Can we consider () unary operator when calling a function, in exps eq.
f(), ( 1 + 2). But when we call function f( 10 ) it is a binary
operator. Even if we pass f( 10, 20) as we are using , operator there
one operand will be there for ()?

The comma is NOT a comma operator in parameter lists. This sort of
reuse of punctuation is one of the "beauties" of C.
 
D

Dan Pop

In said:
The comma is NOT a comma operator in parameter lists. This sort of
reuse of punctuation is one of the "beauties" of C.

You can find them in Fortran, too. Is A(2, 3) a function call or an
array element?

Dan
 
C

Chris Torek

Can we consider () unary operator when calling a function ...

No. Or rather, you can consider anything you like to be anything
else you like, but that will not make it so. :) The parentheses
used in function calls are merely "syntax", not "operators", in
the jargon[%] used by compiler-writers to communicate with other
compiler-writers.
-----
[%] "Jargon", in this case, means a specialized subset of English
as used in a technical field. In law, for instance, the word
"whereas" has a special jargon-ized meaning. Medicine is full of
jargon, some of which has been popularized by TV shows: most people
know that "stat" means "right now", for instance. Here, I am going
to use the words "precedence" and "associativity", which are both
computer-science (CS) jargon, and also "parse" and "grammar", which
are CS jargon adopted from English-grammar jargon.
-----
And Unary operators like !, +, -, ~, ... are said to be having
associativity right to left ...

Unary operators do not need associativity. Some people may say
they have it, but this is usually shorthand for something else.

C's formal specification (either one, C89 or C99) has *neither*
precedence *nor* associativity. It uses a fully factored grammar
in which ambiguous parses are impossible. This is, however,
isomorphic to other grammars that *do* allow ambiguous parses, in
which the ambiguity is resolved by "precedence and associativity".

Consider the expression:

a - b * c + d

In C, this "means" the same thing as:

(a - (b * c)) + d

which is quite different from:

a - (b * (c + d))

But how are we supposed to *know* that the b*c binds the most
tightly, and then the a-(result) and (result)+d bindings should
happen?

The C standards (C89 and C99 both) make sure we come up with the
correct bindings by laborious effort. The grammar includes these
bits:

multiplicative-expr:
cast-expr
multiplicative-expr * cast-expr
multiplicative-expr / cast-expr
multiplicative-expr % cast-expr

additive-expr:
multiplicative-expr
additive-expr + multiplicative-expr
additive-expr - multiplicative-expr

...

expression:
assignment-expr
expression , assignment-expr

(and let me just claim without support that each of a, b, c, and
d are eventually allowed by "cast-expr", and that assignment-expr
eventually includes additive-expr).

To parse the entire expression as an "expression", we have to find
some way for

a - b * c + d

to be allowed by this grammar. That is, the whole thing has to
be an "expression", which can be an "assignment-expr", and an
assignment-expr can be an additive-expr.

While "a" is (through a long chain) a valid "cast-expr", "a - b"
is *not* a valid cast-expr, so it is not a multiplicative-expr
either. This means that "a - b" *cannot* be the left hand side
(LHS) of a multiplicative-expr. But note that "a" *can* be the
*entirety* of a multiplicative-expr, and an additive-expr can
consist entirely of a multiplicative-expr. Similarly, an additive-expr
can consist of a multiplicative-expr on the right-hand-side (RHS)
of the sequence "additive-expr - multiplicative-expr" (because the
LHS multiplicative-expr is allowed as an additive-expr, even though
an additive-expr is not allowed as a multiplicative-expr).

Now, b*c is of course a valid multiplicative-expr, and if we match
"a - b*c" up against the rule:

additive-expr:
additive-expr - multiplicative-expr

and make the first "a" the additive-expr and b*c the multiplicative-expr,
it all works, so this whole thing is itself an additive-expr. This
allows us to collect it all up into one bound-up group, calling
that an "additive-expr"; and now we can use that as the LHS of:

additive-expr:
additive-expr + multiplicative-expr

where "d" is the multiplicative-expr.

If you have managed to follow all that, you should see that we
have gotten this as our final "parse tree":

+
/ \
- d
/ \
a *
/ \
b c

Parsing is all about getting the right parse tree, and the C89 and
C99 standards both use a fully-factored grammar to make sure that
you can *only* get *one* parse tree for any valid expression. There
are two problems with such grammars, though:

- they are painful for people to use, compared to operator-precedence
grammars; and
- they are less efficient in automated parser-generators (like
yacc and bison) than operator-precedence grammars.

In an operator-precedence grammar, we just describe the syntax for
an "expression" giving *all* the possible operators, e.g.:

expr:
variable-name
expr + expr
expr - expr
expr * expr
expr / expr

But this means we have "ambiguous parses": a + b * c (with or without
the "- d" on the end) can be (a + b)-as-an-expr * c-as-an-expr, or
a-as-an-expr + (b * c)-as-an-expr. So we throw in a new concept
called "precedence", and say that * and / "have precedence" over +
and -, meaning you should bind b*c more tightly than a+(result), to
make sure you get the right parse tree.

Precedence fixes the "bind multiply before binding add" problem,
but does not tell you how to resolve expressions like e-f-g: is
that (e-f)-g, or is that e-(f-g)? Do you bind the left "-" first
or the right "-"? They have the same operator-precedence, so this
does not help. So now we throw in yet another concept, "associativity",
and say that "-" is left-associative so that we bind the left "-"
first, giving (e-f)-g.

Again, this is easier for *people* (and to some extent, nicer in
yacc and bison as well), but it is just a way to make sure that we
get the right parse tree. A computer *can* use a fully-factored
grammar instead, and the C standards do.

*All* of this is *just* used to build a parse tree. It does not,
I repeat DOES NOT, control actual run-time order of evaluation. To
see that "order of evaluation" is a separate issue, consider a C
source line that says:

sum = f() + g();

where functions f() and g() both print a line to stdout showing that
they have run:

int f(void) { puts("f() called"); return 17; }
int g(void) { puts("g() called"); return 25; }

When you run a program that uses f()+g(), one of the two will get
called first, then the other -- and nobody says which one will
happen first, and this is up to the compiler -- but there is no
precedence and no associativity needed to figure out how to parse
a simple "x + y" addition. Since we have "runtime order of
evaluation" with no "precedence", they *must* be separate things.
... can anyone explain what exactly does associativity means?

Here is the executive-summary version:

- The C standards do not use an operator-precedence grammar, but
*you* can, if you prefer.

- If you *do* use an operator-precedence grammar, you will need
to remember which operators "have precedence" over the others, and
use that to resolve parse ambiguities. After using precedence,
if (and ONLY if) there are still more ambiguities, you will need
to remember the "associativity" of the remaining ambiguous
operators, and use that to resolve them.

- Precedence and associativity DO NOT control run-time order of
evaluation. They only affect the compile-time parse tree. The
parse tree will usually have some sort of "partial order" effect
on runtime code, but to get *guaranteed* runtime sequencing, you
have to use C's "sequence points".
 
J

Joe Wright

Dan said:
You can find them in Fortran, too. Is A(2, 3) a function call or an
array element?

Dan

In FoxPro, assuming A an array, A(2,3), A[2,3] and A[2][3] are
identical. If A is a function, only the A(2,3) would work. Simply
looking at its invocation won't tell you whether array or function.
If A is a function, you can also call it with 'do A with 1, 2'.

How do I get this back 'On Topic'? Oh yeah, the "beauty" of the
'static' keyword in C. Who says we don't have overloading here?
 
E

Erik de Castro Lopo

Anoob said:
Can we consider () unary operator when calling a function, in exps eq.
f(), ( 1 + 2).

In C the above like is equvalent to:

f () ;
1 + 2 ;

In C there are not () or [] operators. You are thinking of C++ which has
its own newsgroups.

Erik
--
+-----------------------------------------------------------+
Erik de Castro Lopo (e-mail address removed) (Yes it's valid)
+-----------------------------------------------------------+
"Having a firewall that allows NFS to the Internet is like having a
seat belt that lets your head touch the dashboard." -- Marcus Ranum
 
L

Lawrence Kirby

Can we consider () unary operator when calling a function, in exps eq.
f(), ( 1 + 2). But when we call function f( 10 ) it is a binary
operator. Even if we pass f( 10, 20) as we are using , operator there
one operand will be there for ()?

The function call operator can take a different number of operands,
although the operands within the parentheses are more commonly called
arguments. The , is part of the function call operator syntax, and has
nothing to do with the comma operator.

The comma operator evaluates its first operand, discards the result,
evaluates the second and uses the result of that as its result. That
clearly isn't happening in the function call.
And Unary operators like !, +, -, ~, ... are said to be having
associativity right to left which means that we can write, (but not
allowed)
1. 2!
2. !2

Associativity has nothing to do with whether you write the operator before
or after its argument. The syntax specification of ! says it must be
written before, so that's where it must go.
As an explanation can we say. in the first case as ! is not having a
left operand it will take right operand and will be associated with
that. where as in the second case it will be assosiated with left
itself.

That is not what associativity means. Take the expression *p++. The
subexpression p could be associated with either the operator on its left
giving (*p)++ or the operator on its right giving *(p++). When these
operators are described as right associative it means that the operand
associates with the operator on its right in cases like this so *p++ is
equivalent to *(p++). Operators with the same precedence level must have
the same associativity.

Similarly 2 - 3 - 4 could be parsed as (2 - 3) - 4 or 2 - (3 - 4) i.e. the
3 could associate with the - on its left or the one on its right. Because
- is (or can be described as) left associative it is bound to the - on its
left and (2 - 3) - 4 is the equivalent expression.
But the case 1. is not allowed. Then what is the neccessity for saying
the associativiy from right to left it is always associated with right
?
if wrong can anyone explain what exactly does associativity means?

Precedence and associlativity are one (there are others) means of
specifying how an expression is to be parsed when there is more than one
possibility. Consider *++p . The only way this can be parsed is as *(++p),
nothing else, e.g. (*++)p, makes sense. Since there is no ambiguity
precedence/associativity rules are not applicable here.

Lawrence
 
D

Dan Pop

In said:
In C there are not () or [] operators.

You may want to open your copy of K&R2 at page 53 before making such
(foolish) statements. Or, if you prefer the C standard:

6.5.2 Postfix operators
^^^^^^^^^
Syntax

1 postfix-expression:
primary-expression
postfix-expression [ expression ]
^ ^
postfix-expression ( argument-expression-list-opt )
^ ^
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
( type-name ) { initializer-list }
( type-name ) { initializer-list , }

Dan
 
D

Dan Pop

In said:
() is an operator, for both casts and function calls.

To avoid confusion, it is usually written as "(type)" when referring to
the cast operator.

Dan
 
L

Lawrence Kirby

No it's not.

The standard doesn't explicitly call it an operator, but it is perfectly
reasonable to consider it as such. It can be described as an operator that
takes one operand and uses the result of that operand as its own result,
preserving properties of lvalue etc. This is how the standard defines
grouping ()'s, barring explicit use of the term "operator", smells like an
operator to me.

If you think of it this way there's no need to treat parentheses like this
as anything different or special, the "grouping" properties just fall out
of the syntax as they do with other operators. E.g. in a[p + 1] the p + 1
subexpression is evaluates first.

Lawrence
 
C

Chris Torek

[Note: topic drift.]

If you think of it this way there's no need to treat parentheses like this
as anything different or special, the "grouping" properties just fall out
of the syntax as they do with other operators. E.g. in a[p + 1] the p + 1
subexpression is evaluates first.

Well, "grouped first" anyway; the usual caveats apply to runtime
order of evaluation.

I think it is better, from a compiler-writer's perspective at least,
not to consider parentheses for grouping as "operators" but rather
as just "syntax". The same applies (as I said earlier in the
thread) to those in function calls. There *is* a "function-call
operator" (which is not monadic, dyadic, etc., but rather something
"semi-dynamically determined", again from the syntax, in C) but it
does not use any characters at all. If one thinks of it this way,
it always has at least one operand, that being a pointer to the
function to call:

f(1, 2, 3)

is a 4-adic call, with the "tree" being:

[call]
/ | | \
f 1 2 3

Other operators are specifically unary or binary (same as "monadic"
and "dyadic" -- one finds these latter terms in APL, and the former
in traditional compiler grammars), or in the case of a?b:c, "trinary".

Of course, in many C compilers, trinary (or more) operations tend
to be represented with binary trees rather than trinary -- instead
of:

? :
/ | \
a b c

we have:

?
/ \
a :
/ \
b c

GCC's RTL expressions use, internally, something strongly resembling
Lisp lists (albeit implemented as "vectors" or "hunks" rather than
cons nodes), so GCC is a bit unusual here -- it really does have
a three-operand ?: node. GCC dumps these as textual S-expressions,
which are good -- or at least well-known and easily-understood --
ways to represent such lists.

The reason I mention all this is that it is important to understand
that these are all "mere" syntax notions -- there is nothing
*fundamentally* different between:

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

and:

a + b * c + d /* C and similar languages */

or even:

a b c * + d +

(RPN, as found in various HP calculators, or used in Postscript or
Forth). These expressions all have the same meaning (in at least
some sense -- i.e., the mathematical operations expressed are the
same), despite the different syntax. Only when a given language
-- in our case, C -- adds special semantics to particular syntactic
construct does the syntax "really matter", in some deeper way than
"mere appearance" anyway.

Thus, in C, "f() && g()" really *is* special, because the && operator
not only does a boolean "AND", but *also* has sequence point
semantics, forcing f() to run first and g() not to run at all if
f() returns 0. But this is not "because && is an operator" --
operator-ness is not really significant. Nor is it "because it is
two characters long": the comma operator also imposes a sequence
point, but is only one character. The special-ness comes from the
requirements in the standard. Syntax is just one of many ways
to express such requirements.
 
P

pete

Lawrence said:
The standard doesn't explicitly call it an operator,

The standard explicitly calls it a punctuator.
but it is perfectly reasonable to consider it as such.
It can be described as an operator that
takes one operand and uses the result of that operand as
its own result, preserving properties of lvalue etc.
This is how the standard defines grouping ()'s,
barring explicit use of the term "operator", smells like an
operator to me.

OK.
 
L

Lawrence Kirby

The standard explicitly calls it a punctuator.

The standard also call things like & * and ! punctuators. C99 6.4.6
Punctuators says:

"A punctuator is a symbol that has independent syntactic and semantic
significance. Depending in context, it may specify an operation to be
performed (which may in turn yield a value or a function designator,
produce a side-effect, or some combination thereof) in which case it is
known as an /operator/ (other forms of operator also exist in some
contexts). An /operand/ is an entity on which an operator acts."

/word/ represents italic and in the standard this indicates the definition
of that term. So:

a punctuator can also be an operator.

This clause defines the terms operator and operand. The (expr) syntax
evaluates expr and yields a value so it appears that by the standard's
definition it is an operator.

Lawrence
 

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

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top