Expressions and Assignment Statements

advertisement

Expressions and Assignment Statements

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

Postfix ++, --

Ada

**, abs

*, /

All +, -

Prefix ++, --, unary +, - *, /, mod, rem

*, /, % 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 1 st

divided by 2 nd

.

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.

1

Arithmetic Expressions: Operator Associativity Rule

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 1 st .

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

Ada

Left: *, /, %, binary +, binary –

Right: ++, --, unary -, unary +

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

Arithmetic Expressions: Operand Evaluation Order

Operand evaluation order

1.

Variables: fetch the value from memory

2.

Constants: sometimes a fetch from memory; sometimes the constant is in the machine language instruction and not require a memory fetch.

2

3.

If an operand is parenthesized expression, then all operators it contains must be evaluated before its value can be used as an operand.

Arithmetic Expressions: Potentials for Side Effects

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 2 nd

operand is evaluated 1 st

, 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. int a

5; //global int fun1( )

{ a

17; return 3; } // end of fun1 void fun2( )

{ a

 a

 fun1( ); } // end of fun2 void main( )

The value computed for the value of a a in fun2 depends on the order of evaluation of the operands in the expression a+fun1( )

will be either 8 or 20.

.

{ fun2( ); } // end of main

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 leftto-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 1 st

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:

i nt 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

4

– C: (int) angle

– Ada: Float (sum)

Note that Ada’s syntax is similar to function calls

Type Conversions: Errors in Expressions

Causes due to

Inherent limitations of arithmetic e.g., division by zero is disallowed

Limitations of computer arithmetic e.g. overflow or underflow, where the result of an operation cannot be represented in the memory cell where it must be stored (either too large or too small).

Often ignored by the run-time system because it consider exceptions and programs can detect and deal with it.

Relational and Boolean Expressions

Relational Expressions

Use relational operators and operands of various types (simple like integer, or complex like character string ) ( numeric, string, ordinal types)

Evaluate to some Boolean representation

Operator symbols used vary somewhat among languages (!=, /=, .NE., <>, #)

The relational operators always have lower precedence than arithmetic operators.

Ex: a+1>2*b the arithmetic expressions are evaluated 1 st

.

Relational and Boolean Expressions

Boolean Expressions consist of Boolean variables, Boolean constants, relational expressions, and Boolean operators.

Operands are Boolean and the result is Boolean

Example operators: logical operators

FORTRAN 77 FORTRAN 90 C Ada

.AND. and && and

.OR. or || or

.NOT. not ! not

xor (exclusive OR)

Ada: AND and OR operators have equal precedence.

C-based: AND has higher precedence than OR.

Relational and Boolean Expressions: No Boolean Type in C

C has no Boolean type--it uses int type with 0 for false and nonzero for true

• One odd characteristic of C’s expressions: a < b < c is a legal expression, but the result is not what you might expect:

Left most operator is evaluated, producing 0 or 1

The evaluation result is then compared with the third operand (i.e., c). there is never a comparison between b and c in this expression.

Relational and Boolean Expressions: Operator Precedence

Precedence of C-based operators (arithmetic, relational, Boolean).

Highest prefix ++, --

unary +, -, prefix ++, --, !

*,/,%

binary +, -

<, >, <=, >=

=, !=

&&

Lowest ||

Short Circuit Evaluation

5

An expression in which the result is determined without evaluating all of the operands and/or operators

Example: (13*a) * (b/13–1)

If a is zero, there is no need to evaluate (b/13-1). It is difficult to detected during execution

The value of the Boolean expression

(a>=0) && (b<10) if the 1 st

relational expression is false, no need to evaluate the 2 nd

.easily discovered during execution.

Problem with non-short-circuit evaluation index = 0; while (index < length) && (LIST[index] != value)

index++;

Both relational expressions are evaluated.

When index=length, LIST [index] will cause an indexing problem (assuming LIST has length -1 elements)

C, C++, and Java: use short-circuit evaluation for the usual Boolean operators ( && and || ), but also provide bitwise Boolean operators that are not short circuit ( & and | )

Ada: programmer can specify either (short-circuit is specified with and then and or else)

Ex: assume List is declared 1..Listlen, the Ada code

Index :

1; while (Index



Listlen) and then (List(Inde x)/

Key) loop

Index :

Index

1; end loop;

Will not cause an error when Key is not in List and Index becomes larger than Listlen .

Short-circuit evaluation exposes the potential problem of side effects in expressions.

Suppose short-circuit evaluation is used on an expression and part of the expression that contains a side effect is not evaluated; then the side effect only occur in complete evaluation of the whole expression. If program correctness depends on the side effect, short-circuit evaluation can result in a serious error. e.g. (a > b) || ((b++) / 3)

In this expression, b is changed only when a<=b . if the programmer assumed b would be changed every time this expression is evaluated during execution, and the program’s correctness depends on it, the program will fail.

Assignment Statements

Assignment statements provides the mechanism by which the user can dynamically change the bindings of values to variables.

The general syntax

<target_var> <assign_operator> <expression>

The assignment operator

= FORTRAN, BASIC, PL/I, C, C++, Java

:= ALGOLs, Pascal, Ada

= can be bad when it is overloaded for the relational operator for equality

Instead of typing if(x==y)….we typed if (x=y)…

This si a loss of error detection in the C design of the assignment operation that leads to program errors.

Example of safety deficiencies of C and C++ programs.

Assignment Statements: Conditional Targets

Conditional targets (C, C++, and Java)

(flag)? total : subtotal = 0

Which is equivalent to if (flag) total = 0

6

else subtotal = 0

Assignment Statements: Compound Operators

Compound Assignment operator

A shorthand method of specifying a commonly needed form of assignment

Introduced in ALGOL; adopted by C

Example a = a + b is written as a += b

Assignment Statements: Unary Assignment Operators

Unary assignment operators in C-based languages combine increment and decrement operations with assignment

Examples sum = ++count (count incremented, then assigned to sum) count=count+1;

sum=count; sum = count++ ( Assignment of the value of count to some occurs 1 st

, then count is incremented, added to sum) sum=count;

count=count+1;

Using of unary increment operator to form a complete assignment statement. count++ (count incremented )

When two Unary operators apply to the same operands, the association is right

-count++ (count incremented then negated ) equivalent to –(count++)

Assignment as an Expression

In C, C++, and Java, the assignment statement produces a result and can be used as operands.

This design treats the assignment operator much like any other binary operators, except that it has te side effect of changing its left operand.

An example: in C

while ((ch = getchar())!= EOF){…}

= has lower precedence of relational operator, this why we put ch=getchar() in parenthesis.

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

7

Download