0% found this document useful (0 votes)
42 views8 pages

Expressions and Assignments

The document discusses expressions and assignment statements in programming languages. It covers the syntax and semantics of expressions, including arithmetic expressions, operator precedence and associativity rules. It also covers issues in expression evaluation order and differences between imperative and functional language approaches.

Uploaded by

alukapellyvijaya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views8 pages

Expressions and Assignments

The document discusses expressions and assignment statements in programming languages. It covers the syntax and semantics of expressions, including arithmetic expressions, operator precedence and associativity rules. It also covers issues in expression evaluation order and differences between imperative and functional language approaches.

Uploaded by

alukapellyvijaya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 8

Expressions and Assignment statements

Introduction
 Expressions in programming languages are fundamental constructs for specifying
computations. They consist of operators and operands, and their syntax and semantics
are crucial for understanding how computations are performed in a given language.

 The syntax of expressions is typically described using formal mechanisms like


Backus-Naur Form (BNF), which defines the structure and arrangement of the
elements within an expression.

 The semantics of expressions deal with how expressions are evaluated, including
the order of evaluation for operators and operands. Operator evaluation order is
determined by associativity and precedence rules defined by the language. Operand
evaluation order, on the other hand, is often left unspecified by language designers,
allowing implementors flexibility in choosing the order, which can lead to potential
differences in program behaviour across implementations.

 Issues in expression semantics also include handling type mismatches, coercions


(implicit type conversions), and features like short-circuit evaluation, where certain
expressions may not be fully evaluated if the result can be determined early.

 In imperative programming languages, assignment statements play a important


role. These statements are used to change the values of variables, thus altering the
program's state. Variables in imperative languages are mutable, meaning their values
can be modified during program execution.

 Functional languages, on the other hand, use a different approach to variables,


typically relying on function parameters and immutable data. Declarations in
functional languages bind values to names, similar to assignment statements in
imperative languages, but without causing side effects. These declarations typically
involve defining functions or creating immutable data structures.
Arithmetic Expressions
 Arithmetic expressions typically comprise operators, operands, parentheses for
grouping, and possibly function calls. Operators can be unary (operating on one
operand), binary (operating on two operands), or even ternary (operating on three
operands).
In most programming languages, binary operators are infix, meaning they are positioned
between their operands. However, there are exceptions such as Perl, which incorporates
some prefix operators that precede their operands.

The primary goal of an arithmetic expression is to define an arithmetic computation.


Implementing such a computation necessitates two actions: fetching the operands (usually
from memory) and executing the arithmetic operations on those operands.

Several design issues are associated with arithmetic expressions, including:


 Operator Precedence Rules: Determining the order in which operators are evaluated
when an expression contains multiple operators. For example, multiplication might
have higher precedence than addition.
 Operator Associativity Rules: Specifying how operators with the same precedence are
grouped when evaluating expressions. For instance, in languages with left-
associativity, expressions are evaluated from left to right.
 Order of Operand Evaluation: Determining the sequence in which operands are
evaluated. This can influence the result of expressions and potential side effects.
 Restrictions on Operand Evaluation Side Effects: Specifying whether there are
limitations or constraints on the side effects that can occur during operand evaluation.
 User-Defined Operator Overloading: Whether the language permits users to redefine
the behaviour of operators for custom types.
 Type Mixing in Expressions: Addressing the rules and limitations regarding mixing
different types of operands in expressions. Some languages may allow implicit type
conversions, while others enforce strict type checking.
Operator Evaluation Order
 The operator precedence and associativity rules of a language dictate the order of
evaluation of its operators
Precedence

 The value of an expression depends at least in part on the order of evaluation of the
operators in the expression.
 Consider the following expression: a + b * c Suppose the variables a, b, and c have
the values 3, 4, and 5, respectively. If evaluated left to right (the addition first and
then the multiplication), the result is 35. If evaluated right to left, the result is 23.
 Operator Precedence Hierarchy: In most programming languages, operators are
