Академический Документы
Профессиональный Документы
Культура Документы
Introduction
• Expressions are the fundamental means of specifying computations in a programming language
• To understand expression evaluation, need to be familiar with the orders of operator and operand
evaluation
• Essence of imperative languages is dominant role of assignment statements
• The purpose of an assignment statement is to change the value of a variable.
Arithmetic Expressions
• Arithmetic evaluation was one of the motivations for the development of the first programming
languages
• Arithmetic expressions consist of operators, operands, parentheses, and function calls
Arithmetic Expressions: Design Issues
• Design issues for arithmetic expressions
– operator precedence rules
– operator associativity rules
– order of operand evaluation
– operand evaluation side effects
– operator overloading
– mode mixing expressions
Arithmetic Expressions: Operators
• A unary operator has one operand
• A Unary addition is called the identity operator, has no affect of its operand. In Java, unary
plus or minus actually does have an effect when its operand is short or byte, it causes an implicit
conversion of that operand to int type.
• Unary minus operator can appear at the beginning or anywhere, as long as it is parenthesized.
Ex: A+(-B) *C
• A binary operator has two operands. (Infix in most languages, prefix in some operators of
Perl).
• A ternary operator has three operands ? : , included in the C-based languages.
Arithmetic Expressions: Operator Precedence Rules
• The operator precedence rules for expression evaluation define the order in which “adjacent”
operators of different precedence levels are evaluated
• Typical precedence levels
– parentheses
– unary operators
– ** (if the language supports it)
– *, /
– +, -
• The precedence of the arithmetic operators of a few common programming languages are as
follows: (sorted from the highest to the lowest)
Fortran C-based Ada
** Postfix ++, -- **, abs
*, / Prefix ++, --, unary +, - *, /, mod, rem
All +, - *, /, % Unary +, -
Binary +, -
Binary +, - Binary +, -
• The (**) operator is exponentiation. The (%) operator of C is exactly like the (rem) of Ada, it
takes two integer operands and yield the reminder of 1st divided by 2nd.
• The Ada (mod) operator is identical to (rem) when both operands are positive, but can be
different when one or both are negative.
• The (abs) od Ada is a unary operator that yields the absolute value of its operand.
Arithmetic Expressions: Operator Associativity Rule
1
• The operator associativity rules for expression evaluation define the order in which adjacent
operators with the same precedence level are evaluated
• Typical associativity rules
– Left to right, except **, which is right to left
– Sometimes unary operators associate right to left (e.g., in FORTRAN) A**B**C. The right
operator is evaluated 1st.
– In Ada, exponentiation is non associative, which means that the expression A**B**C is illegal.
The expression must be parenthesized to show the desired order. (A**B)**C or A**(B**C)
– In VB the exponentiation (^) is left associative.
– Fortran unary and binary minus operators have the same precedence, but in Ada and most other
common languages, unary minus have precedence over binary minus.
-A-B (-A) –B
Consider the following –A/B , -A*B The relative precedence of the unary minus and binary
operators are irrelevant. i.e. the order of evalustion of the two operators has no effect on the
value of the expression.
But, -A**B, has an effect. Fortran, VB and Ada are the oly languages exponentiation operator.In
these languages the exponentiation has higher precedence over unary minus. So, -A**B -
(A**B)
If the unary operator appears at positions other than at the left of the expression, it must be
parenthesized, in order to give it highest precedence.
There is one situation where the precedence of a unary operator can be confusing. N Ada, the
precedence of unary minus is lower than that of (mod),so expression -17 mod 5 is equivalent to
–(17 mod 5) which evaluated to -2, rather than 3, which would be the result if unary minus had
higher precedence than (mod), as it does in C-based languages. (A mod B= (A+k*B) mod B)
– Associativity rules for some imperative languages
Language Associativity rules
Fortran Left: *, /, +, -
Right: **
C-based Left: *, /, %, binary +, binary –
Right: ++, --, unary -,
unary +
Ada Left: all except **
Nonassociative **
• APL is different; all operators have equal precedence and all operators associate right to left
A*B+C if A=3, B=4, C=5, then value =27
• Precedence and associativity rules can be overriden with parentheses. Ex: (A+B)*C
Arithmetic Expressions: Conditional Expressions
• Conditional Expressions (?:) ternary operator
– C-based languages (e.g., C, C++) expression_1? expression_2: expression_3
– An example:
average = (count == 0)? 0 : sum / count
– Evaluates as if written like
if (count == 0) average = 0
else average = sum /count
2
• Functional side effects: occurs when a function changes a two-way parameter or a non-local
variable (non-local is a global variable declared outside the function but is accessible in the
function).
• Consider the expression a+fun(a) if fun does not have the side effect of changing a, then the
order of evaluation of the two operands, a and fun(a), has no effect on the value of the expression.
• If fun changes a, there I an effect.
• Ex: suppose fun returns the value of its argument divided by 2, and changes the value of its
parameter to 20.
Suppose we have the following:
a=10;
b=a+fun(a);
if the value of a is fetched first (in the expression evaluation process), its value is 10 and the value
of the expression is 15. But if the 2nd operand is evaluated 1st, then the value of the first operand is
20 (because it is changed by the function), and the value of the expression is 25.
Consider the following C program which illustrates the same problem when a function changes a
global variable that appears in expression.
i na = t5 /; / g l o b a l
i n f ut n) 1 (
The value computed for a in fun2
{ a= 1 7 ; depends on the order of evaluation of the
operands in the expression a+fun1( ) .
r e 3t u} ;/ r/e nno fd u n 1 the value of a will be either 8 or 20.
v o f ui d n) 2 (
{ a = a + f u n) ;}1/ e/( no df u n 2
v om i da) i n (
{ f u n) ;}2 / (/e no mdf a i n
Functional Side Effects
• Two possible solutions to the problem of operand evaluation order.
1. Write the language definition to disallow functional side effects
• No two-way parameters in functions
• No non-local references in functions
• Advantage: it works!
• Disadvantage: inflexibility of two-way parameters and non-local references
• Consider the case of C and C++, which have only functions.
• To eliminate the side effects of two-way parameters and still provide
subprograms that return more than one value, a new subprogram type that is similar
to the procedures of the other imperative languages would be required.
• When efficiency is important, using access to global variables to avoid
parameter passing is an important method of increasing execution speed. Ex: In
compilers, access to data such as the symbol table is commonplace.
2. Write the language definition to demand that operand evaluation order be fixed
• Disadvantage: limits some compiler optimizations
• In Java language definition guarantees that operands appear to be evaluated in
left-to-right order, eliminating the problem of side effects.
Overloaded Operators
• Use of an operator for more than one purpose is called operator overloading
• Some are common (e.g., + for int and float Java use it for string catenation. It is accessible, as
long as readability and reliability are not suffer)).
3
• Some are potential trouble (e.g., * in C and C++, & if it is binary operator, specifies a
bitwise logical AND operation. As a unary operator with a variable as its operand, means
address of that variable (address-of-operator)).
– Loss of compiler error detection (omission of an operand should be a detectable
error). Ex: simple keying error of leaving out 1st operand for a bitwise AND operation can
go undetected by the compiler, because it is interpreted as an address-of operator.
– Some loss of readability (same symbol for two completely unrelated operations).
– Can be avoided by introduction of new symbols (e.g., Pascal’s div for integer
division)
• C++, Ada, Fortran95, and C# allow user-defined overloaded operators
• Potential problems:
– Users can define nonsense operations
– Readability may suffer, even when the operators make sense
Type Conversions
• A narrowing conversion converts a value to a type that cannot store even approximation of
all of the values of the original type.
Ex: In Java convert a double to float: the range of double is much larger than that of float
Float to int
• A widening conversion converts a value to a type that can include at least approximation of
all f the values of the original type.
Ex: converting an int to a float in Java.
• Widening conversions are nearly always safe, whereas narrowing conversions are not.
• Type conversions can be either explicit or implicit.
Type Conversions: Mixed Mode
• A mixed-mode expression is one that has operands of different types.
• Languages that allow such expressions, much define conventions for implicit operand type
conversions because computers usually do not have binary operations that take operands of
different types.
• A coercion is an implicit type conversion initiated by the compiler.
• Disadvantage of coercions:
– They decrease in the type error detection ability of the compiler
Consider the following Java code:
int a;
float b, c, d;
…
d=b*a;
Suppose that the second operand of (*) meant to be (c), but wrongly typed (a). because
Java allows mixed-mode, compiler would not detect as an error. Simply insert code to
coerce int operand (a) to float. If the previous case was in Ada, it would be error.
• In most languages, all numeric types are coerced in expressions, using widening conversions
Consider the following Java code
byte a, b, c;
…
A=b+c;
The values of (b) and (c) are coerced to int and an int addition is performed, then the sum is
converted to byte and put in (a).
• In Ada, there are virtually no coercions in expressions
Explicit Type Conversions
• Explicit Type Conversions could be widening or narrowing warning message could be issued
when explicit narrowing conversion results in significant change to the value of the object
being converted.
• Called casting in C-based language
• Examples
– C: (int) angle
4
– Ada: Float (sum)
ch = getchar() is carried out; the result (assigned to ch) is used as a conditional value for the
while statement.
Disadvantages of allowing assignment statement to be operands in expressions, it provides another
kind of expression side effect. Makes expressions difficult to read and understand.
Mixed-Mode Assignment
• Assignment statements can also be mixed-mode, for example
int a, b;
float c;
c = a / b;
• The coercion takes place only after the right side expression has been evaluated. One
alternative will be to coerce all operands in the right side to the type of the target before
evaluation as in the above example.
• In Pascal, integer variables can be assigned to real variables, but real variables cannot be
assigned to integers
• In Java and C#, only widening assignment coercions are done. i.e. int value can be assigned
to float variable, but not vice versa. This increases the reliability.
• In Ada, there is no assignment coercion