Escolar Documentos
Profissional Documentos
Cultura Documentos
IBRAHIMBAGH, HYDERABAD-31
DEPARTMENT OF COMPUTER SCIENCE & ENGINEERING
Subject: Principles of Programming languages
Class: B.E 3/4
Academic Year: 2013-14,
Sem-II
Instructor: I.Navakanth
Tel. No: 9550578779
Lecturers: I.Navakanth
Venue : Room No. R-207
Monday: 12.30-1.20
Tuesday: 12.30-1.20
Wednesday: 10.00-10.50
Saturday: 11.40-12.30
---------------------------------------------------------------------------------------------------------------------
Course Objectives:
1. Ability to understand the Syntax of various Programming languages
2. Ability to define context free grammars for the programming language constructs
3. Ability to understand the structure of Programming languages
4. Able to declare the variables in various Programming languages
5. Able to differentiate the syntax of conditional statements and control loops in
various Programming Languages
6. Able to understand Data representation
7. Able to understand Procedure invocation through Activation records
8. Able to differentiate Functional and Object oriented languages
9. Understand the features of object oriented programming languages
10. Understand the features of functional programming languages and Logic
Programming languages
Course Contents:
1. The Art of Language Design
2. Programming Language Syntax
3. Names, Scopes, and Bindings
4. Control Flow
5. Data Types
6. Subroutines and Control Abstraction
7. Data Abstraction and Object Orientation
8. Concurrency
9. Run-time Program Management
10. Functional Languages and Logic languages
Mode of Evaluation :
Examinations
1st Internal Test
2nd Internal Test
Quizes based on Assignments
Final Semesters Examination
Marks
20
20
5
75
Suggested Reading:
1. Programming Language Pragmatics, 3/e, Michael Scott, Elsevier, Morgan
Kaufmann, 2009.
2. Concepts of Programming languages, Sebesta, 8/e, Pearson.
3. Programming Languages Design and Implementation, 4/e Pratt, Zelkowitz, PHI
4. Programming Languages, Louden, 2/e, Cengage, 2003
Unit-I
Introduction:
The Art of Language Design
Without programming languages, we would have to program computers using their native code, called
machine code. A programming language is a man made language designed to express the calculations that
can be performed by a machine, including a computer. Programming languages creates several programs
that control the behavior of a machine to express precisely in algorithms, or as any form of human
communication assigned.
Language design and language implementation are intimately related to one another. An implementation
must conform to the rules of the language. At the same time, a language designer must consider how easy
or difficult it will be to implement various features, and what sort of performance is likely to result for
programs that use those features.
imperative
von Neumann C, Ada, Fortran, . . .
scripting Perl, Python, PHP, . . .
object-oriented Smalltalk, Eiffel, C++, Java, .
.
Programming Environments:
In recent programming environments provide much more integrated tools.When an invalid address error
occurs in an integrated environment, a new window is likely to appear on the users screen, with the line of
source code at which the error occurred highlighted. Breakpoints and tracing can then be set in this window
without explicitly invoking a debugger. Changes to the source can be made without explicitly invoking an
editor. The editor may also incorporate knowledge of the language syntax, providing templates for all the
standard control structures, and checking syntax as it is typed in. If the user asks to rerun the program after
making changes, a new version may be built without explicitly invoking the compiler or configuration
manager.
Overview of Compilation:
Compilers are generally structured as a series of phases. The first few phasesscanning, parsing, and
semantic analysisserve to analyze the source program.Collectively these phases are known as the
compilers front end. The final few phasesintermediate code generation, code improvement, and target
code generationare known as the back end. They serve to build a target programpreferably a fast one
whose semantics match those of the source.
Context-Free Grammars:
Any set of strings that can be defined if we add recursion is called a context-free language (CFL). Contextfree languages are generated by context-free grammars (CFGs) and recognized by parsers. Each of the rules
in a context-free grammar is known as a production. The symbols on the left-hand sides of the productions
are known as variables, or nonterminals. They cannot appear on the left-hand side of any production. In a
programming language, the terminals of the contextfree grammar are the languages tokens. One of the
nonterminals, usually the one on the left-hand side of the first production, is called the start symbol. It
names the construct defined by the overall grammar. The notation for context-free grammars is sometimes
called Backus-Naur Form (BNF).
Scanning: Scanners and parsers are language recognizers:They indicate whether a given string is valid.
The principal job of the scannerbis to reduce the quantity of information that must be processed by the
parser, bybgrouping characters together into tokens, and by removing comments and white space. Scanner
and parser generators automatically translate regular expressions and context-free grammars into scanners
and parsers.
Parsing: Practical parsers for programming languages (parsers that run in linear time) fall into two
principal groups: top-down (also called LL or predictive) and bottom-up (also called LR or shift-reduce). A
top-down parser constructs a parse tree starting from the root and proceeding in a left-to-right depth-first
traversal. A bottom-up parser constructs a parse tree starting from the leaves, again working left-to-right,
and combining partial trees together when it recognizes the children of an internal node. The stack of a topdown parser contains a prediction of what will be seen in the future; the stack of a bottom-up parser
contains a record of what has been seen in the past.
Unit-II
Names, Scopes, and Bindings:
The Notion of Binding Time:
A binding is an association between two things, such as a name and the thing it names. Binding time is the
time at which a binding is created or, more generally, the time at which any implementation decision is
made. There are many different times at which decisions may be bound: Language Design time, Language
Implementation time, Program writing time, Compile time, Link time, Load time, Run time.
Scope Rules:
The textual region of the program in which a binding is active is its scope. In most modern languages, the
scope of a binding is determined staticallythat is, at compile time. Typically, a scope is the body of a
module, class, subroutine, or structured control flow statement, sometimes called a block. At any given
point in a programs execution, the set of active bindings is called the current referencing environment. The
set is principally determined by static or dynamic scope rules. We shall see that a referencing environment
generally corresponds to a sequence of scopes that can be examined (in order) to find the current binding
for a given name. In some cases, referencing environments also depend on what are (in a confusing use of
terminology) called binding rules. Specifically, when a reference to a subroutine S is stored in a variable,
passed as a parameter to another subroutine, or returned as a function value, one needs to determine when
the referencing environment for S is chosenthat is, when the binding between the reference to S and the
referencing environment of S is made. The two principal options are deep binding, in which the choice is
made when the reference is first created, and shallow binding, in which the choice is made when the
reference is finally used.
Implementing Scope:
To keep track of the names in a statically scoped program, a compiler relies on a data abstraction called a
symbol table. In essence, the symbol table is a dictionary: it maps names to the information the compiler
knows about them. The most basic operations serve to place a new mapping (a name-to-object binding) into
the table and to retrieve (nondestructively) the information held in the mapping for a given name. Static
scope rules in most languages impose additional complexity by requiring that the referencing environment
be different in different parts of the program. In a language with dynamic scoping, an interpreter (or the
output of a compiler) must performoperations at run time that orrespond to the insert, lookup, enter scope,
and leave scope symbol table operations in the implementation of a statically scoped language.
Macro Expansion: To ease the burden of writing repetitive code many assemblers provided
sophisticated macro expansion facilities. A macro is that which replaces an expression or statement with
the appropriate multi-instruction sequence.
Separate Compilation:
As most language programs are constructed and tested incrementally, and since the compilation of a very
large program can be a multihour operation, any language designed to support large programs must provide
for separate compilation.
Control Flow:
Ordering is fundamental to most (though not all) models of computing. It determines what should be done
first, what second, and so forth, to accomplish some desired task. We can organize the language
mechanisms used to specify ordering into seven principal categories. 1. sequencing 2. selection
3. iteration 4. procedural abstraction 5. recursion 6. concurrency
Expression Evaluation:
An expression generally consists of either a simple object (e.g., a literal constant, or a named variable or
constant) or an operator or function applied to a collection of operands or arguments, each of which in turn
is an expression. It is conventional to use the term operator for built-in functions that use special, simple
syntax, and to use the term operand ffor the argument of an operator.
Unit-III
Data Types:
Most programming languages include a notion of type for expressions and/or objects. Types serve two
principal purposes:
1. Types provide implicit context for many operations, so the programmer does not have to specify
that context explicitly.
2. Types limit the set of operations that may be performed in a semantically valid program.
Type Systems:Informally, a type system consists of (1) a mechanism to define types and associate them
with certain language constructs and (2) a set of rules for type equivalence, type compatibility, and type
inference. The constructs that must have types are precisely those that have values, or that can refer to
objects that have values. These constructs include named constants, variables, record fields, parameters,
and sometimes subroutines; explicit (manifest) constants ; and more complicated expressions containing
these. Type equivalence rules determine when the types of two values are the same. Type compatibility
rules determine when a value of a given type can be used in a given context. Type inference rules define the
type of an expression based on the types of its constituent parts or (sometimes) the surrounding context.
Type Checking:Type checking is the process of ensuring that a program obeys the languages type
compatibility rules. A violation of the rules is known as a type clash. A language is said to be strongly typed
if it prohibits, in a way that the language implementation can enforce, the application of any operation to
any object that is not intended to support that operation. A language is said to be statically typed if it is
strongly typed and type checking can be performed at compile time. In the strictest sense of the term, few
languages are statically typed. In practice, the term is often applied to languages in which most type
checking can be performed at compile time, and the rest can be performed at run time.
Composite Types: Nonscalar types are usually called composite, or constructed types. They are
generally created by applying a type constructor to one or more simpler types. Common composite types
include records (structures), variant records (unions), ar rays, sets, pointers, lists, and files. All but pointers
and lists are easily described in terms of mathematical set operations (pointers and lists can be described
mathematically as well, but the description is less intuitive).
Records were introduced by Cobol, and have been supported by most languages since the 1960s. A record
consists of a collection of fields, each of whichbelongs to a (potentially different) simpler type. Records are
akin to mathematical tuples; a record type corresponds to the Cartesian product of the types of the fields.
Variant records differ from normal records in that only one of a variant records fields (or collections
of fields) is valid at any given time. A variant record type is the union of its field types, rather than their
Cartesian product.
Arrays are the most commonly used composite types. An array can be thought of as a function that maps
members of an index type to members of a component type. Arrays of characters are often referred to as
strings, and are often supported by special purpose operations not available for other arrays.
Sets, like enumerations and subranges, were introduced by Pascal. A set type is the mathematical powerset
of its base type, which must usually be discrete. A variable of a set type contains a collection of distinct
elements of the base type.
Pointers are l-values. A pointer value is a reference to an object of the pointers base type. Pointers are
often but not always implemented as addresses. They are most often used to implement recursive data
types. A type T is recursive if an object of type T may contain one or more references to other objects of
type T.
Lists, like arrays, contain a sequence of elements, but there is no notion of mapping or indexing. Rather, a
list is defined recursively as either an empty list or a pair consisting of a head element and a reference to a
sublist. While the length of an array must be specified at elaboration time in most (though not all)
languages, lists are always of variable length. To find a given element of a list, a program must examine all
previous elements, recursively or iteratively, starting at the head. Because of their recursive definition, lists
are fundamental to programming in most functional languages.
Files and Input/Output: Input/output (I/O) facilities allow a program to communicate with the
outside world. In discussing this communication, it is customary to distinguish between interactive I/O and
I/O with files. Interactive I/O generally implies communication with human users or physical devices,
which work in parallel with the running program, and whose input to the program may depend on earlier
output from the program (e.g., prompts). Files are intended to represent data on mass storage devices,
outside the memory in which other program objects reside. Like arrays, most files can be conceptualized as
a function that maps members of an index type (generally integer) to members of a component type. Unlike
arrays, files usually have a notion of current position, which allows the index to be implied implicitly in
consecutive operations. Files often display idiosyncrasies inherited from physical input/ output devices. In
particular, the elements of some files must be accessed in sequential order.
Strings: In many languages, a string is simply an array of characters. In other languages,
strings have special status, with operations that are not available for arrays of other sorts. Particularly
powerful string facilities are found in Snobol, Icon, and the various scripting languages.
Unit-IV
2. To cope with independent physical devices. Some software is by necessity concurrent. An operating
system may be interrupted by a device at almost any time. It needs one context to represent what it was
doing before the interrupt and another for the interrupt itself. Likewise a system for real-time control
(e.g., of a factory, or even an automobile) is likely to include a large number of processors, each connected
to a separate machine or device. Each processor has its own thread(s) of control, which must interact with
the threads on other processors to accomplish the overall objectives of the system .Message-routing
software for the Internet is in some sense a very large concurrent program, running on thousands of servers
around the world. 3. To increase performance by running on more than one processor at once. Even when
concurrency is not dictated by the structure of a program or the hardware on which it has to run, we can
often increase performance by choosing to have more than one processor work on the problem
simultaneously. With many processors, the resulting parallel speedup can be very large.
Unit-V
Run-time Program Management:
Late Binding of Machine Code: Late binding allows for dynamic execution at runtime.
In some environments it makes sense to bring compilation and execution closer together in time.Just-intime (JIT) compilation translates a program from source or intermediate form into machine language
immediately before each separate run of the program
Inspection/Introspection: Symbol data metadata makes it easy for utility programs-just-in-time and
dynamic compilers, optimizers, debuggers, profilers and binary rewriters to inspect a program and reason
about its structures and types. Lisp has long allowed a program to reason about its own internal structure
and types. This sort of reasoning is sometimes called introspection.
Functional Languages:
Functional Programming Concepts:
In a strict sense of the term, functional programming defines the outputs of a
program as a mathematical function of the inputs, with no notion of internal state,
and thus no side effects. Among the common functional programming languages,
Miranda, Haskell, Sisal, pH, and Backuss FP proposal [Bac78] are purely functional;
Lisp/Scheme and ML include imperative features. To make
functional programming practical, functional languages provide a number of features,
the following among them, that are often missing in imperative languages.
_ First-class function values and higher-order functions, Extensive polymorphism, List
types and operators, Recursion, Structured function returns, Constructors
(aggregates) for structured objects, Garbage collection
A Review/Overview of Scheme: Most Scheme implementations employ an interpreter that runs a
read-evalprint loop. The interpreter repeatedly reads an expression from standard input (generally typed
by the user), evaluates that expression, and prints the resulting
If the user types (+ 3 4)
the interpreter will print 7
If the user types 7
the interpreter will also print 7
(The number 7 is already fully evaluated.) To save the programmer the need to type an entire program
verbatim at the keyboard, most Scheme implementations provide a load function that reads (and evaluates)
input from a file: (load "my_Scheme_program")
Evaluation Order Revisited: we observed that the subcomponents of many expressions can
be evaluated in more than one order. In particular, one can choose to evaluate function arguments before
passing them to a function, or to pass them unevaluated. The former option is called applicative-order
evaluation; the latter is called normal-order evaluation. Like most imperative languages, Scheme uses
applicative order in most cases. Normal order, which arises in the macros and call-byname parameters of
imperative languages, is available in special cases. Suppose, that we have defined the following function.
(define double (lambda (x) (+ x x)))
Evaluating the expression (double (* 3 4)) in applicative order (as Scheme
Logic Languages:
Logic Programming Concepts:
Logic programming systems allow the programmer to state a collection of axioms from which theorems can
be proven. The user of a logic program states a theorem, or goal, and the language implementation attempts
to find a collection of axioms and inference steps (including choices of values for variables) that together
imply the goal. Of the several existing logic languages, Prolog is by far the most widely used.
Prolog: Logic programming consists of facts and rules. Prolog was born for natural language processing
Introduction to Prolog:
PROLOG is particularly strong in solving problems characterized by requiring complex symbolic
computations. As conventional imperative programs for solving this type of problems tend to be large and
impenetrable, equivalent PROLOG programs are often much shorter and easier to grasp. The language in
principle enables a programmer to give a formal specification of a program; the result is then almost
directly suitable for execution on the computer. Moreover, PROLOG supports stepwise are amendment in
developing programs because of its modular nature. These characteristics render PROLOG a suitable
language for the development of prototype systems.
Data structures in prolog:
Term is a basic data structure in Prolog, i.e., everything including program and data is expressed in form of
term. There are four basic types of terms in Prolog: variables, compound terms, atoms and numbers. The
following picture shows the correlation between them as well as examples of corresponding terms:
term
|-- var (X,Y)
|
-- nonvar (a,1,f(a),f(X))
|-- compound (f(a),f(X))
|
-- atomic (a,1)
|-- atom (a)
|
number (1)
Theoritical Foundations: In mathematical logic, a predicate is a function that maps constants
(atoms) or variables to the values true and false. rainy is a predicate, for example, we might have
rainy(Seattle) = true and rainy(Tijuana) = false. Predicate calculus provides a notation and inference rules
for constructing and reasoning about propositions (statements) composed of predicate applications,
operators (and, or, not, etc.), and the quantifiers and . Logic programming formalizes the search for
variable values that will make a given proposition true.