assigned a precedence level based on their complexity and mathematical convention.
For example, multiplication typically has a higher precedence than addition because
it's considered more complex.

 Unary Operators: Unary operators are operators that act on a single operand.
Common unary operators include unary addition (identity operator) and unary minus
(negation). Unary minus changes the sign of its operand. Unary addition usually has
no effect on its operand.

Placement of Unary Operators: Unary operators like unary minus can appear either
at the beginning of an expression or anywhere inside the expression, as long as they
are properly parenthesized to avoid ambiguity with other operators.

Implicit Type Conversion: In some languages like Java and C#, unary minus not
only changes the sign of its operand but also causes implicit type conversion for
certain data types. For example, unary minus may cause the conversion of short and
byte operands to int type. Unary addition is called the identity operator because it usually
has no associated operation and thus has no effect on its operand.

Operator Precedence Rules in Common Imperative Languages: Most imperative


languages follow similar operator precedence rules, typically with exponentiation
having the highest precedence, followed by multiplication and division, and then
binary addition and subtraction at the same level.

For example,
a + (- b) * c
is legal, but
a+-b*c
usually is not.

Next, consider the following expressions:


-a/b
-a*b
- a ** b

In the first two cases, the relative precedence of the unary minus operator and the
binary operator is irrelevant—the order of evaluation of the two operators has no
effect on the value of the expression.

Only Fortran, Ruby, Visual Basic, and Ada have the exponentiation operator. In all
four, exponentiation has higher precedence than unary minus, so

- A ** B
is equivalent to

-(A ** B)

The precedence’s of the arithmetic operators of Ruby and the C-based languages are
as follows:
Ruby C-Based Languages
Highest ** postfix ++, --
unary +,- prefix ++, --, unary +, -
*, /, % *, /, %
Lowest binary +, - binary +, -

The ** operator is exponentiation. The % operator takes two integer operands and
yields the remainder of the first after division by the second.

 APL is odd among languages because it has a single level of precedence


 Precedence accounts for only some of the rules for the order of operator evaluation
associativity rules also affect it.

Associativity

Consider the following expression:


a-b+c–d

Precedence vs. Associativity: Precedence determines the priority of operators, while


associativity defines the order of evaluation when operators have the same
precedence.

Operators with Same Precedence: When an expression contains two adjacent


operators with the same level of precedence (such as addition and subtraction), the
order of evaluation is determined by the associativity rules of the language.

Left-to-Right Associativity: In many programming languages, operators associate


from left to right by default. This means that when two operators with the same
precedence appear in an expression, the left operator is evaluated first, followed by
the right operator.

Exception for Exponentiation: The exponentiation operator (when provided by the


language) sometimes associates right to left. This means that in expressions involving
exponentiation, the rightmost operator is evaluated first.

Java expression
a-b+c
the left operator is evaluated first.

Exponentiation in Fortran and Ruby is right associative, so in the expression


A ** B ** C
the right operator is evaluated first.

In Ada, exponentiation is no associative, which means that the expression


A ** B ** C
is illegal. Such an expression must be parenthesized to show the desired order, as in
either
(A ** B) ** C
or
A ** (B ** C)

In Visual Basic, the exponentiation operator, ^, is left associative.

The associativity rules for a few common languages are given here

Associativity in APL: In APL, operators have the same precedence, so evaluation


order relies solely on right-to-left associativity. For instance, in A × B + C, addition
precedes multiplication.

Mathematical Associativity: Some arithmetic operations, like addition, are


mathematically associative, meaning evaluation order doesn't affect the result. A + B
+ C will yield the same result regardless of the order of addition.

Compiler Optimizations: Compilers may reorder operations for optimization,


leveraging mathematical associativity. However, this isn't always safe with floating-
point arithmetic due to precision limitations.

Limitations of Floating-Point Arithmetic: Floating-point arithmetic in computers


approximates mathematical operations, subject to precision constraints. Non-
associativity can occur, causing unexpected results, especially with large or small
numbers.

Impact on Expressions: Non-associativity in floating-point arithmetic can lead to


unexpected outcomes, such as overflow exceptions, affecting expression values.

Programmer Considerations: Programmers must be mindful of floating-point


limitations, adjusting code to ensure accuracy and avoid unexpected behaviour,
especially in critical calculations.

Parentheses:

Precedence Override:
 Parentheses allow programmers to specify the order of evaluation within an
expression, regardless of the default precedence of operators.

For example, in the expression


(A + B) * C,
the addition operation within the parentheses is evaluated first, followed by
multiplication.
This allows for precise control over the order of operations, ensuring that the desired
computation is performed.

Avoiding Overflow:
 Parentheses can also be used to prevent overflow or clarify the intended order of
evaluation.
 By grouping operations within parentheses, programmers can explicitly define the
sequence of computations, as shown in (A + B) + (C + D). This can improve code
clarity and prevent unexpected results, especially in complex expressions.
Ruby Expressions:

In Ruby

 Operators as Methods: In Ruby, all arithmetic, relational, assignment, array


indexing, shifts, and bitwise logic operators are implemented as methods. This means
that when you use an operator like +, it's actually calling a method named + on the
object referenced by the left operand, passing the right operand as a parameter. For
example, a + b is equivalent to a.+(b).
 Operator Overriding: One consequence of implementing operators as methods is
that they can be overridden by application programs. This means that developers can
redefine the behaviour of operators for specific types or classes. While it may not be
common to redefine operators for predefined types (like integers or strings), it can be
useful when working with user-defined types.
 Operator Overloading: This concept of redefining operators for user-defined types
is known as operator overloading. It allows developers to define custom behaviour for
operators when they are applied to instances of specific classes or structs. For
example, you could define how the + operator behaves when used with instances of a
custom Vector class.

Expressions in LISP

 All arithmetic and logic operations in LISP are performed by subprograms.


 But in LISP, the subprograms must be explicitly called.
 For example, to specify the C expression
a+b*c
in LISP, one must write the following expression:
(+ a (* b c))
In this expression, + and * are the names of functions.

Conditional Expressions

Conditional
Expressions:
– a ternary operator in C-based languages (e.g., C, C++)

– An example:

average = (count == 0)? 0 : sum / count

– Evaluates as if written like

if (count == 0) average = 0 else average = sum /count

Operand Evaluation Order

Side Effects
A side effect of a function, called a functional side effect, occurs when the
function changes either one of its parameters or a global variable.
(A global variable is 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.

 However, if fun changes a, there is an effect. Consider the following situation:


fun returns 10 and changes the value of its parameter to 20. Suppose we have
the following:

a = 10;
b = a + fun(a);

Then, if the value of a is fetched first (in the expression evaluation process), its value
is 10 and the value of the expression is 20.

But if the second operand is evaluated first, then the value of the first operand is
20 and the value of the expression is 30.

The following C program illustrates the same problem when a function


changes a global variable that appears in an expression:
int a = 5;
int fun1() {
a = 17;
return 3;
} /* end of fun1 */
void main() {
a = a + fun1();
} /* end of main */
The value computed for a in main depends on the order of evaluation of the operands
in the expression a + fun1().
The value of a will be either 8 (if ais evaluated first) or 20 (if the function call is
evaluated first).
 There are two possible solutions to the problem of operand evaluation order
and side effects.
 First, the language designer could disallow function evaluation from affecting
the value of expressions by simply disallowing functional side effects.
 Second, the language definition could state that operands in expressions are to
be evaluated in a particular order and demand that implementors guarantee
that order.
 Disallowing functional side effects in the imperative languages is difficult, and
it eliminates some flexibility for the programmer.
 The problem with having a strict evaluation order is that some code
optimization techniques used by compilers involve reordering operand
evaluations.
 A guaranteed order disallows those optimization methods when function calls
are involved. There is, therefore, no perfect solution, as is borne out by actual
language designs.
 The Java language definition guarantees that operands appear to be evaluated
in left-to-right order, eliminating the problem .

You might also like